From http://www.xtracker32.org/fileformat.shtml ----- This is the documentation of the DMF file format versions 6 and up, as used by the original DOS xtracker and xtracker32. - Versions up to 7 where only used in beta version of xtracker. Still there are quite a few songs available that use these versions. - The xtracker final version used file format version 8 - xtracker32 extensions are marked as file format version 10. DDMF (D-lusion digital music format) is a IFF-like chunk-orientated format which should be really easy to use. The following chunks exist: * [DDMF] Format identifier * [INFO] reserved * [CMSG] Song message * [SEQU] Sequencer, order to play patterns in * [PATT] Patterndata * [INST] Instrument data, reserved * [SMPI] Sample-Information * [SMPD] Sample-Data. Must be saved after [SMPI] chunk * [SMPJ] Sample Jump Positions. Must be saved after [SMPI] chunk (v10+) * [ENDE] EOF marker +-----------------------------------------------------------------------------+ | DDMF chunk - Format identifier | |-----------------------------------------------------------------------------| | Offset | Description | Type | |----------+------------------------------------------------------+-----------| | 00h | Chunk ID ('DDMF') | 4 Chars | |----------+------------------------------------------------------+-----------| | 04h | File version | 1 Byte | |----------+------------------------------------------------------+-----------| | 05h | Tracker software name | 8 Chars | |----------+------------------------------------------------------+-----------| | 0dh | Song name - fill unused chars with 0 | 30 Chars | |----------+------------------------------------------------------+-----------| | 2bh | Composer name - fill unused chars with 0 | 20 Chars | |----------+------------------------------------------------------+-----------| | 3fh | Creation date - one byte for day, month, year+1900 | 3 Bytes | +-----------------------------------------------------------------------------+ +-----------------------------------------------------------------------------+ | CMSG chunk - Song message | |-----------------------------------------------------------------------------| | Offset | Description | Type | |--------+----------------------------------------------------------+---------| | 00h | Chunk ID ('CMSG') | 4 Chars | |--------+----------------------------------------------------------+---------| | | Blocklength - Offset to start of next block. This does | | | 04h | NOT include the Chunk ID or the blocklength field itself | 1 dword | | | (so blocklength is the length of the current chunk - 8) | | |--------+----------------------------------------------------------+---------| | 08h | Filler - reservered (0) | 1 byte | |--------+----------------------------------------------------------+---------| | 09h | Message - ASCII-Text with fixed length of 40 chars per | x chars | | | line. Length of Message is blocklength-1 bytes | | +-----------------------------------------------------------------------------+ +-----------------------------------------------------------------------------+ | SEQU chunk - sequencer data | |-----------------------------------------------------------------------------| | Offset | Description | Type | |--------+----------------------------------------------------------+---------| | 00h | Chunk ID ('SEQU') | 4 Chars | |--------+----------------------------------------------------------+---------| | 04h | Blocklength - (see above) | 1 dword | |--------+----------------------------------------------------------+---------| | 08h | Sequencer loop start | 1 word | |--------+----------------------------------------------------------+---------| | 0ah | Sequencer loop end | 1 word | |--------+----------------------------------------------------------+---------| | | Sequencer data - every word represents one entry in the | | | 0ch | sequencer. Length is blocklength-4 ((blocklength-4)/2 | x words | | | sequencer entries) | | +-----------------------------------------------------------------------------+ +-----------------------------------------------------------------------------+ | PATT chunk - pattern data | |-----------------------------------------------------------------------------| | Offset | Description | Type | |-----------------+-----------------------------------------+-----------------| | 00h | Chunk ID ('PATT') | 4 Chars | |-----------------+-----------------------------------------+-----------------| | 04h | Blocklength - (see above) | 1 dword | |-----------------+-----------------------------------------+-----------------| | 08h | Pattern entries (1-1024) - number of | 1 word | | | patterns in this song | | |-----------------+-----------------------------------------+-----------------| | 0ah | Max tracks (1-32) - highest number of | 1 byte | | | tracks used in all patterns | | |-----------------+-----------------------------------------+-----------------| | 0bh | Patterns - the following structure is | | | | repeated 'pattern entries' times | | |-----------------------------------------------------------------------------| | +-------------------------------------------------------------------------+ | | | Pattoffs. | Description | Type | | | |----------------+-----------------------------------------+--------------| | | | 00h | Track entries (1-32) - number of tracks | 1 Byte | | | | | in this pattern | | | | |----------------+-----------------------------------------+--------------| | | | | Beat - the lower nibble of this byte is | | | | | | reserved. The upper nibble holds the | | | | | 01h | number of rows per beat. A value of 64 | 1 Byte | | | | | in this field would result in every 4th | | | | | | row beeing highlighted (64 shr 4 = 4) | | | | |----------------+-----------------------------------------+--------------| | | | 02h | Row entries - number of rows in this | 1 Word | | | | | pattern | | | | |----------------+-----------------------------------------+--------------| | | | | Patternlength - Length of the following | | | | | 04h | pattern data in bytes = offset to begin | 1 DWord | | | | | of next pattern | | | | |----------------+-----------------------------------------+--------------| | | | | Patterndata - Compressed stream of | | | | | | pattern data. Sorry, now it's getting a | | | | | | bit more complex ;) | | | | | 08h | The following structure is repeated | x Bytes | | | | | 'Row entries' times: (Attention: If the | | | | | | last rows of the pattern are completely | | | | | | empty, then they won't be saved) | | | | |-------------------------------------------------------------------------| | | | +---------------------------------------------------------------------+ | | | | | [GLOBAL TRACK] ([TRACK] * [TRACK ENTRIES]) | | | | | |---------------------------------------------------------------------| | | | | | GLOBAL TRACK: | | | | | | | | | | | | INFO - 1 Byte | | | | | | (COUNTER) - 1 Byte | | | | | | (DATA) - 1 Byte | | | | | | | | | | | | INFO = zyxxxxxx | | | | | | | | | | | | xxxxxx (lowest 6 bits) = Global track effect | | | | | | y = reserved | | | | | | z = counter saved (pack indicator) | | | | | | | | | | | | In case the pack indicator is set, then the next byte in the stream | | | | | | will be COUNTER. | | | | | | COUNTER is a (guess what ;) counter that is count down for every | | | | | | note row. There is no global track information saved until counter | | | | | | is 0 again. At the begin of a pattern, COUNTER always starts with | | | | | | 0. | | | | | | If the pack indicator isn't set then no COUNTER is saved, instead | | | | | | you have to assume COUNTER beeing 0 which means that the next row | | | | | | will have a global track again. | | | | | | If the global track effect is > 0, then a DATA byte containing the | | | | | | effect data is saved in the stream. Else there is no DATA byte. | | | | | |---------------------------------------------------------------------| | | | | | TRACK: | | | | | | | | | | | | INFO - 1 Byte | | | | | | (COUNTER) - 1 Byte | | | | | | (INSTRUMENT) - 1 Byte | | | | | | (NOTE) - 1 Byte | | | | | | (VOLUME) - 1 Byte | | | | | | (INSTRUMENT EFFECT) - 2 Bytes | | | | | | (NOTE EFFECT) - 2 Bytes | | | | | | (VOLUME EFFECT) - 2 Bytes | | | | | | | | | | | | INFO = 76543210 | | | | | | bit 0: reserved | | | | | | bit 1: 1=volume effect saved | | | | | | bit 2: 1=note effect saved | | | | | | bit 3: 1=instrumend effect saved | | | | | | bit 4: 1=volume saved | | | | | | bit 5: 1=note saved | | | | | | bit 6: 1=instrument saved | | | | | | bit 7: 1=counter saved (pack indicator) | | | | | | | | | | | | The following values are only saved if the corresponding bits in | | | | | | INFO are set. | | | | | | | | | | | | COUNTER | | | | | | See above - COUNTER is counted down for each row until it is zero. | | | | | | There is no data saved in this track until counter reaches zero. If | | | | | | the pack indicator isn't set, then there is no counter saved which | | | | | | means that the next row will have track data again. | | | | | | | | | | | | INSTRUMENT | | | | | | Instrument/Sample to play | | | | | | | | | | | | NOTE | | | | | | 0 = No change | | | | | | 1-108 = Note in halfnote-steps, C0=1 up to H8=108. | | | | | | 109-128 = undefined | | | | | | 129-236 = This note is saved into the notebuffer, the current | | | | | | playing note won't be changed. The Notebuffer is used as a second | | | | | | parameter for effects like "portamento to note", where the effect | | | | | | parameter byte is already in use. | | | | | | 237-254 = undefined | | | | | | 255 = Note Off, sets the notes frequency to 0 hz | | | | | | | | | | | | VOLUME | | | | | | 0 = undefined 1-255 = new volume, linear scaling | | | | | | | | | | | | INSTRUMENT EFFECT | | | | | | 1. Byte: Instrument effect nr. | | | | | | 2. Byte: Instrument effect data | | | | | | | | | | | | NOTE EFFECT | | | | | | 1. Byte: Note effect nr. | | | | | | 2. Byte: Note effect data | | | | | | | | | | | | VOLUME EFFECT | | | | | | 1. Byte: Volume effect nr. | | | | | | 2. Byte: Volume effekt data | | | | | |---------------------------------------------------------------------| | | | | +---------------------------------------------------------------------+ | | | +-------------------------------------------------------------------------+ | +-----------------------------------------------------------------------------+ +-----------------------------------------------------------------------------+ | SMPI chunk - Sample-Information | |-----------------------------------------------------------------------------| | Offset | Description | Type | |-----------------+----------------------------------------+------------------| | 00h | Chunk ID ('SMPI') | 4 Chars | |-----------------+----------------------------------------+------------------| | 04h | Blocklength - (see above) | 1 dword | |-----------------+----------------------------------------+------------------| | 08h | Sample entries - number of samples | 1 Byte | | | saved in the song | | |-----------------+----------------------------------------+------------------| | 09h | Samples - the following structure is | Bytes | | | repeated 'Sample entries' times | | |-----------------------------------------------------------------------------| | +-------------------------------------------------------------------------+ | | | Sampleoff. | Description | Type | | | |------------+--------------------------------------------------+---------| | | | 00h | Samplename length (0-30) - number chars of | 1 Byte | | | | | samplename | | | | |------------+--------------------------------------------------+---------| | | | 01h | Samplename - the name of the sample | x Chars | | | |------------+--------------------------------------------------+---------| | | | | Sample length - length of sample in bytes. | | | | | x + 01h | Attention: This is the final length of the | 1 Dword | | | | | depacked sample (unlike the sample length in the | | | | | | SMPD chunk, which stores the packed length) | | | | |------------+--------------------------------------------------+---------| | | | x + 05h | Sample loop start - position of sample loop | 1 Dword | | | | | start in bytes | | | | |------------+--------------------------------------------------+---------| | | | x + 09h | Sample loop end - position of sample loop end in | 1 Dword | | | | | bytes | | | | |------------+--------------------------------------------------+---------| | | | x + 0dh | c3 frequency - frequency in hz of the sample at | 1 Word | | | | | the note c-3. Valid range is 1000-45000 Hz | | | | |------------+--------------------------------------------------+---------| | | | x + 0fh | Volume - Sample volume, 0 = not set, 1-255 = | 1 Byte | | | | | volume in linear scale | | | | |------------+--------------------------------------------------+---------| | | | | Sample Type - Different flags that define the | | | | | | sample | | | | | | xxxxxxx0 = no loop | | | | | | xxxxxxx1 = sample is played looping. The sample | | | | | | plays from its beginning on until it reaches | | | | | | 'Sample loop end' and then repeats the range | | | | | | from 'Sample loop start' to 'Sample loop end' | | | | | | xxxxxx0x = 8BIT Sample | | | | | x + 10h | xxxxxx1x = 16BIT Sample | 1 Byte | | | | | xxxxXXxx = Compression type xxxx00xx = | | | | | | Uncompressed signed PCM xxxx01xx = Compression | | | | | | type 0 - modified huffmann xxxx10xx = | | | | | | Compression type 1 - mp3 xxxx11xx = Compression | | | | | | type 2 - currently undefined xxx0xxxx = mono | | | | | | sample xxx1xxxx = stereo sample xXXxxxxx = | | | | | | reserved 0xxxxxxx = sampledata is saved in SMPD | | | | | | chunk 1xxxxxxx = sampledata is saved in external | | | | | | libary | | | | |------------+--------------------------------------------------+---------| | | | | Library Name - library name in which the sample | | | | | x + 11h | is stored. Fill with 0 if unused. ATTENTION: | 8 Bytes | | | | | This field only exists in version 8 and above. | | | | | | (With xtracker32 it's unused for now) | | | | |------------+--------------------------------------------------+---------| | | | x + 19h | Filler - reserved | 1 Byte | | | |------------+--------------------------------------------------+---------| | | | x + 1bh | CRC32 - crc32 over sampledata | 1 DWord | | | +-------------------------------------------------------------------------+ | +-----------------------------------------------------------------------------+ +-----------------------------------------------------------------------------+ | SMPD chunk - Sample-Data | |-----------------------------------------------------------------------------| | Offset | Description | Type | |-----------------+----------------------------------------+------------------| | 00h | Chunk ID ('SMPD') | 4 Chars | |-----------------+----------------------------------------+------------------| | 04h | Blocklength - (see above) | 1 dword | |-----------------+----------------------------------------+------------------| | | Sample data - the following structure | | | 08h | is repeated 'Sample entries' (from | Bytes | | | SMPI) times | | |-----------------------------------------------------------------------------| | +-------------------------------------------------------------------------+ | | | Sampleoff. | Description | Type | | | |------------+--------------------------------------------------+---------| | | | | Sample data length - length of sample data | | | | | | stream in bytes. This is the real length of the | | | | | 00h | possibly compressed data. For the real final | 1 Dword | | | | | length, see SMPI chunk. If this sample is empty | | | | | | or saved in a library file, then this field is | | | | | | set to 0 | | | | |-------------------------------------------------------------------------| | | |-------------------------------------------------------------------------| | | | 04h | Sample data stream | x Bytes | | | +-------------------------------------------------------------------------+ | +-----------------------------------------------------------------------------+ +-----------------------------------------------------------------------------+ | SMPJ chunk - Sample Jump points | | (This chunk exists from dmf version 10 and up) | |-----------------------------------------------------------------------------| | Offset | Description | Type | |-----------------+-----------------------------------------+-----------------| | 00h | Chunk ID ('SMPJ') | 4 Chars | |-----------------+-----------------------------------------+-----------------| | 04h | Blocklength - (see above) | 1 dword | |-----------------+-----------------------------------------+-----------------| | | Sample jump points - the following | | | 08h | structure is repeated 'Sample entries' | Bytes | | | (from SMPI) times | | |-----------------------------------------------------------------------------| | +-------------------------------------------------------------------------+ | | | Offset | Description | Type | | | |--------+---------------------------------------------------+------------| | | | 00h | Count of jump points following. 0=No jump points | 1 Byte | | | | | for this sample | | | | |-------------------------------------------------------------------------| | | |-------------------------------------------------------------------------| | | | | Jump points. This is the sample-offset in bytes | | | | | | (not samples!) to jump to if the JMP command is | | | | | 01h | issued in a track. These are 32 bit signed | x Integers | | | | | integers. A value of -1 means that a jump-point | | | | | | is undefined. In this case the JMP command should | | | | | | be ignored. | | | | +-------------------------------------------------------------------------+ | +-----------------------------------------------------------------------------+ +-----------------------------------------------------------------------------+ | ENDE chunk - end of DDMF | |-----------------------------------------------------------------------------| | Offset | Description | Type | |---------------------+--------------------------------+----------------------| | 00h | Chunk ID ('ENDE') | 4 Chars | +-----------------------------------------------------------------------------+