An .sndh is a program: the music's own 68000 player routine, ripped from
the game or demo it came from, with a small tag header saying what it is and how to call it.
Three branches come first -- init (with the subtune number in d0), exit and
play, the last called at the replay rate -- and SNDH at offset 12 opens the
tags. To hear one, a 68000 runs init once and play every tick while the YM2149 (and on the STe,
the DMA sound) is emulated. Nearly every file is then packed with Pack-Ice.
Read backwards. The packed stream is consumed from the end of the file toward this header, and the image is written from its end toward its start. Bits come from bytes taken from the end, top bit first; the lowest set bit of each byte is a marker that says it is spent. The stream alternates literal runs (a flag, then a length in fields of 1, 2, 2, 3, 8 and 15 bits, each all-ones field stepping to the next) and strings copied from what has already been written: a length from 2 to 1033 and an offset in one of three widths, or for a two-byte string one of two. One more bit after the image says whether a 32,000-byte picture was also reordered from bitplanes; music never sets it.
Usually BRA.W: 0x6000 and a signed 16-bit displacement from the
address after the opcode. An entry with nothing to do can be a bare RTS.
Text tags are four letters and a NUL-terminated string:
TITL, COMM (composer), RIPP, CONV,
YEAR, and FLAG, a ~ and letters for what the player
needs (y for the YM2149, e for the STe, a-d for the timers it takes over). Zero bytes may pad
between tags. In this file the composer, ripper, converter and year sit between the title
and the part drawn second.
Before HDNS. The end tag came with version 2 of the format. An older header just stops: the last tag's terminator, a byte of padding if needed, and the player's code at the next even address.
Everything after the header: the routine the three branches reach, its pattern and instrument data, and on STe or Falcon files the DMA samples. It is position independent or relocates itself, since it is loaded wherever the host player puts it.
On disk, ICE! at zero (Pack-Ice 2.3 and 2.4; earlier versions
write Ice! and are not described here); inside, SNDH at offset 12,
after the three entries.