-----------------------------------------------------------------------------
         Fully Copyrighted 1993 RBF Software

        MED/OctaMED MMD0/MMD1/MMD2 file formats
        written by Teijo Kinnunen (30.05.1993)
        Revision 2

$VER: MMD_documentation 2 (30.05.1993)

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

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

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 is 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 */    ULONG   reserved1;
/* 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) and MMD2 (0x4D4D4432).
MMD3 and upwards are reserved for future versions.

In  multi-modules,  the  following  modules  usually contain id MCNT, MCN1 or
MCN2.  The first module always has MMD0 - MMD2 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.

smplarr
-------
Pointer to a table of instrument pointers. The size of the table is
MMD0song.songlen 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 leftmost 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

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

flags2
------
More flags, currently only BPM stuff:
    FLAG2_BMASK 0x1F (bits 0-4)     BPM beat length (in lines)
                        0 = 1 line, $1F = 32 lines.
                    (The rightmost slider in OctaMED Pro
                     BPM mode.)
    FLAG2_BPM   0x20    BPM 

