
=============================================================================
Miditracker Song format
=============================================================================

/* The file format is described in pseudo-sourcecode similar to C.
 *
 * UWORD = 2 bytes (unsigned short)
 * ULONG = 4 bytes (unsigned long)
 *
 * All values are stored in big (motorola) endian.
 *
 *
 * The 6-byte header string lets the loader determine that this file is a MidiTracker
 * songfile. Depending on the version we have to take care of some fields which
 * are new in newer versions.
 *
 * For example, if there is a field labeled with "new in V6", this means that in
 * versions >= 6 this field is present and must be skipped in earlier versions.
 *
 */

struct MTSong {
  char   header[6]; // this is always "MTSONG"
  UWORD  version;   // version of fileformat. current version is 13
} mtsong;


struct SongHeader {
// V0
  char   songname[40];
  UWORD  tempo; // up to V8: bpm value,
                // since V9 with 2 decimal places, e.g. 12540 for 125.40 bpm
  ULONG  length;
  ULONG  oldpositions; // up to V4: number of positions (see below); since V5 unused

// new in V2
  UWORD  maxtracks;

// new in V3
  char   author[20];

// new in V4
  UBYTE  chansliders[16];
  UWORD  mastervolume; // 0-127

// new in V7
  UBYTE  loopsong;
  UBYTE  reserved2;
  ULONG  looppos;
  BYTE   desttrans[16];

// new in V8
  UBYTE  pchgtypes[16];
  // progchange types:
  //   0  normal
  //   1  extended (bank = controlsource 32)
  //   2  JV1080 User
  //   3  JV1080 Preset A
  //   4  JV1080 Preset B
  //   5  JV1080 Preset C
  //   6  JV1080 Preset D (GM)
  //   7  JV1080 DATA
  //   8  JV1080 PCM
  //   9  JV1080 Expansion A1
  //  10  JV1080 Expansion A2
  //  11  JV1080 Expansion B1
  //  12  JV1080 Expansion B2
  //  13  JV1080 Expansion C1
  //  14  JV1080 Expansion C2
  //  15  JV1080 Expansion D1
  //  16  JV1080 Expansion D2
  //  17  Boehm Bank 0
  //  18  Boehm Bank 1
  //  19  Boehm Bank 2
  //  20  Roland MC-303
  //  21  Yamaha XG
  //  22  QuasiMIDI Quasar
  //  23  Yamaha CS1x

// new in V9
  ULONG  sysex_msgs; // number of sysex messages
  ULONG  default_resolution;

// new in V10
  ULONG patterntablen; // length of pattern table

// new in V12
  UWORD openchannels; // channelwindows which are opened: bit 0 = channel1, ...
  struct Channeldata {
    UWORD left, top; // window coords
    ULONG displayed_tracks; // number of tracks being displayed
    ULONG chanlines; // number of visible lines divided by 2 (only one half, above middle line)
                     // e.g. this is 4 when there are 9 lines visible in the channelwindow
  } cdata[16];

// new in V13
  UWORD channelmutes; // mute state (bit 0 = channel1, ...)

} songheader;


// new in V6
UWORD  channels_maps[16]; // mapping (from stacker/remapper):
                          // 1 word for each channel: bit 0 = mapped to channel 1, ...

// new in V1
char   channelnames[16][24];


// new in V11
struct Filters
{
  // midi-in filters: bit 0 = channel1, ...
  UWORD note_ifilter;
  UWORD progchange_ifilter;
  UWORD pitchbend_ifilter;
  UWORD monopress_ifilter;
  UWORD ppress_ifilter;

  // midi-out filters: bit 0 = channel1, ...
  UWORD note_ifilter;
  UWORD progchange_ifilter;
  UWORD pitchbend_ifilter;
  UWORD monopress_ifilter;
  UWORD ppress_ifilter;

  // filters for each midi controlsource: bit 0 = channel1, ...
  UWORD controlsources_ifilter[128];
  UWORD controlsources_ofilter[128];

  // global switches (zero or not zero)
  UBYTE global_ifilter;
  UBYTE global_ofilter;
};


// always present (V0)
if mtsong.version >= 5 then
  UWORD positions[songheader.length];
else // V0-V4
  UWORD positions[songheader.oldpositions];

// new in V9
struct SysexMessage
{
  ULONG  length; /* length of body, aligned to 4 bytes */
  char   body[(length+3)&-4]; // aligned to 4 bytes
  char   name[sysex_name_len];
} sysex_messages[songheader.sysex_msgs];


// patterns are following, counting backwards (last pattern first)

struct TrackData
{

  struct Pattern
  {
    ULONG events;
    UWORD channelmask;  // channels on/off (bit0 = channel1, ...)
    ULONG bpmtracksize; // size of bpmtrack data, 0 = no bpmtrack
    UWORD pattnum;      // pattern number
    UWORD channels;     // these channels will follow (bit0 = channel1, ...)
  } pattern;

