Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

157 Commits

Repository files navigation

SNG File Format

.sng is a simple and generic binary container format that groups a list of files and metadata into a single file.

This repository includes several components: a reference tool for converting SNG files to and from the designated format, the file specification, a registry of frequently used metadata keys, and a registry of file names.

SngCli

The SngCli tool is a basic command line tool that has a couple of operating commands each with their own set of command line flags:

Usage: SngCli [command] [options]
Options:
-h, --help Show help message
-v, --version Display version information
--verbose Display more information such as audio encoder output.
encode:
-o, --out FOLDER Specify output folder location for SNG files
-i, --in FOLDER Specify input folder to search for song folders
-t, --threads Set how many songs will be encoded in parallel. Can also be useful to set to 1 when a song has an error along with --verbose.
--noStatusBar Disable rendering of the status bar. Can reduce cpu usage.
--skipExisting If the song to be encoded already exists as an sng in the output folder skip it
--skipUnknown Skip unknown files.By default unknown files are included (All audio and images of supported formats are transcoded)
--videoExclude Exclude video files
--opusEncode Encode all audio to opus
--opusBitrate Set opus encoder bitrate, default: 80
--jpegEncode Encode all images to JPEG
--jpegQuality JPEG encoding quality, default: 75
--albumUpscale Enable upscaling album art, by default images are only shrunk.
--albumResize Resize album art to set size. Smaller resolutions load faster in-game, Default size: 512x512
Supported Sizes:
Nearest - This uses next size below the image size
256x256
384x384
512x512
768x768
1024x1024
1536x1536
2048x2048
decode:
-o, --out FOLDER Specify output folder location for extracted song folders
-i, --input FOLDER Specify input folder to search for SNG files
-t, --threads Set how many songs will be encoded in parallel.
--noStatusBar Disable rendering of the status bar. Can reduce cpu usage.

When encoding this tool can also do audio transcoding to opus, and image transcoding to JPEG. Opus encoding takes a significant amount of time for larger song libraries. The more cpu cores you have, the tool can take advantage of this, and encode multiple songs in parallel speeding up the process significantly.

SNG File Specification

The following are definitions of the data types used in this file specification

Data TypeDescription
byte8-bit unsigned integer
uint3232-bit unsigned integer
uint6464-bit unsigned integer
int3232-bit signed integer
stringA sequence of utf-8 characters a byte[] array excluding NULL 0x00 characters as many languages use these as end of string sequences
SngIdentifyThe SNGPKG file identifier. 0x53 0x4E 0x47 0x50 0x4b 0x47 as bytes. Used to identify the file format
byte[]An array of bytes
MetadataPair[]An array of metadataPair objects
FileMeta[]An array of fileMeta objects
File[]An array of file objects
maskedByte[]An array of bytes representing masked file data

Structure Overview

Before delving into the full SNG specification, the following is a brief overview of the structure. The format consists of a header followed by three sections, each adhering to this format:

FieldData TypeSizeDescription
sectionLengthuint648Length of section in bytes after this field
sectionDatabyte[]sectionLengthBytes that make up the section

These is the required ordering of each of these components:

Section TypeDescription
HeaderThe file header contains important details needed to parse the format
MetadataMetadata information for applications that cover the specific song data stored
FileIndexDefines information about what files are within the container and how to read them
FileDataContains the actual file data

Sections

Header

FieldData TypeSizeDescription
fileIdentifierSngIdentify6SNGPKG sequence to identify the file type
versionuint324The .sng format version
xorMaskbyte[]16Random bytes for masking files

Metadata

FieldData TypeSizeDescription
metadataLenuint648Number of bytes in the section after this field
metadataCountuint648Number of MetadataPair sections
metadataPairArrayMetadataPair[]metadataLen - 8Array of MetadataPair sections

MetadataPair (represents a single metadata string key/value pair)

FieldData TypeSizeDescription
keyLenint324The number of bytes in the key
keystringkeyLenutf-8 byte string for the metadata's key
valueLenint324The number of bytes in the value
valuestringvalueLenThe metadata's value

FileIndex

