ACIDCAT . FILE FORMAT REFERENCE

MDX Anatomy

Sharp X68000MXDRV . YM2151
rev 2026.09
magic none
endian big
container own
samples separate .PDX

An .mdx is a Music Macro Language score for the Sharp X68000, played by MXDRV. It drives the YM2151 FM chip, and where a tune uses ADPCM samples those live in a separate .PDX file which the MDX names. The format has no magic number: a file opens with its title, so identification is arithmetic rather than a signature.

nothing is at a fixed offset

The title and the sample-bank name are both variable length and neither declares its size, so every structure after them moves per file. The offset table's position is whatever those two happen to leave, and every offset inside it is measured from the table's own first word rather than from the start of the file. Read them as absolute and a tune points nowhere useful, by an amount that grows with the length of its title.

header, through the offset table

A complete header: a Shift-JIS title, the three-byte terminator, a sample-bank name, then the table. Forty-seven bytes here; a different title makes it a different length.

▸the offset table20 bytes . big-endian

One word for the voice block, then one per channel. Every value is relative to the position of the voiceOffset word.

The channel count is not stored anywhere. It is recovered from the table's own shape: the table runs right up to whatever is written after it, so the smallest offset in the table IS the table's size, and

channels(smallest offset − 2) / 2
here(0x0014 − 2) / 2 = 9
only two values occur9 or 16; anything else is not an MDX

That smallest offset is usually channel A's, because the channel streams are usually written first and the voice block last. It is a convention and not a rule: some tunes put the voice block first, and in those the voiceOffset is the table's size and channel A's offset points well past it. A reader that assumes channel A always comes first gets a channel count in the hundreds for those files and concludes they are not MDX at all.

▸channels9 or 16

Channels are lettered, not numbered, and the letters are not contiguous.

A – Hthe eight YM2151 FM voices
PADPCM, played from the .PDX sample bank
Q – Wthe extra voices a Mercury Unit expansion board provides
nine channelsa stock machine: A through H, plus P
sixteen channelsa Mercury Unit is fitted

A channel that carries no music still has an entry. Its offset points at two bytes, which is how an empty stream is written rather than omitted.

▸the title, and why it is not a header0x00 . variable

The file begins with text, in Shift-JIS, terminated by 0D 0A 1A. That sequence is carriage return, line feed, and the DOS end-of-file character, so a tune printed to a console shows its title and stops.

There is no signature before it and no length in front of it. Identifying an MDX means finding the terminator, then a NUL-terminated name, then reading the table and checking that it resolves to a legal channel count with every offset inside the file. The arithmetic IS the identification.

One class of file passes the first half and fails the second on purpose. Tunes were distributed packed with the X68000 compressors of the day, and the packers compressed the file from the offset table onward while leaving the title and the sample-bank name readable. The result is a module whose text reads perfectly and whose table is compressor output, so the channel count resolves to nonsense. The compressor stamps its name and version a few bytes into the packed stream -- LZX, ZOO, LHA or LZS -- which is what separates a packed module from a file that is simply not an MDX.

▸the sample bankafter the terminator

A NUL-terminated Human68k filename naming a .PDX file that holds the ADPCM samples. A bare NUL means the tune is FM only. The extension is usually left off the name, as it is here.

A tune referencing a bank is two files, and the MDX carries no copy of the samples. Separated from its .PDX, channel P has nothing to play.

▸a voice27 bytes

Voices are YM2151 register values, not an abstraction over them, so a voice is literally what gets written to the chip. Each four-byte field is the four operators in the order the chip numbers them.

▸feedback and connection, bit by bit1 byte

The second byte of a voice packs two fields and leaves the top two bits clear.

▸byte orderbig-endian

Every multi-byte value is big-endian, which for once follows the machine rather than fighting it: the X68000 is a 68000. The MML command streams the offsets point at are byte-oriented and carry no multi-byte words of their own.