-----------------------------------------------------------------------------

        MED/OctaMED MMD0/MMD1/MMD2/MMD3 file formats
        written by Teijo Kinnunen (01.02.1996)
        Revision 6

$VER: MMD_documentation 6 (01.02.1996)

-----------------------------------------------------------------------------

Background
~~~~~~~~~~
A couple of years ago, when programming MED V2.1, I needed a file format for
MED modules. The only "module" format in MED V2.0 was the Sng+samples format.
Although it produced compact files, it was very difficult and tricky to read
in. Therefore, I designed a new file format, that would be easy to use in
module player programs etc. This file format was named 'MMD0' (Med MoDule 0).
The limitations in MMD0 block format forced me to create a new file format
for OctaMED Professional, this format is 'MMD1'. It's mostly the same as
MMD0, except the block structure is different. Another new format is called
'MMD2', this extends some of the old limits and provides a couple of new
features. 'MMD3' is identical to 'MMD2', but programs supporting this
format must be able to recognize mixing mode of OctaMED Soundstudio. (This
new id was introduced so that old program would not try to play modules they
really can't.) Note that 'V7' in the following documentation refers to
OctaMED Soundstudio V1.

Design concepts
~~~~~~~~~~~~~~~
One of the main goals was to make MMD's (MED modules) as extensible as
possible. This would have been easy to implement with IFF-style chunks.
However, this method was obviously not the best for play-routine use.

Therefore, MMD's are implemented in quite an extraordinary way. They consist
of structures (similar to C structs), and pointers. In a module file,
pointers are defined as offsets from the beginning of the module. This way, a
particular structure can be read just by Seek()'ing using the pointer as the
offset from the beginning of the file. When a module has been read into
memory, it has to be relocated before it can be used (the relocation is done
simply by adding the address of the module to the pointers).

As with the Amiga OS, a MMD file does not contain absolute addresses. There's
a module header structure at the beginning of the file. This structure
contains pointers to different parts of the module. And you *MUST* use these
pointers. You may NOT expect that the song structure is at offset $00000034,
for example. Although it usually is, this may change in future releases. In
addition, it's possible that a structure even doesn't exist (the structure
pointer is NULL). Therefore, you *MUST* check the structure pointer before
accessing the structure. Finally, when writing MMD's you *MUST* set
undefined/reserved fields to zeros. More finally, you *MUST* align all
structures to even boundaries! (I forgot the alignment in MED V3.00 save
routine, resulting Guruing modules under some conditions :-(

The module header
~~~~~~~~~~~~~~~~~
This structure must exist at the beginning of each MED module file. Each of
the structure members are described.

In multi-modules, there are header structs for each song. (The subsequent
header pointers can be found from expdata structure. Multi-modules should
have the same smplarr pointer in every header.) Older MEDs which don't
recognize multi-modules consider a multi-module as an ordinary module (only
the first song is loaded).

The numbers enclosed in /* */ at the beginning of each line are (decimal)
offsets of each member (for assembly programmers).

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
struct MMD0 {
/* 0 */     ULONG   id;
/* 4 */     ULONG   modlen;
/* 8 */     struct MMD0song *song;
/* 12 */    UWORD   psecnum;    /* for the player routine, MMD2 only */
/* 14 */    UWORD   pseq;       /*  "   "   "   "    */
/* 16 */    struct MMD0Block **blockarr;
/* 20 */    UBYTE   mmdflags;
/* 21 */    UBYTE   reserved[3];
/* 24 */    struct InstrHdr **smplarr;
/* 28 */    ULONG   reserved2;
/* 32 */    struct MMD0exp *expdata;
/* 36 */    ULONG   reserved3;
/* 40 */    UWORD   pstate;  /* some data for the player routine */
/* 42 */    UWORD   pblock;
/* 44 */    UWORD   pline;
/* 46 */    UWORD   pseqnum;
/* 48 */    WORD    actplayline;
/* 50 */    UBYTE   counter;
/* 51 */    UBYTE   extra_songs; /* number of songs - 1 */
}; /* length = 52 bytes */

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
id
--
This longword is used to identify the MMD and its version. Currently defined
MMD types are MMD0 (0x4D4D4430), MMD1 (0x4D4D4431), MMD2 (0x4D4D4432) and
MMD3 (0x4D4D4433). MMD4 and upwards are reserved for future versions. Note
that MMD2 and MMD3 file formats are identical (some notes exist below,
though).

In multi-modules, the following modules usually contain id MCNT, MCN1, MCN2
or MCN3. The first module always has MMD0 - MMD3 as an id.

modlen
------
This longword contains the length of the entire module.

song
----
Pointer to a MMD0song/MMD2song structure. This structure MUST ALWAYS EXIST!

blockarr
--------
Pointer to a table of block pointers. For example:
    blockarr:  $00003000
            block 0 ptr block 1 ptr block 2 ptr
offset  $00003000:  $00002000,  $00002400,  $00002800 ....

offset  $00002000: block 0 data...
offset  $00002400: block 1 data...
...
The size of the table is MMD0song.numblocks longwords.

mmdflags
--------
This field contains generic flags of the module. Only one flag is currently
defined:

    MMD_LOADTOFASTMEM    0x1

This flag instructs the loading routine (LoadModule) to always read this
module into fast RAM (if it uses mixing, 8 ch mode or no samples). Not all
versions of OctaMED write this flag.

smplarr
-------
Pointer to a table of instrument pointers. The size of the table is
MMD0song.numsamples longwords. This pointer is zero in OctaMED Pro MMD1 songs.
In this case, OctaMED Pro loads the instruments from disk(s).

expdata
-------
Pointer to an expansion structure. The expansion structure contains a lot of
extra information. The exp. structure does not exist in all MMD's. (Be sure
to check the pointer before using it.)

pstate, pblock, pline, pseqnum, actplayline, counter, psecnum, pseq
-------------------------------------------------------------------
These are variables for the play routine. You can read these fields to get
the current song position (not all versions of the play routine use these
fields, however). When writing a MMD, you should leave all fields to zero,
except the 'actplayline', which ought to be -1 ($FFFF).

extra_songs
-----------
This field contains the number of songs in the current module. For
non-multi-modules, this is 0. If there are two songs, extra_songs contains 1,
and so on.

reserved0,1,2,3
---------------
Not currently defined. Set to zero.


The song structure (MMD0song)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This structure contains the basic information about the song. It must exist
on every module file. This structure is for MMD0/MMD1 only! The MMD2 struct
is documented below.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
struct MMD0song {
    struct MMD0sample sample[63];   /* 63 * 8 bytes = 504 bytes */
    UWORD   numblocks;      /* offs: 504 */
    UWORD   songlen;        /* offs: 506 */
    UBYTE   playseq[256];   /* offs: 508 */
    UWORD   deftempo;       /* offs: 764 */
    BYTE    playtransp;     /* offs: 766 */
    UBYTE   flags;          /* offs: 767 */
    UBYTE   flags2;         /* offs: 768 */
    UBYTE   tempo2;         /* offs: 769 */
    UBYTE   trkvol[16];     /* offs: 770 */
    UBYTE   mastervol;      /* offs: 786 */
    UBYTE   numsamples;     /* offs: 787 */
}; /* length = 788 bytes */

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sample
------
Contains some basic info about each sample. The structure looks like this:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    struct MMD0sample {
        UWORD rep,replen;   /* offs: 0(s), 2(s) */
        UBYTE midich;       /* offs: 4(s) */
        UBYTE midipreset;   /* offs: 5(s) */
        UBYTE svol;         /* offs: 6(s) */
        BYTE strans;        /* offs: 7(s) */
    };

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    rep         repeat start offset, shifted right one bit (as in
                Protracker).
    replen      repeat length, shifted right one bit.
    midich      MIDI channel for current instrument, 0 if not MIDI.
    midipreset  MIDI preset number for current instrument, 0 if no preset.
    svol        default volume for current instrument (0 - 64).
    strans      instrument transpose value.

More information is defined in expdata structure.

numblocks
---------
Number of blocks in current song. This field also indicates the length of the
blockarr table in longwords.

songlen
-------
Song length (number of sequence numbers in the play sequence list).

playseq
-------
This is the play sequence list.

deftempo
--------
Default song tempo (the main tempo slider in MED/OctaMED). If BPM mode is on,
this value indicates BPM.

playtransp
----------
The global play transpose value for current song.

flags
-----
Contains many single-bit flags:
    FLAG_FILTERON   0x1     the hardware audio filter is on
    FLAG_JUMPINGON  0x2     mouse pointer jumping on (not in OctaMED Pro)
    FLAG_JUMP8TH    0x4     jump every 8th line (not in OctaMED Pro)
    FLAG_INSTRSATT  0x8     sng+samples indicator (not useful in MMD's)
    FLAG_VOLHEX     0x10    volumes are HEX
    FLAG_STSLIDE    0x20    use ST/NT/PT compatible sliding
    FLAG_8CHANNEL   0x40    this is OctaMED 5-8 channel song
    FLAG_SLOWHQ     0X80    HQ V2-4 compatibility mode

flags2
------
More flags:
    FLAG2_BMASK 0x1F (bits 0-4)     BPM beat length (in lines)
                                    0 = 1 line, $1F = 32 lines.
                                    (OctaMED Pro Lines Per Beat slider.)
    FLAG2_BPM   0x20    BPM mode on
    FLAG2_MIX   0x80    This flag implies that the module uses mixing.

    (bit 0x40 is not defined, and must be set to zero)

tempo2
------
This is the "secondary tempo" (the rightmost MED/OctaMED tempo slider),
indicating the number of timing pulses per line.

trkvol[16]
----------
The relative track volumes (1 - 64) for each track.

mastervol
---------
The relative master volume (1 - 64).

numsamples
----------
Number of instruments (samples/synthsounds) in current song. Also indicates
the size of the smplarr table in longwords.

The MMD2 song structure
~~~~~~~~~~~~~~~~~~~~~~~
struct MMD2song {
    struct MMD0sample sample[63];
    UWORD   numblocks;
    UWORD   songlen;    /* NOTE: number of sections in MMD2 */
    struct  PlaySeq **playseqtable;
    UWORD   *sectiontable;  /* UWORD section numbers */
    UBYTE   *trackvols; /* UBYTE track volumes */
    UWORD   numtracks;  /* max. number of tracks in the song
                           (also the number of entries in
                           'trackvols' table) */
    UWORD   numpseqs;   /* number of PlaySeqs in 'playseqtable' */
    BYTE    *trackpans;		/* NULL means 'all centered */
    ULONG   flags3;		/* see defs below */
    UWORD   voladj;		/* volume adjust (%), 0 means 100 */
    UWORD   channels;		/* mixing channels, 0 means 4 */
    UBYTE   mix_echotype;	/* 0 = nothing, 1 = normal, 2 = cross */
    UBYTE   mix_echodepth;	/* 1 - 6, 0 = default */
    UWORD   mix_echolen;	/* echo length in milliseconds */
    BYTE    mix_stereosep;	/* stereo separation */
    UBYTE   pad0[223];		/* reserved for future expansion */
/* Below fields are MMD0/MMD1-compatible (except pad1[]) */
    UWORD   deftempo;
    BYTE    playtransp;
    UBYTE   flags;
    UBYTE   flags2;
    UBYTE   tempo2;
    UBYTE   pad1[16];   /* used to be trackvols, in MMD2 reserved */
    UBYTE   mastervol;
    UBYTE   numsamples;
};

This structure is exactly as long as the MMDsong structure. Common fields are
located at same offsets. You can also see, that there's a lot of room for
expansion in this structure. The new/changed fields are:

songlen
-------
Now expresses the number of sections (i.e. the length of 'sectiontable').

playseqtable
------------
Points to a table of PlaySeq structures. This structure is:

    struct PlaySeq {
        char    name[32];       /* (0)  31 chars + \0 */
        ULONG   reserved[2];    /* (32) for possible extensions */
        UWORD   length;         /* (40) # of entries */
    /* Commented out, not all compilers may like it... */
    /*  UWORD   seq[0]; */      /* (42) block numbers.. */
    };

This should be self-explaining. Note: block numbers in seq[] may not be
greater than 0x7FFF. These are reserved for future expansions. The current
player routines skip these numbers.

trackvols
---------
Points to a table of 'numtracks' UBYTEs, which contain values 1 - 64 for
relative track volumes.

numtracks
---------
The number of tracks this song uses (i.e. the width of the widest block).

numpseqs
--------
The number of PlaySeqs in 'playseqtable'.

trackpans
---------
Points to a table of 'numtracks' BYTEs, which contain values -16 - 16 for
panpot positions of tracks.

flags3
------
These flags:
    FLAG3_STEREO     0x1    Mixing in stereo
    FLAG3_FREEPAN    0x2    Mixing flag: free pan

voladj
------
Volume adjust value of the module (mixing). Value 0 equals volume adjust
100.

channels
--------
Max. number of mixing channels. Value 0 equals 4.

mix_echotype
------------
Currently these echo types are defined (this is an ordinal number, not
a bit field):
	0 = none
	1 = normal
	2 = cross echo

mix_echodepth
-------------
Echo depth, currently these values are defined:
	0 = default
	1 = 50 %
	2 = 25 %
	3 = 12.5 %
	4 = 6.25 %
	5 = 3.125 %
	6 = 1.5625 %

mix_echolen
-----------
Echo length in milliseconds.

mix_stereosep
-------------
Stereo separation (-4 - 4).

pad[]
-----
Must be zero! Don't attempt to read.

The block format
~~~~~~~~~~~~~~~~
As described above, MMD0 header structure contains a pointer (blockarr) to a
table of block pointers. These block pointers point to the actual block data
structures. The format of these data structures differ in MMD0 and MMD1 file
formats.

MMD0 block format
-----------------
At the beginning of each block, there's a small header:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    struct MMD0Block {
        UBYTE numtracks,lines;
    };

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    numtracks   number of tracks (4, 8, 12 or 16) on this block
    lines       number of lines on this block; 0 = 1 line,
                255 = 256 lines

Following this header, there is the actual note data, consisting of 3-byte
structures containing a note and its command. The data is arranged
sequentially a line at a time, i.e. in the following order:
    line 0 track 0
    line 0 track 1
    line 0 track 2
    line 0 track 3
    line 1 track 0
    line 1 track 1
    ...
The 3-byte structure looks like this (each letter corresponds to one bit):

    xynnnnnn iiiicccc dddddddd

    n = note number (0 - $3F). 0 = ---, 1 = C-1, 2 = C#1...
    i = the low 4 bits of the instrument number
    x = the 5th bit (#4) of the instrument number
    y = the 6th bit (#5) of the instrument number
    c = command number (0 - $F)
    d = databyte ($00 - $FF)

MMD1/MMD2 block format
-----------------
MMD1/MMD2 block format can contain a lot more information than MMD0's. The
block header looks like this:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    struct MMD1Block {
        UWORD numtracks;
        UWORD lines;
        struct BlockInfo *info;
    };

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    numtracks   Number of tracks in this block (4, 8, 12, or 16).
                (MMD2: All values between 1 - 64 are valid.)
    lines       Number of lines in this block (0 = 1 line etc.).
                OctaMED Pro can handle upto 3200 lines/block, so
                this is obviously the practical upper limit.
    info        Pointer to structure containing extra information.
                (Can be NULL, if no BlockInfo struct exists).

    The BlockInfo structure is:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    struct BlockInfo {
        ULONG   *hlmask;
        UBYTE   *blockname;
        ULONG   blocknamelen;
        struct  BlockCmdPageTable *pagetable;
        ULONG   reserved[5];
    };

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    hlmask      Pointer to an array of longwords, containing info
                about line highlighting (TAB key on MED). The number
                of longwords depend on the number of lines on the
                block. (E.g: 1 line -> 1 longword, 32 lines -> 1 lw,
                33 lines -> 2 lws, 256 lines -> 4 lws)
                The bits in the longwords are arranged in reversed
                order (e.g. bit #0 = line 0, bit #31 = line 31).

    blockname   Pointer to the name of the block. Must be null-
                terminated.

    blocknamelen    Length of the block name, including the terminating
                    zero. OctaMED Pro currently has the maximum length of
                    41 chars (+ zero). However, this may change in the
                    future. Don't read blocknames longer than you are
                    able to handle!

    pagetable   OctaMED V6 supports multiple player commands per note.
                This pointer points to the BlockCmdPageTable structure,
                if this block has more than one pages. (See below.)

    reserved[5] These are reserved for future extensions. Must be set   
                to zero.

    This is the BlockCmdPageTable structure:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
struct BlockCmdPageTable {
	UWORD	num_pages;
	UWORD	reserved;
	UWORD	*page[0];
};

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    num_pages   Specifies the number of additional command pages. The first
                command page that always exists is not included in this.

    reserved    Some room for future expansions, you never know..

    page        Here begins the table of command page pointers. (The table
                has num_pages entries.) Each page contains two-byte entries
                (command and data byte), which are arranged just as notes
                in blocks. (Line 0 Track 0, Line 0 Track 1...)

    The note structures, which are 4 bytes long in MMD1 modules, are
    arranged exactly as in MMD0 modules (i.e. L0T0, L0T1... L1T0, L1T1..).

        xnnnnnnn xxiiiiii cccccccc dddddddd

    n = note number (0 - $7F, 0 = ---, 1 = C-1...)
    i = instrument number (0 - $3F)
    c = command ($00 - $FF)
    d = data byte ($00 - $FF)
    x = undefined, reserved for future expansion. MUST BE SET TO ZERO,
        AND MASKED OUT WHEN READING THE NOTE OR INSTRUMENT NUMBER.


The instrument format
~~~~~~~~~~~~~~~~~~~~~
The MMD0 header structure contains a pointer (smplarr) to a table of
instrument pointers. These pointers point to the actual instrument data
structures. If an instrument pointer is zero, there's no instrument in that
slot.

Every instrument has a six-byte header structure, which is the same for all
instrument types (sample/synth/hybrid).

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    struct InstrHdr {
        ULONG   length;
        WORD    type;
        /* Followed by actual data */
    };

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    length      indicates the length of the instrument (the six byte
                header data length is not included)
    type        instrument type - currently the following types are
                defined:

        HYBRID      -2
        SYNTHETIC   -1
        SAMPLE      0   (an ordinary 1-octave sample)
        IFF5OCT     1   (5 octaves)
        IFF3OCT     2   (3 octaves)
        (The following ones are recognized by OctaMED Pro only)
        IFF2OCT     3   (2 octaves)
        IFF4OCT     4   (4 octaves)
        IFF6OCT     5   (6 octaves)
        IFF7OCT     6   (7 octaves)
        (OctaMED Pro V5 + later)
        EXTSAMPLE   7   (two extra-low octaves)

The sample-type instruments (>= 0) contain the actual sample data straight
after the header structure.

Since OctaMED V6, there are also two flag bits in the type field:
        S_16        0x10
        STEREO      0x20

S_16 means that this is a 16-bit sample. Length still indicates the sample
length in bytes, so there are actually length / 2 16-bit samples.

STEREO means that this is a stereo sample. The sample is not interleaved. The
left channel comes first, followed by the right channel. Important: Length
specifies the size of one channel only! The actual memory usage for both
samples is length * 2 bytes.

Plus an obsolete item:
        OBSOLETE_MD16    0x18

This instrument type is obsolete, and was used for V5.04 Aura support. It
should be treated as type S_16|SAMPLE (0x10), with instrument's output device
set to Aura.

Synthetic instruments
---------------------
Synthsounds have a special structure of their own. They also contain
waveforms and pointers to them. Therefore, relocation is required. However,
there's an important difference: pointers are expressed as an offset from the
beginning of the synthsound, NOT the beginning of the module. The 'reloc.a'
routine provided with MED/OctaMED automatically handles this.

The synthsound structure is as follows (note that this structure contains the
header structure):

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    struct SynthInstr {
        ULONG   length;     /* length of this struct */
        WORD    type;       /* -1 or -2 (offs: 4) */
        UBYTE   defaultdecay;
        UBYTE   reserved[3];
        UWORD   rep;
        UWORD   replen;
        UWORD   voltbllen;  /* offs: 14 */
        UWORD   wftbllen;   /* offs: 16 */
        UBYTE   volspeed;   /* offs: 18 */
        UBYTE   wfspeed;    /* offs: 19 */
        UWORD   wforms;     /* offs: 20 */
        UBYTE   voltbl[128];    /* offs: 22 */
        UBYTE   wftbl[128]; /* offs: 150 */
        struct  SynthWF *wf[64]; /* offs: 278 */
    };

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    defaultdecay    = the default decay of the current synthsound. This
                      is NOT used in modules. It's significant only when
                      saving a single synthsound.

    reserved[3] = set to zero.

    rep, replen = repeat/rep. length for hybrid sounds. Used only
                  when saving a single hybrid sound.

    voltbllen   = the length of the volume sequence table.

    wftbllen    = the length of the waveform sequence table.

    volspeed    = the initial volume table execution speed.

    wfspeed     = the initial waveform table execution speed.

    wforms      = the number of waveforms in the current synthsound.

    voltbl      = the actual volume sequence table. Values $00-$7F
                  are volumes or command arguments. Values >= $80 are
                  commands. The following commands are currently
                  defined:
                $FF END     $F4 EN1
                $FE JMP     $F3 CHU
                $FB HLT     $F2 CHD
                $FA JWS     $F1 WAI
                $F6 EST     $F0 SPD
                $F5 EN2

    wftbl       = the actual waveform sequence table. Values $00-$7F
                  are waveform numbers  or command arguments. Values
                  >= $80 are commands. The following commands are
                  currently defined:
                $FF END     $F6 RES
                $FE JMP     $F5 VBS
                $FD ARE     $F4 VBD
                $FC ARP     $F3 CHU
                $FB HLT     $F2 CHD
                $FA JVS     $F1 WAI
                $F7 VWF     $F0 SPD

    wf      = pointers to waveforms. (Once again: relative to the
              beginning of the synthsound!) A waveform structure
              is as follows:

                struct SynthWF {
                    UWORD length;   /* length in words */
                    BYTE  wfdata[xx]; /* the waveform */
                };

                (where xx = length in bytes)

              In hybrid sounds, however, wf[0] is different.

Hybrid instruments
------------------
Hybrid sounds use the same structure as synthsounds, except that the first
waveform (wf[0]) pointer points to a sample. (The sample header structure
exists, as usual.)


MMD0exp - the key to future expansions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For possible future expansions, I designed a structure for carrying the
miscellaneous things that were added to MED/OctaMED now and then. (MED V3.00
was the first version, which wrote this structure.) Most of its fields are in
use now, but it's possible to even expand this structure (things will get a
bit more tricky, though).

In multi-modules, you should extract all data from the expansion structure of
the first song. The only exceptions are currently the 'nextmod' and
'songname' fields, which are song-specific.

Also, there has been need for extending the MMD0sample structure. Both
InstrExt and MMDInstrInfo provide extra information about the instruments.
These are defined as structure arrays (exp_smp and iinfo point to the first
structure). The extension structures don't have a constant size, instead you
have to read s_ext_entrsz or i_ext_entrsz to get the structure sizes. When
reading, you have to check the entrsz fields to see which structure members
do exist. See the MMD3 note below for s_ext_entries!!

The difference between InstrExt and MMDInstrInfo is that InstrExt contains
information the play-routine is interested in (e.g. finetune). MMDInstrInfo
contains "secondary" information, which is of no use to the player routine
(e.g. instrument name).

The expansion structure follows:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    struct MMD0exp {
        struct MMD0 *nextmod;
        struct InstrExt *exp_smp;
        UWORD  s_ext_entries;
        UWORD  s_ext_entrsz;
        UBYTE  *annotxt;
        ULONG  annolen;
        struct MMDInstrInfo *iinfo;
        UWORD  i_ext_entries;
        UWORD  i_ext_entrsz;
        ULONG  jumpmask;
        UWORD  *rgbtable;
        UBYTE  channelsplit[4];
        struct NotationInfo *n_info;
        UBYTE  *songname;
        ULONG  songnamelen;
        struct MMDDumpData *dumps;
        struct MMDInfo *mmdinfo;
        struct MMDARexx *mmdrexx;
        struct MMDMIDICmd3x *mmdcmd3x;
        ULONG  reserved2[3];
        ULONG  tag_end;
    };

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    nextmod     = pointer to the next module (or zero). (Only used in
                  multi-modules!)

    exp_smp     = pointer to InstrExt. Currently the first four bytes
                  of InstrExt have been defined:

                    struct InstrExt {
                        UBYTE hold;
                        UBYTE decay;
                        UBYTE suppress_midi_off;
                        BYTE  finetune;
                        /* Below fields saved by >= V5 */
                        UBYTE default_pitch;
                        UBYTE instr_flags;
                        UWORD long_midi_preset;
                        /* Below fields saved by >= V5.02 */
                        UBYTE output_device;
                        UBYTE reserved;
                        /* Below fields saved by >= V7 */
                        ULONG long_repeat;
                        ULONG long_replen;
                    };

                    hold, decay = hold/decay values of the
                                  instrument

                    suppress_midi_off = 0 (FALSE) or not (TRUE)

                    finetune    = instrument finetune (-8-+7)

                    default_pitch = instrument's default pitch
                                    (0 = ---, 1 = C-1, 2 = C#1...)

                    instr_flags = some miscellaneous flags:
                                  SSFLG_LOOP     0x01 (Loop On/Off)
                                  SSFLG_EXTPSET  0x02 (Ext. Preset)
                                  SSFLG_DISABLED 0x04 (Disabled)
                                  SSFLG_PINGPONG 0x08 (Ping-pong looping)

                    long_midi_preset = overrides the preset in the
                                       song structure (allows ext.
                                       presets)

                    output_device = instrument's output device,
                                    currently the following exist:
                                    OUTPUT_STD  0 (standard Amiga audio)
                                    OUTPUT_MD16 1 (Aura)
                                    OUTPUT_TOCC 2 (Toccata)

                    reserved = zero, at the moment

                    long_repeat, long_replen = override repeat and repeat
                            length values in the song structure. These
                            fields allow long and odd repeat values.
                            (Which are not useful unless mixing or using
                            fast mem playing.)

    s_ext_entries   = the size of InstrExt structure array (i.e. the
                      number of InstrExt structures). IMPORTANT: If you are
                      reading MMD3 modules, this value may be greater than
                      63! You should ignore any exp_smp structures above 63
                      in that case! (Making room for > 63 instruments.)

    s_ext_entrsz    = the size of each InstrExt structure (in bytes).

    annotxt     = pointer to the annotation text (null-terminated).

    annolen     = length of 'annotxt', including the terminating \0.

    iinfo       = pointer to MMDInstrInfo. Currently the first forty
                  bytes have been defined:

                    struct MMDInstrInfo {
                        UBYTE   name[40];
                    };

                  name = null-terminated instrument name

    i_ext_entries   = the size of the MMDInstrInfo struct array (i.e. the
                      number of MMDInstrInfo structures).

    i_ext_entrsz    = the size of each MMDInstrInfo struct in bytes.

    jumpmask    = a mask controlling which instruments cause the
                  mouse pointer to jump. E.g. bit #1 = instr. #1.
                  This field has become obsolete in OctaMED Pro.

    rgbtable    = pointer to eight UWORDs (screen colors) to be
                  passed to LoadRGB4() routine.

    channelsplit    = this longword is divided to four boolean bytes,
                      controlling channel splitting in OctaMED 5 - 8 chnl
                      modes. (A non-zero byte means that the channel is
                      NOT splitted.) Currently only the following
                      combinations should be used:

                      0x00000000 (8 channels (or normal 4 channel mode))
                      0x000000FF (7 channels)
                      0x0000FFFF (6 channels)
                      0x00FFFFFF (5 channels)

    n_info      = pointer to NotationInfo structure (used only in
                  OctaMED V2.0 and later). It contains some info for
                  the notation editor.
                
                    struct NotationInfo {
                        UBYTE n_of_sharps;
                        UBYTE flags;
                        WORD  trksel[5];
                        UBYTE trkshow[16];
                        UBYTE trkghost[16];
                        BYTE  notetr[63];
                        UBYTE pad;
                    };

                  n_of_sharps   = number of sharps or flats (0 - 6)
                  flags     = misc. bits, these are defined:
                              NFLG_FLAT   1
                           (= use flats instead of sharps)
                              NFLG_3_4    2
                           (= display 12 lines instead of 16)

                  trksel    = the number of the selected track,
                              for each display preset
                              (-1 = no track selected)

                  trkshow   = tracks shown (five bits used in
                              each byte, bit #0 = preset 1, etc.)

                  trkghost  = tracks ghosted (as in 'trkshow')

                  notetr    = note transpose value for each
                              instrument (-24 - +24). If bit 6 is
                              negated, the instrument is hidden.

                  pad       = possibly holding info about struct
                              expansions in the future. Don't touch!

    songname    = song name of the current song (0-terminated).
                  Each song of a multi-module can have a different
                  name.

    songnamelen = song name length (including the terminating zero).

    dumps       = MIDI dump data (created using OctaMED Pro MIDI
                  message editor). The 'dumps' field points to the
                  following struct:

                    struct MMDDumpData {
                        UWORD   numdumps;
                        UWORD   reserved[3];
                    };

                  Immediately after this struct, there are 'numdumps'
                  pointers to the following struct:

                    struct MMDDump {
                        ULONG   length;
                        UBYTE   *data;
                        UWORD   ext_len;
                        /* if ext_len >= 20: */
                        UBYTE   name[20];
                    };

                  length    = length of the MIDI message dump.

                  data      = pointer to the actual MIDI dump
                              data.

                  ext_len   = MMDDump struct extension length.
                              For flexible future expansion.

                  (if ext_len >= 20, the following fields exist)

                  name      = name of the dump.

    mmdinfo     = provides more information about the song that annotxt.
                  Currently allows a text file to be attached. The
                  structure MMDInfo is:

                  struct MMDInfo {
                      struct MMDInfo *next;
                      UWORD reserved;
                      UWORD type;
                      ULONG length;
                  /* data follows... */
                  };

                  next = pointer to the next MMDInfo structure. However,
                         OctaMED 6 only supports one attachment, so this
                         field is not used at the moment. May change in
                         the future.

                  reserved = 0

                  type = data type. This is for maximum flexibility for
                         future expansions. Currently only type 1 (ASCII
                         text) is supported. Other types should be ignored.

                         ASCII is standard Amiga ISO ASCII. Lines terminated
                         by a single '\n'. The text is null terminated. No
                         tabs allowed (ListView gadgets can't display them).

                  length = data length in bytes.

    mmdrexx     = contains the embedded ARexx commands (triggered by the
                  song). 'mmdrexx' points to this structure:

                  struct MMDARexx {
                      UWORD  res;	/* reserved, must be zero! */
                      UWORD  trigcmdlen; /* size of trigcmd entries
                                            (MUST be used!!) */
                      struct MMDARexxTrigCmd *trigcmd; /* a chain of
                                         MMDARexxTrigCmds, or NULL */
                  };

                  'trigcmdlen' is the size of trigcmd entries. You must
                  write sizeof(struct MMDARexxTrigCmd) to this field when
                  writing modules.

                  struct MMDARexxTrigCmd is:

                  struct MMDARexxTrigCmd {
                      struct MMDARexxTrigCmd *next; /* the next command,
                                                      or NULL */
                      UBYTE cmdnum; /* command number (01..FF) */
                      UBYTE pad;
                      WORD cmdtype; /* command type (OMACTION_...) */
                      STRPTR cmd; /* command, or NULL */
                      STRPTR port; /* port, or NULL */
                      UWORD cmd_len; /* length of 'cmd' string (without
                              term. 0) */
                      UWORD port_len; /* length of 'port' string (without
                              term. 0) */
                  }; /* current (V7) structure size: 20 */

                  next = Pointer to the next instance of this structure.
                         Use when reading.

                  cmdnum = Command (data byte) number for sending this
                           command (01...FF).

                  cmdtype = Command type (see modplayer.h).

                  cmd = Command string (pointer), NULL if none.

                  port = Port name string (pointer), NULL if none.
                         (For OMACTION_CMDEXT.)

                  cmd_len, port_len = lengths of the above two strings

    mmdcmd3x    = This structure contains the settings for command 3x.
                  The information is in the following structure:

                  struct MMDMIDICmd3x {
                      UBYTE struct_vers; // current version = 0
                      UBYTE pad;
                      UWORD num_of_settings; // number of Cmd3x settings
                                             // (currently set to 15)
                      UBYTE *ctrlr_types; // controller types [ignore
                                          // unknown types!!]
                      UWORD *ctrlr_numbers; // controller numbers
                  };

                  struct_vers = 0

                  num_of_settings = number of controller settings
                                    (could be > 15 in the future)

                  ctrlr_types = pointer to a UBYTE array of controller
                                types (see modplayer.h for MCS_TYPE_xx
                                definitions).

                  ctrlr_numbers = pointer to a UWORD array of controller
                                  numbers

    reserved2   = future expansion fields, that MUST be zero now.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Finally, here is a collection of the most important rules you should obey
when handling MMD's:

    * Always use pointers, not absolute offsets.

    * Check that a pointer is nonzero before accessing anything it
      points to.

    * When writing, set undefined/reserved bits and bytes to zero.
      When reading, mask out undefined bits, and don't use undefined
      fields.

    * When writing, always align everything to even boundaries.

    * When writing, always write the song structure.

    * Remember to handle error situations correctly (in all programs,
      not only when handling MMDs ;^)

If you don't understand some part of this file completely, try saving a
module and examine the file with a file editor. This way you can learn easily
about the file format of MED/OctaMED.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
