The .M files are the music files used by Xeen games. They contain interwoven MIDI and FM synth commands for complete compatibility between cards with support for FM (such as Adlib and Sound Blaster) and MIDI (such as Roland and Wave Blaster)
Most commands are interpreted, such that the same command can mean the same thing but handled slightly differently depending on whether it is outputting MIDI or FM data. There is extra data for each also stored in the file which is simply skipped if not relevant to the current output.
The FM (Frequency Modulation) processor works by altering the frequency of several sine wave channels and passing the result through a digital to analogue converter to produce a specific tone. By manipulating these sine waves, more complex sounds can be produced.
While most sound cards still have an FM processor, it should also be possible to program a simple FM emulation engine for systems that do not, like the Nintendo DS.
MIDI operates in UART mode, meaning it is simply a string of commands with no logic processing.
Channels 0-6 appear to be the music channels, while channel 8 appears to be for special effects. Channel 7 acts as some kind of hybrid, being special case in many instructions, but still using the same structures as the music channels, which differs from the effects channel (channel 8).
The execution is interrupt based, executing some instructions before returning. It triggers about 72.8 times per second. The interrupt process is initiated by the "play" command, sent to music driver, and covers both music and sound effects. There is a count down timer delay which is decremented every iteration through the interrupt. When this delay reaches zero, the next instruction is read and acted upon from the file. The 0x1 command (below) can be used to set this timer. For example, if instructions have set a channel to play a certain note, and the next instruction is "0x10 0x48" it will skip 72 times through the interrupt (effectively playing that note for a full second) before proceeding to the next instruction.
The .M file consists of a series of commands, followed by zero or more data bytes. A command byte is read from the file, and then branched depending on the value of certain flags. The high nibble of the command byte is the actual instruction, while the low nibble is the channel on which that instruction is executed, if applicable. Due to the combined nature of the music file, some instructions have slightly different processing depending on whether it's playing MIDI or FM music, and some have no execution at all.
See Sound/Music_Drivers for a complete list of all commands and their uses.
The instrument data, as recorded in the file, is 26 bytes long. It's divided into sections based upon what type of music (FM or MIDI) will be played.
|0x00||0x20||Amplitude Modulation / Vibrato / Envelope Generator Type / Keyboard Scaling Rate / Modulator Frequency Multiple|
|0x01||0x40||Level Key Scaling / Total Level|
|0x02||0x60||Attack Rate / Decay Rate|
|0x03||0x80||Sustain Level / Release Rate|
|0x05||0x20||Amplitude Modulation / Vibrato / Envelope Generator Type / Keyboard Scaling Rate / Modulator Frequency Multiple|
|0x06||0x40||Level Key Scaling / Total Level|
|0x07||0x60||Attack Rate / Decay Rate|
|0x08||0x80||Sustain Level / Release Rate|
|0x0A||0xC0||Feedback / Algorithm|
First five bytes are duplicated, though it's not yet obvious why. Possibly to allow for left/right channel.
Byte 0x0B - 0x17 are unknown. Possibly for a different driver.
|0x18||A value from 0-127 indicating the instrument as listed in the General Midi spec|
Byte 0x19 - 0x1A are also unknown. Possibly for a different driver.
TODO: investigate other drivers for more instrument information.