XM

From GDWiki

Jump to: navigation, search
This article is a stub. You can help out by expanding it.
Image:40px-notepad.png To comply with our quality standards, this article may need to be rewritten.
Please help improve this article. The discussion page may contain suggestions.


Okay this is supposed to cover the xm format (Extended Module) created by Triton a swedish demo group. (now commonly known as Starbreeze Studios)

XM (Extended Module) and XI (Extended Instrument). XM was and still is one of the most popular module formats nowadays, because of its compact and well compressible file structure. This document will guide you through the file structure of the XM file format, and hopefully also show you how to open and play it. With this said and done, I think it's time to start coding.


Variable explanation

Uword is an "short"

Dword is an "unsigned long"

Ubyte is and "unsigned char"

Sbyte is an "signed char"


Presumably these types are assuming the usual x86 architecture. More likely Uword is a uint16_t, Dword is a uint32_t, and the assumption is that CHAR_BIT==8.

Contents

[edit] Headers

[edit] General Header

     
Offset    Length    Type   EXPLANATION
******    ******    *****  ***********

0         17        char   should always contain the string "Extended Module:", Fasttracker reports the file as corrupt if not 
17        20        char   stores the name of the song 
37        1         char   dunno what this is or does, thou it seems as it always is 26 ??????? (See note below table)
38        20        char   usually stores the name of the tracker used to create the xm file
58        2         Uword  version of the file , hi-byte major and low-byte minor. The current format is version $0103
60        4         Dword  stores the size of this header
+4        2         Uword  the length of the song (in patterns).
+6        2         Uword  restart position
+8        2         Uword  number of channels (2,4,6,8,10,...,32)
+10       2         Uword  number of patterns (max 256)
+12       2         Uword  number of instruments (max 128)
+14       2         Uword  flags 0 = amiga frequency table, 1 = linear frequency table
+16       2         Uword  Default tempo (number of ticks)
+18       2         Uword  Default BPM (Beats Per Minute)
+20       256       Ubyte  Pattern order table (0,1,5,2,34....)

Char 26: It's an "escape char". If you cat the file on your terminal it will stop after printing "Extended Module:" and the name of the song. Otherwise your terminal will fill up with garbage (works for Windows/Dos at least)

[edit] Pattern Header

?         4         Dword  the size of this header (always 9)
+4        1         Ubyte  the pattern type. always 0 (don't think that xm files contain any other types of patterns)
+5        2         Uword  number of rows in this pattern
+7        2         Uword  the size of the pattern

Note that if the size equals 0, then that pattern isn't stored in the actual module and therefore needs to be created. Allocate 64(rows) * (nr of channels) and set them to 128

[edit] Note Header

?         1         Ubyte  stores notes from 0-96. 97 is note off
+1        1         Ubyte  stores the instrument used
+2        1         Ubyte  volume
+3        1         Ubyte  effect type      (arppegio,porta....)
+4        1         Ubyte  effect parameter (value)

[edit] Intrument Header

?         4         Dword  stores the size of the header
+4        22        char   instrument name
+24       1         Ubyte  instrument type. should always be 0
+25       2         Uword  number of samples in instrument

[edit] Second Instrument Header

?         4         Dword  stores the size of the header
+4        95        Ubyte  table refering to samples
+99       23        Uword  volume envelopes, stored as x,y .... x,y
+122      23        Uword  panning envelopes, stored as x,y .... x,y
+145      1         Ubyte  number of volume points stored in instrument
+146      1         Ubyte  number of panning points stored in instrument
+147      1         Ubyte  volume sustain point
+148      1         Ubyte  volume loop start point
+149      1         Ubyte  volume loop end point
+150      1         Ubyte  panning sustain point
+151      1         Ubyte  panning loop start point
+152      1         Ubyte  panning loop end point
+153      1         Ubyte  volume type: 0 = on ; 1 = sustain ; 2 = loop
+154      1         Ubyte  panning type:0 = on ; 1 = sustain ; 2 = loop
+155      1         Ubyte  vibrato type
+156      1         Ubyte  vibrato sweep
+157      1         Ubyte  vibrato depth
+158      1         Ubyte  vibrato rate
+159      2         Uword  volume fadeout

[edit] Sample Header

?         4         Dword  sample length
+4        4         Dword  loop start
+8        4         Dword  loop end
+12       1         Ubyte  volume
+13       1         Sbyte  finetune  signed byte
+14       1         Ubyte  type 0 = no loop ; 1 = forward loop ; 2 = ping-pong loop ; 16 = 16-bit sampledata
+15       1         Ubyte  panning
+16       1         Sbyte  relative note signed byte
+17       1         Ubyte  reserved
+18       22        char   sample name

[edit] How to use

Read patterns (pseudo code)

If the pattern size equals zero you have to create the pattern and allocate (rows * (nr of channels)) and set the notes to 128


for(int i=0; i< patterns; i++)
{
   patternsize =  OpenDWord; // the size of the pattern.                
   type        =  OpenByte;  // always 0 (atleast should be)             
   Rows        =  OpenWord;  // this is the number of rows in this pattern 
 
   if (patternsize == 0)
      {
      //create a empty pattern 
      Rows = 64; // set rows to 64 by default
      // Allocate rows * (nr of channels) and set the notes to 128 
      }
 
      for(int y=0; y< rows; y++) 
      for(int x=0; x< channels; x++)
      { 
          //readnote
      }
}

The notes are stored using a simple packing scheme, just so that the patterns don't become too large. description of the compression technique follows. Since the higher range of the note byte isn't used. it is used for the compression. If the bit is set, then the other bits are interpreted as follows:


bit 0 set: Open Note byte 
  1 set: Open Instrument byte
  2 set: Open Volume byte  
  3 set: Open Effect byte  
  4 set: Open Parameter byte
Ubyte first;
first = openbyte // open up one byte to perform a little check on it to see if the note is packed or not. 
 
if (first & 128)
   {         // the note is packed    
 
   if (first & 1) note       = openbyte; // the note number. Ranges from 0-96, 97 is note-off
   if (first & 2) instrument = openbyte; // the instrument used 
   if (first & 4) volume     = openbyte; // the volume number
   if (first & 8) effect     = openbyte; // the effect number
   if (first & 16)parameter  = openbyte; // the effect parameter
 
   } else  { // the note isn't packed 
 
   note       = first;
   instrument = openbyte;
   volume     = openbyte;
   effect     = openbyte;
   parameter  = openbyte;
   }

this document is not ready yet. More to come. Lars If you notice anything thats wrong, or just isn't clear. Then don't hesitate to drop me a e-mail (lars_akesson_1(at)hotmail.com) or change the wrong part. this is a wiki after all. :)

Personal tools
Categories