  UBYTE BPMTrack[pattern.bpmtracksize]; // 2-byte-packed data
  // since V9, bpm values in this track have 2 decimal places - see songheader above


  // channels 16 down to 1, empty channels are not saved (see pattern.channels)

  struct Channel
  {
    // channel header

    ULONG presettracksize;    // size of preset track data, or zero for no preset track.
    ULONG pitchbendtracksize; // dito
    ULONG mpresstracksize;    // dito
    UWORD numcs;              // number of Controlsources
    UBYTE pitchbend_onoff;    // 0 = off, other = on
    UBYTE mpress_onoff;       // 0 = off, other = on
    UWORD resolution;         // channel resolution
    UWORD numtracks;          // number of note-tracks


    UBYTE presettrack[presettracksize]; // 2-byte-packed data

    UBYTE pitchbendtrack[pitchbendtracksize]; // 2-byte-packed data

    UBYTE mpresstrack[mpresstracksize]; // 1-byte-packed data


    // controlsources tracks follow

    struct ControlSource
    {
      UBYTE parameter; // Controlsource parameter number, e.g. 7 = volume, 1 = modwheel
      UBYTE onoff;     // 0 = track is off, else on
      ULONG datasize;  // size of following track data
      UBYTE data[datasize]; // 1-byte-packed data
    } csources[numcs];


    struct NoteTrack
    {
      UWORD tracknumber; // number of track (0, 1, ...)
      UBYTE onoff;       // 0 = track is off, else on
      UBYTE padding;
      ULONG datasize;    // size of following track data
      UBYTE data[datasize]; // 4-byte-packed data
    } notetracks[numtracks];

  } channel[];

};


// new since V10
ULONG zero_eof = 0; // last 4 bytes of file are zero


// END OF MT SONG FILE


/*
 * Algorithm for decrunching 1-byte-packed (2-byte-packed) data (pseudo code)
 * (it is a simple RLE algorithm)
 *
 * events = events in the pattern (e.g. 24 clocks * 4 beats * 4 bars = 384 events)
 * src    = array of signed char (word), holding the packed stream
 * dest   = array of signed char (word), receiving unpacked data
 * clear  = value to set an unused event, e.g. 128 or -1 or whatever you want
 *
 * 1-byte-packed data is used on controlsource tracks and mpress tracks.
 * 2-byte packed data is used on preset tracks and pitchbend tracks
 */

src_count = 0;
dest_count = 0;
while( dest_count < events )
{
  value = src[src_count];

  if( value < 0 )
  {
    // value is negative; in positive, it is the number of empty events

    for( i = value; i < 0; i = i + 1 )
    {
      dest[dest_count] = clear;
      dest_count = dest_count + 1;
    }
  }
  else
  {
    // value is positive: so this is a valid value

    dest[dest_count] = value;
    dest_count = dest_count + 1;
  }

  src_count = src_count + 1;
}



/*
 * Algorithm for decrunching 4-byte-packed data (pseudo code)
 *
 * events = events in the pattern (e.g. 24 clocks * 4 beats * 4 bars = 384 events)
 * src    = array of signed char, holding the packed stream
 * dest   = array of signed char, receiving unpacked data
 * clear  = value to set an unused event, e.g. 128 or -1 or whatever you want
 *
 * 4-byte packed data is used only on note tracks.
 *
 * This algorithm is a slightly modified version of the 1(2)-byte-packed data algorithm.
 * In the 1(2)-byte-packed data algorithm, negative and positive values both take 1 or
 * 2 bytes, respectively.
 * The difference to 1(2)-byte-packed data is, that the negative value (which is
 * indicating the number of following empty events) takes 2 bytes, and the positive
 * value (indicating a valid value) takes 4 bytes.

 * To make the difference clear, the following algorithm uses C-style variable declarations.
 *
 */

WORD *src, *dest; // initialized to something
WORD value;
LONG clear; // initialized to the empty value

src_count = 0;
dest_count = 0;

while( dest_count < events )
{
  value = src[src_count];

  if( value < 0 )
  {
    // value is negative; in positive, it is the number of empty events

    for( i = value; i < 0; i = i + 1 )
    {
      // split clear value into two words

      dest[dest_count]   = clear>>16;
      dest[dest_count+1] = clear & 0xffff;

      dest_count = dest_count + 2;
    }
  }
  else
  {
    // value is positive: so this is a valid value

    dest[dest_count]   = value;
    src_count = src_count + 1;
    dest[dest_count+1] = src[src_count]; // copy the next word from src

    dest_count = dest_count + 2;
  }

  src_count = src_count + 1;
}




=============================================================================
MidiTracker SysEx Format
=============================================================================

#define sysex_name_len  40

struct MTSysEx0 {
  char   header[7];
  UBYTE  version;
  UWORD  length;
  char   name[sysex_name_len];
} sysex;

struct MTSysEx1 {
  char   header[7];
  UBYTE  version;
  ULONG  length;
  char   name[sysex_name_len];
} sysex;

sysex.header  = "MTSYSEX";
sysex.version = 1;


