xtracker32.org
Fileformat

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
OffsetDescriptionType
00hChunk ID ('DDMF')4 Chars
04hFile version1 Byte
05hTracker software name8 Chars
05hTracker software name8 Chars
0dhSong name - fill unused chars with 030 Chars
2bhComposer name - fill unused chars with 020 Chars
3fhCreation date - one byte for day, month, year+19003 Bytes


CMSG chunk - Song message
OffsetDescriptionType
00hChunk ID ('CMSG')4 Chars
04hBlocklength - Offset to start of next block. This does NOT include the Chunk ID or the blocklength field itself (so blocklength is the length of the current chunk - 8)1 dword
08hFiller - reservered (0)1 byte
09hMessage - ASCII-Text with fixed length of 40 chars per line. Length of Message is blocklength-1 bytesx chars


SEQU chunk - sequencer data
OffsetDescriptionType
00hChunk ID ('SEQU')4 Chars
04hBlocklength - (see above)1 dword
08hSequencer loop start1 word
0ahSequencer loop end1 word
0chSequencer data - every word represents one entry in the sequencer. Length is blocklength-4 ((blocklength-4)/2 sequencer entries)x words


PATT chunk - pattern data
OffsetDescriptionType
00hChunk ID ('PATT')4 Chars
04hBlocklength - (see above)1 dword
08hPattern entries (1-1024) - number of patterns in this song1 word
0ahMax tracks (1-32) - highest number of tracks used in all patterns1 byte
0bhPatterns - the following structure is repeated 'pattern entries' times 
Pattoffs.DescriptionType
00hTrack entries (1-32) - number of tracks in this pattern1 Byte
01hBeat - the lower nibble of this byte is reserved. The upper nibble holds the number of rows per beat. A value of 64 in this field would result in every 4th row beeing highlighted (64 shr 4 = 4)1 Byte
02hRow entries - number of rows in this pattern1 Word
04hPatternlength - Length of the following pattern data in bytes = offset to begin of next pattern1 DWord
08hPatterndata - Compressed stream of pattern data. Sorry, now it's getting a bit more complex ;)
The following structure is repeated 'Row entries' times: (Attention: If the last rows of the pattern are completely empty, then they won't be saved)
x Bytes
[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
OffsetDescriptionType
00hChunk ID ('SMPI')4 Chars
04hBlocklength - (see above)1 dword
08hSample entries - number of samples saved in the song1 Byte
09hSamples - the following structure is repeated 'Sample entries' timesBytes
Sampleoff.DescriptionType
00hSamplename length (0-30) - number chars of samplename1 Byte
01hSamplename - the name of the samplex Chars
x + 01hSample length - length of sample in bytes. Attention: This is the final length of the depacked sample (unlike the sample length in the SMPD chunk, which stores the packed length)1 Dword
x + 05hSample loop start - position of sample loop start in bytes1 Dword
x + 09hSample loop end - position of sample loop end in bytes1 Dword
x + 0dhc3 frequency - frequency in hz of the sample at the note c-3. Valid range is 1000-45000 Hz1 Word
x + 0fhVolume - Sample volume, 0 = not set, 1-255 = volume in linear scale1 Byte
x + 10hSample 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
xxxxxx1x = 16BIT Sample
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
1 Byte
x + 11hLibrary Name - library name in which the sample is stored. Fill with 0 if unused. ATTENTION: This field only exists in version 8 and above. (With xtracker32 it's unused for now)8 Bytes
x + 19hFiller - reserved1 Byte
x + 1bhCRC32 - crc32 over sampledata1 DWord


SMPD chunk - Sample-Data
OffsetDescriptionType
00hChunk ID ('SMPD')4 Chars
04hBlocklength - (see above)1 dword
08hSample data - the following structure is repeated 'Sample entries' (from SMPI) timesBytes
Sampleoff.DescriptionType
00hSample data length - length of sample data stream in bytes. This is the real length of the possibly compressed data. For the real final length, see SMPI chunk. If this sample is empty or saved in a library file, then this field is set to 01 Dword
04hSample data streamx Bytes


SMPJ chunk - Sample Jump points
(This chunk exists from dmf version 10 and up)
OffsetDescriptionType
00hChunk ID ('SMPJ')4 Chars
04hBlocklength - (see above)1 dword
08hSample jump points - the following structure is repeated 'Sample entries' (from SMPI) timesBytes
OffsetDescriptionType
00hCount of jump points following. 0=No jump points for this sample1 Byte
01hJump points. This is the sample-offset in bytes (not samples!) to jump to if the JMP command is issued in a track. These are 32 bit signed integers. A value of -1 means that a jump-point is undefined. In this case the JMP command should be ignored.x Integers


ENDE chunk - end of DDMF
OffsetDescriptionType
00hChunk ID ('ENDE')4 Chars