FieldData TypeSizeDescription
fileMetaLenuint648Number of bytes in the section after this field
fileCountuint648Number of FileMeta (and FileData) sections
fileMetaArrayFileMeta[]fileMetaLen - 8Array of FileMeta sections

FileMeta (contains the file index metadata for each File section)

FieldData TypeSizeDescription
filenameLenbyte1The number of bytes in the filename
filenamestringfilenameLenRelative file path within song folder. Folders are denoted by the '/' character following each folder. The filename follows all folders.
contentsLenuint648The number of bytes in the file's contents
contentsIndexuint648The first byte index from the start of the file of the corresponding file section

FileData

FieldData TypeSizeDescription
fileDataLenuint648Total length in bytes of all file data
fileDataArrayFile[]fileDataLenConcatenated file sections

File (contains the binary contents of a single file)

FieldData TypeSizeDescription
maskedFileBytesmaskedByte[]contentsLenThe file's binary contents masked

Masking

File Data is masked using a fairly simple algorithm which utilizes the xorMask field from the file header and the byte pos within that file. The following is example pseudo code to convert to the file's true contents.

// Iterate through the indices of the maskedFileBytes arrayfori=0tosize(maskedFileBytes)-1:
// Calculate the XOR key based on the current index and xorMask arrayxorKey=xorMask[i%16]XOR(iAND0xFF)// You can cast to a byte instead of "AND 0xFF" if your language supports it// XOR each byte in maskedFileBytes with the xorKeyfileBytes[i]=maskedFileBytes[i]XORxorKey

Metadata Strings

Some characters in metadata strings have restrictions to simplify serialization into INI files, affecting both keys and values. To include data with these characters, it's recommended to replace or remove them before converting into the SNG format.

  • Semicolon (;)
    • Semicolons are used to denote comments in INI files. If a semicolon is allowed in a key, it will create confusion between a key-value pair and a comment, making it difficult to parse the INI file correctly.
  • Newline characters (\r\n)
    • Newline characters mark the end of a line in a text file. Allowing newline characters in values makes it hard to tell where one key-value pair finishes and the next starts, causing problems when reading the file.

Characters only disallowed for keys

  • Equal sign (=)
    • In an INI file, an equal sign (=) separates keys and values. Allowing an equal sign in a key can cause confusion about where the key stops and the value starts. This issue doesn't affect values, as only the first equal sign on a line separates the key from the value. For instance, some song.ini tags use equal signs in values, like <color=#00FF00>, to indicate the color of a metadata string.

Metadata values:

Metadata values are strings, but some are intended to be string representations of specific data types. Applications must decide how to parse the data type from the string. The following are a baseline of common types that should stay consistent between all applications:

bool

Bool values take the form of 2 strings and they are case sensitive:

  • True

  • False

integer

Integer values take the following form: (+/- sign)(digits)

  1. sign - Optional sign digit - or +

  2. digits - A sequence of digit characters 0 - 9

float

Float values take the following form: (+/- sign)(integral_digits).(fractional_digits)

  1. sign - Optional sign digit - or +
  2. integral_digits - A sequence of digit characters 0 - 9 representing whole numbers
  3. period (.) - this is the delimiter between integral_digits and fractional_digits
  4. fractional_digits - A sequence of digit characters 0 - 9 representing the fractional part of the number

string

Strings are the final fallback data type any value that cannot be represented as above currently will be assumed as string as long as it follows the Metadata rules and the rules for the SNG utf-8 string type above (no null 0x00 characters).

File Names

There are also some limitations to what is allowed for file names to prevent issues across operating systems when extracting files:

  • < (less than)
  • > (greater than)
  • : (colon)
  • " (double quote)
  • / (forward slash)
  • \ (backslash)
  • | (vertical bar or pipe)
  • ? (question mark)
  • * (asterisk)
  • Integer value characters below 31(0x00 - 0x1F), known as control characters
  • 0x7f (DEL character)
  • .. (Two consecutive periods)
  • Do not end a file name with a period . or a space
  • the following names are prohibited due to windows reserved file name list, this includes when using file extensions. For example both CON and CON.txt are disallowed
    • CON
    • PRN
    • AUX
    • NUL
    • COM0
    • COM1
    • COM2
    • COM3
    • COM4
    • COM5
    • COM6
    • COM7
    • COM8
    • COM9
    • LPT0
    • LPT1
    • LPT2
    • LPT3
    • LPT4
    • LPT5
    • LPT6
    • LPT7
    • LPT8
    • LPT9

