Skip to main content
A .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:
Clone Hero and YARG read .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 .sng file 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: Lengths, counts and offsets of 8 bytes are unsigned 64-bit numbers. Keys, values and names are UTF-8, without NUL characters.
  • 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 .sng file.

Masking

Each file’s data is masked with the 16 bytes of the mask. For byte i 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.
The mask keeps programs that don’t know the format from reading the files inside as ordinary files.

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.
  • name is 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 True or False.
  • 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.ini keys, frets, track, pro_drum and star_power_note. Write charter, album_track, pro_drums and multiplier_note.
Edge case: the chart’s [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.ini stored: 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.
Edge case: background images in folders. Clone Hero shows any image whose name contains 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.ini key and value as written, so pro_drums = 1 stays 1, and Name stays Name;
  • renames frets, track, star_power_note and pro_drum to charter, album_track, multiplier_note and pro_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.
It can also convert the audio to .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

  • preview and crowd audio, as in a song folder: see Deprecated. Clone Hero doesn’t play a preview file inside a .sng file 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

Clone Hero loads it as a song of its own. YARG doesn’t look for songs inside a song folder, so it skips it. A scanner loads it as a song of its own, as Clone Hero does.
Neither game finds the file.
Neither game loads a file with another identifier or another version, and Clone Hero lists a file of another version in its errors.txt. A scanner doesn’t load the file.
A scanner refuses the file. Readers trust different fields: SngCli and parse-sng read the pairs and entries by their counts, and Clone Hero and YARG read each part by its length, then the pairs or entries inside it by their count. So such a file reads differently in each, or not at all.
A scanner finds each file by its offset, as Clone Hero, YARG and SngCli do, and refuses a .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.
Clone Hero and YARG don’t load a .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 scanner matches names exactly, so it doesn’t find the file, as Clone Hero does. YARG does.
Neither game finds the key, so the song reads as if it weren’t there. Without name, Clone Hero doesn’t list the song.
A scanner reads only 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 scanner reads it as Clone Hero does: an optional sign, then digits, within the 32-bit range, with spaces allowed around them, and the key’s default for anything else. YARG reads a number from the value’s first character, and reads 0 when it isn’t a sign or a digit.
Clone Hero doesn’t list the song, even when the .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.
Clone Hero reads empty text, or a number’s default. YARG reads past the end of an empty value, into the next pair. A scanner reads the key as not set. SngCli never writes one.
Both games use the last.
No game checks for them. The specification forbids them so that the metadata can become a song.ini file again.
Games ignore it: the metadata is the only source of the song’s values.
Clone Hero ignores them. YARG reads them as it does in song.ini. A scanner ignores them.
Unlike in a song folder, both games play the first of .opus, .ogg, .mp3 and .wav. As in a song folder, a .sng file holds one file for each audio name.
As in a song folder, Clone Hero loads the song without sound, and YARG doesn’t load it unless it holds crowd audio or a stem in .aiff.