A PSF file is a console's sound program and the memory it runs in, compressed,
with a checksum and a tag block. Neill Corlett made it in 2002 for PlayStation dumps, and then
everyone who needed to ship the same thing for a different chip borrowed it: one version
byte names the machine, and nothing else about the container changes. So a
.psf, a .minigsf, a .ssf and a .usf are the
same file with a different byte 3.
This is a complete Game Boy Advance mini: sixteen bytes of header, a 22-byte compressed program, and a tag block. Nothing is left out. The program inflates to fourteen bytes, and twelve of those are a header, which is the point of a mini -- the tune lives in a library file the tag names, and this file is just the song number.
Three letters and then the only byte that differs between platforms.
The letters alone are not enough to identify a file: PSF opens
ordinary text too. A reader checks the version byte with them.
After the header and the reserved area comes the program, zlib-compressed, of the size the header states. What the program IS depends on the machine: a PlayStation executable, an N64 ROM image, a GBA ROM. The container does not say, and a reader that does not know the platform's program layout should not guess at it.
What the container does say is whether the program is intact. The header carries a CRC32 of the compressed bytes. Most formats give a reader nothing to check against; this one hands over a checksum, so "the program is undamaged" is a fact rather than a hope.
A soundtrack shares one sound engine and one sample set across every track.
Shipping all of it in every file would multiply a game's music by its track count, so the
format splits it: the shared part goes in a library (.psflib,
.gsflib, .ssflib...) and each track is a mini whose program is
a few bytes patched over the library's, and whose _lib tag names the library.
A mini separated from its library is a song number with nothing to play. The library sits beside it by convention, and a reader can check.
Once the program is inflated, a GSF program opens with three little-endian words and then exactly that much ROM:
A library's ROM is the whole game's sound side, up to sixteen megabytes. A mini's is one or two bytes at an offset inside the library's image: the song number, written where the engine reads it. This header is decoded because it is documented and holds on every file measured; the other machines' programs are reported as a size that inflates and checksums, and nothing more is claimed.
A 2SF program is the GBA layout without the entry point: two little-endian words, offset and length, then that many bytes of DS ROM. A library holds the whole cartridge image, up to 64 MB inflated; a mini holds two bytes, the song number, at an offset inside it.
2SF is the one machine that uses the header's reserved area. When present it is a SAVE block: the four letters, a little-endian zlib size, the CRC32 of the zlib stream, then the stream. Inflated, it has the same shape as the program: offset, length, data. It is a patch into the emulator's save state; a mini's is four bytes, and a mini may carry a SAVE patch and a tag and no program at all, the library holding everything else.
Optional, at the end, marked by five literal bytes. Then one key=value
per line, LF-separated, UTF-8. A key that repeats is a value continued on the next line.
m:ss or secondsThe three header words are little-endian, as is the GBA header inside a GSF program. Other machines' programs follow their own machine; the container does not care what is inside the zlib.