Design Decisions

  • The primary advantage of using a format like this is that it enables streaming audio data from the container without having to load the entire file into memory, thanks to the use of memory-mapped files. Since no compression is applied, the file offsets remain static, which simplifies reading data from the file.
    • In comparison, other projects often employ formats based on ZIP files. Although it's possible to seek within a ZIP file during runtime, the data typically needs to be decompressed and loaded into memory. In C#, this imposes a limit of 2GB of data per audio file. Additionally, because audio data is generally already compressed, using ZIP files introduces unnecessary overhead that slows down the process of loading audio. By opting for a format that does not rely on compression, these limitations can be avoided, allowing for more efficient streaming and access to audio data.
  • The metadata is versatile and not confined to any particular application. It can encompass a multitude of properties, including those specific to individual applications. To prevent inadvertent property clashes among data from different applications, a metadata keys registry is also included in this repository. Metadata should be limited to what can be serialized into an INI file, as it must be capable of round-tripping to and from a song.ini file. For more complex metadata requiring additional data blobs, they should be managed as a separate file within the container.
  • .sng is designed to be able to contain the binary contents of any set of files.
  • File binaries are placed at the end of the format, and sections have lengths to allow programs to efficiently scan only the .sng's metadata or fileMeta sections whichever may be required.
  • The format has lengths defined in each major section to allow easily skipping over data that may not be required during parsing.
  • The file binary is masked so that it can't be directly detected by programs that don't know how to parse the file.
  • This format is exclusively in a LittleEndian byte ordering for efficiency on modern cpu architectures.
  • File names are purposely limited to 255 bytes in length as most file systems have this length restriction.

Registry

The registry is intended to be a helpful tool for anyone utilizing the format, participation ensures that others will not inadvertently use conflicting metadata keys. It is not required to register keys with the registry but it is in your best interest as an application developer to do so.

To submit a new entry for the registry submit a pull request to add any keys that your application may be making use of along with the recommended data type for this value. We recommend using a application prefix if it is something very specific to your application, however if it is a more general usage metadata value not including a prefix would make sense.

Metadata registry

Currently there are no SNG specific metadata names registered but all the keys from these links should be considered taken thus far:

GuitarGame_ChartFormats - Game Specific Tags

GuitarGame_ChartFormats - Typical Tags

Filename Registry

The filename registry serves a similar purpose to the metadata one so that conflicting file names aren't utilized within the format that have different usages.

note that currently all registered file names are specified as lowercase, this is intentional. The reference encoding tool will force any files of these names to be lowercase within the output file, however any unknown file names will not be modified.

Additionally filenames can contain folders within the song seperated by the '/' character however currently there are no 'registered' folders as being used in the accepted format. The reference tool does support encoding folders when explicitly enabled.

  • notes.chart
  • notes.mid
  • song.ini - Reserved, but will be not communicated through into sng file as this is the source of metadata in the SNG file
  • album.{png,jpg,jpeg}
  • background.{png,jpg,jpeg}
  • highway.{png,jpg,jpeg}
  • video.{mp4,avi,webm,vp8,ogv,mpeg}
  • guitar.{mp3,ogg,opus,wav}
  • bass.{mp3,ogg,opus,wav}
  • rhythm.{mp3,ogg,opus,wav}
  • vocals.{mp3,ogg,opus,wav}
  • vocals_1.{mp3,ogg,opus,wav}
  • vocals_2.{mp3,ogg,opus,wav}
  • drums.{mp3,ogg,opus,wav}
  • drums_1.{mp3,ogg,opus,wav}
  • drums_2.{mp3,ogg,opus,wav}
  • drums_3.{mp3,ogg,opus,wav}
  • drums_4.{mp3,ogg,opus,wav}
  • keys.{mp3,ogg,opus,wav}
  • song.{mp3,ogg,opus,wav}
  • crowd.{mp3,ogg,opus,wav}
  • preview.{mp3,ogg,opus,wav}

About

Song Container format

Resources

Stars

33 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages