.sng file holds a whole song folder in one file. The values of the folder’s song.ini become the .sng file’s metadata, and its other files are stored inside it:
.sng files, and play the audio straight from them, without unpacking them. scan-chart doesn’t read or write them.
Matthew Sitton and Geo designed the format. Its specification comes with SngCli, a tool that packs song folders into .sng files and unpacks them.
Where a .sng file goes
- Required: a
.sngfile goes where a song folder would, among the song folders, not inside one. - Required: the extension
.sng, in lowercase. SngCli names the file after the song folder.
Layout
A.sng file is a header, then three parts: the metadata, the file index and the files’ data. Every number is little-endian. M is the metadata’s length, and L the file index’s:
- Required: the metadata length, the file index length and the file data length each equal the number of bytes their part holds.
- Required: the file data starts right after the file data length, holds the files in the order of the file index with nothing between them, and ends the
.sngfile.
Masking
Each file’s data is masked with the 16 bytes of the mask. For bytei of a file, counted from 0 at that file’s first byte:
- The same operation masks and unmasks a file. The key repeats every 256 bytes, so a scanner can build it as a 256-byte table.
- Any 16 bytes are a valid mask. Recommended: random bytes for a new file, and the file’s own mask when it’s saved again.
Metadata
The metadata is the[song] section of a song.ini file, as key and value pairs. Its keys are those of Metadata and Settings, and each value is one that song.ini can hold, so that the metadata can become a song.ini file again.
nameis Required.- Required: keys in lowercase. Both games match keys exactly.
- Required: each key once.
- Required: a value of at least one character in every pair. To leave a value unset, leave its key out.
- Required: a boolean written as
TrueorFalse. - Required: a number written as digits, with an optional
-before them, and no spaces. - Required: no
;and no line break in keys and values, and no=in keys. - Required: none of the older names of
song.inikeys,frets,track,pro_drumandstar_power_note. Writecharter,album_track,pro_drumsandmultiplier_note.
[Song] section. Clone Hero takes nothing from a .chart file’s [Song] section but Offset, PreviewStart and PreviewEnd, and those only when the metadata doesn’t set delay, preview_start_time or preview_end_time. So the metadata holds every value the song needs.
Files
Each file in the index is a file of the song folder. Files in a song folder gives their names and rules: one chart, at least one audio file, and one file for each audio name.- Required: names in lowercase. Clone Hero matches names exactly.
- Required: each name once, and no two names that differ only in letter case.
- A name is at most 255 bytes of UTF-8, folders included.
- Required: no
song.inistored: the metadata takes its place. - Recommended: no folders in the names. The format allows a name such as
extras/photo.png, but games don’t read files in folders.
background, folders included, and YARG any whose name starts with background. So an image named backgrounds/1.png can still appear behind the highway.
Edge case: long names. parse-sng, a TypeScript library that reads .sng files, reads a name’s length as a signed byte, so it fails on a name longer than 127 bytes.
Edge case: the song’s identity. Clone Hero and YARG tell songs apart by a hash of the chart file alone, in a .sng file as in a folder. So packing a folder into a .sng file, or unpacking it, doesn’t change the song’s identity, as long as the chart file doesn’t change.
Making a .sng file
SngCli encode packs each song folder in a folder into a .sng file, and SngCli decode unpacks them. As it packs a folder, SngCli:
- copies every
song.inikey and value as written, sopro_drums = 1stays1, andNamestaysName; - renames
frets,track,star_power_noteandpro_drumtocharter,album_track,multiplier_noteandpro_drums, and leaves out known keys whose values it can’t read; - writes the names of the files games read in lowercase, and gives each audio file the extension of its content;
- stores files games don’t read, unless it’s given
--skipUnknown, and stores the files of a subfolder with the subfolder’s name before theirs.
.opus. Before packing a folder, write its booleans as True or False and its keys in lowercase, and remove the files games don’t read.
Deprecated
previewandcrowdaudio, as in a song folder: see Deprecated. Clone Hero doesn’t play apreviewfile inside a.sngfile at all.
Ignored
- Metadata keys a scanner doesn’t read. An exporter keeps them.
- Files games don’t read, and files in folders, except background images as above.
Invalid forms
A .sng file inside a song folder
A .sng file inside a song folder
An extension other than .sng, such as .SNG
An extension other than .sng, such as .SNG
An identifier other than SNGPKG, or a version other than 1
An identifier other than SNGPKG, or a version other than 1
errors.txt. A scanner doesn’t load the file.Lengths that don't match the bytes used
Lengths that don't match the bytes used
File data out of order, with gaps, or with bytes after it
File data out of order, with gaps, or with bytes after it
.sng file with a file that runs past its end, as Clone Hero does. parse-sng ignores the offsets, and reads the files one after another from the end of the file data length, so it reads the wrong bytes. YARG fails when it reads a file that runs past the end.One name used twice, or two names that differ only in letter case
One name used twice, or two names that differ only in letter case
.sng file that holds one name twice. YARG makes names lowercase first, so it also doesn’t load one that holds Song.opus and song.opus. Clone Hero reads those as two files. A scanner reads them as Clone Hero does. When SngCli packs two files with one name, it keeps the first.A file name not in lowercase, such as Notes.chart
A file name not in lowercase, such as Notes.chart
A metadata key not in lowercase, such as Name
A metadata key not in lowercase, such as Name
name, Clone Hero doesn’t list the song.A boolean written as 1 or 0
A boolean written as 1 or 0
True and False, in any letter case, and anything else as not set, as Clone Hero does. So a .sng file with pro_drums = 1 plays without pro drums, while a song folder with the same song.ini plays with them. YARG reads 1 as true.A number in another form, such as one with spaces
A number in another form, such as one with spaces
No name
No name
.chart file’s [Song] section has a Name. YARG uses that Name. A scanner takes the name from the metadata alone, never from [Song], as Clone Hero does: see SongHash.An empty value
An empty value
A key written more than once
A key written more than once
A semicolon, a line break or = where the metadata forbids it
A semicolon, a line break or = where the metadata forbids it
song.ini file again.A stored song.ini
A stored song.ini
frets, track, pro_drum or star_power_note in the metadata
frets, track, pro_drum or star_power_note in the metadata
song.ini. A scanner ignores them.Two audio files with one name, such as song.ogg and song.opus
Two audio files with one name, such as song.ogg and song.opus
.opus, .ogg, .mp3 and .wav. As in a song folder, a .sng file holds one file for each audio name.No audio file
No audio file
crowd audio or a stem in .aiff.