ACIDCAT . FILE FORMAT REFERENCE

PMD Anatomy

NEC PC-9801Professional Music Driver . YM2608
rev 2026.09
magic 3 weak bytes
endian little
container own
samples separate .PPC / .PPS / .PZI

A .M file is a compiled score for Professional Music Driver, the sound driver M. Kajihara wrote for the NEC PC-9801 and its Yamaha YM2608 FM chip. Most of the PC-98's game and doujin music was written for it. A composer writes MML, a text language, and a compiler turns it into this: a table of eleven part streams, the FM instruments, and a memo block where the score's own #Title and #Composer survive.

source and binary

MML is the source. It is plain text: c d e f g for notes, t120 for tempo, @1 to pick an instrument, and a block of #-directives at the top for the title, composer and sample banks. MC.EXE compiles it to the binary on this page, and the driver, PMD.COM, plays the binary. So a .M is to its .MML what an object file is to its source, and the memo block is the part of the source the compiler chose to keep.

the header, 27 bytes

A flag byte, then twelve little-endian words, then one more. Every offset in the file is measured from byte 1, not byte 0: the driver loads the file and then points its buffer one byte in, and never looks back.

▸the part table12 words . little-endian

Eleven part streams and one address table, each a word offset counted from byte 1. The parts are lettered the way the MML names them:

A – Fsix FM voices on the YM2608
G – Ithree SSG channels, the chip's square-wave half
JADPCM, played from the .PPC or .P86 sample bank
Krhythm, the chip's six built-in drum sounds
twelfth wordthe rhythm pattern address table, not a part

Twelve words, not eleven. The driver walks the eleven parts and then takes one more for the rhythm table. A reader that counts eleven finds the tone offset two bytes early and leaves a two-byte hole in front of every first part; the numbers still look plausible, which is why it is worth saying.

A part whose stream opens with 0x80 is silent: the MML wrote nothing for it. A stream's length is not stored anywhere. A part runs from its own offset to whatever begins next in the file, so the extents come from sorting every offset the header gives you.

▸identification, with no magic to speak of3 bytes

There is no signature. What the driver checks before it will play a file is three bytes:

byte 0at most 0x0F; 0 is PC-98, 1 is X68000
byte 10x1A or 0x18
byte 20x00 or 0xE6

Bytes 1 and 2 are just the low and high halves of part A's offset, which is 26 or 24 in every file the compiler produces because the header is that long. So the "magic" is a consequence of the layout, not a mark, and a random file passes it roughly once in a few thousand. That is why a reader checks the extension too.

▸the memo anchor4 bytes, just before the tones

The memo is found backwards. The word at offset 0x18 of the stream is the tone offset; four bytes before where it points sit a word pointer, a tag byte, and 0xFE. That is the anchor, and it is not a region of its own: it is the tail of whatever precedes the tone block, usually the rhythm table.

The tag byte says which sample-bank slots the memo table carries in front of its text. The PCM-file slot is always first. A tag of 0x42 or above puts a PPS-file slot in front of it; 0x48 or above puts a PPZ-file slot in front of both. That is the driver's arithmetic reproduced: a caller asks for slot −2, −1 or 0 and the driver adds one per threshold. Get the order wrong and the composer lands in the arranger field.

▸the memo tableword pointers, then strings

A list of word pointers, each to a NUL-terminated Shift-JIS string, ending with a zero word. The slots are the MML directives the compiler read them from, as the driver's author lists them:

[#PPZFile]PPZ8 sample bank, if the tag says so
[#PPSFile]SSG-PCM sample bank, if the tag says so
#PCMFilethe ADPCM bank part J plays from
#Titlethe tune's name
#Composerwho wrote it
#Arrangerwho arranged it
#Memo ...free lines, up to 128, until the zero word

A string that is just / means the directive was never written. So does an empty one. A PMD file names its sample banks the way an X68000 MDX names its PDX: the samples live elsewhere, and a tune separated from its bank has an ADPCM part with nothing to play.

▸the tone blockFM instruments, 26 bytes each

A list of instruments, each an instrument number and then 25 bytes of YM2608 operator registers, ended by 00 FF. It is a list and not an array: the driver finds instrument @5 by walking the records comparing numbers, so they need not be in order and need not be contiguous. The memo strings begin on the byte after the terminator.

They are here only if the MML was compiled with MC /V. Without that flag the compiler writes none, the tone offset simply equals the header size, and the driver expects a separate .FF instrument file. A file with no tones is a real thing the compiler produces, not damage; so is a list holding only its terminator, which is what an SSG-only tune has.

▸the familyPC-98 . PC-88 . X68000 . FM Towns

The driver was ported, and the compiler's output followed. Byte 0 is the platform flag: 0 for the PC-98 and 1 for the X68000, whose files otherwise share this layout exactly. The part letters map to different chips on each machine, which the MML manual notes and the file does not.

Other extensions the compiler writes: .M2 and .M86 are the same format under a different preprocessor setting; .MZ is compressed. The sample banks are their own formats: .PPC and .P86 for ADPCM, .PPS for SSG-PCM, .PZI and .PVI for PPZ8.

▸byte orderlittle-endian

Every word is little-endian, as the 8086 in the PC-9801 is. The X68000 variant keeps it that way despite running on a 68000, because the compiler and driver were ported together and the format did not change.