diff playercode/load_med.c @ 4:5d614bcc4287

Initial entry of mikmod into the CVS tree.
author darius
date Fri, 23 Jan 1998 16:05:08 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/playercode/load_med.c	Fri Jan 23 16:05:08 1998 +0000
@@ -0,0 +1,490 @@
+/*
+
+ Name: LOAD_MED.C
+
+ Description:
+ Amiga MED module loader
+
+ Portability:
+ All systems - all compilers (hopefully)
+
+ If this module is found to not be portable to any particular platform,
+ please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for
+ more information on contacting the author).
+
+*/
+
+#include <string.h>
+#include "mikmod.h"
+
+#define MMD0_string 0x4D4D4430
+#define MMD1_string 0x4D4D4431
+
+typedef struct MMD0
+{   ULONG   id;
+    ULONG   modlen;
+    ULONG   MMD0songP;        // struct MMD0song *song;
+    UWORD   psecnum;          // for the player routine, MMD2 only
+    UWORD   pseq;             //  "   "   "   "
+    ULONG   MMD0BlockPP;      // struct MMD0Block **blockarr;
+    ULONG   reserved1;
+    ULONG   InstrHdrPP;       // struct InstrHdr **smplarr;
+    ULONG   reserved2;
+    ULONG   MMD0expP;         // struct MMD0exp *expdata;
+    ULONG   reserved3;
+    UWORD   pstate;           // some data for the player routine
+    UWORD   pblock;
+    UWORD   pline;
+    UWORD   pseqnum;
+    SWORD   actplayline;
+    UBYTE   counter;
+    UBYTE   extra_songs;      // number of songs - 1
+} MMD0;
+
+
+typedef 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)
+    SBYTE strans;            // offs: 7(s)
+} MMD0sample;
+
+
+typedef struct MMD0song
+{   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
+    SBYTE   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
+} MMD0song;
+
+
+typedef struct MMD0NOTE
+{  UBYTE a,b,c;
+} MMD0NOTE;
+
+
+typedef struct MMD1NOTE
+{   UBYTE a,b,c,d;
+} MMD1NOTE;
+
+
+typedef struct InstrHdr
+{   ULONG   length;
+    SWORD   type;
+    // Followed by actual data
+} InstrHdr;
+
+
+static MMD0 *mh     = NULL;
+static MMD0song *ms = NULL;
+static ULONG *ba    = NULL;
+static MMD0NOTE *mmd0pat = NULL;
+static MMD1NOTE *mmd1pat = NULL;
+
+#define d0note(row,col) mmd0pat[(row*(UWORD)of.numchn)+col]
+#define d1note(row,col) mmd1pat[(row*(UWORD)of.numchn)+col]
+
+
+static CHAR MED_Version[] = "MED";
+
+
+BOOL MED_Test(void)
+{
+    UBYTE id[4];
+
+    if(!_mm_read_UBYTES(id,4,modfp)) return 0;
+    if(!memcmp(id,"MMD0",4)) return 1;
+    if(!memcmp(id,"MMD1",4)) return 1;
+    return 0;
+}
+
+
+BOOL MED_Init(void)
+{
+    if(!(mh=(MMD0 *)_mm_calloc(1,sizeof(MMD0)))) return 0;
+    if(!(ms=(MMD0song *)_mm_calloc(1,sizeof(MMD0song)))) return 0;
+    return 1;
+}
+
+
+void MED_Cleanup(void)
+{
+    if(mh!=NULL) free(mh);
+    if(ms!=NULL) free(ms);
+    if(ba!=NULL) free(ba);
+    if(mmd0pat!=NULL) free(mmd0pat);
+    if(mmd1pat!=NULL) free(mmd1pat);
+
+    mh = NULL;
+    ms = NULL;
+    ba = NULL;        // blockarr
+    mmd0pat = NULL;
+    mmd1pat = NULL;    
+}
+
+
+void EffectCvt(UBYTE eff,UBYTE dat)
+{
+    switch(eff)
+    {   // 0x0 0x1 0x2 0x3 0x4      // PT effects
+        case 0x5:       // PT vibrato with speed/depth nibbles swapped
+           UniPTEffect(0x4,(dat>>4) | ((dat&0xf)<<4) );
+        break;
+
+        case 0x6:       // not used
+        case 0x7:       // not used
+        case 0x8:       // midi hold/decay
+        break;
+
+        case 0x9:
+           if(dat<=0x20) UniPTEffect(0xf,dat);
+        break;
+
+        // 0xa 0xb 0xc all PT effects
+
+        case 0xd:       // same as PT volslide
+           UniPTEffect(0xa,dat);
+        break;
+
+        case 0xe:       // synth jmp - midi
+        break;
+
+        case 0xf:
+           // F00 does patternbreak with med
+           if(dat==0) UniPTEffect(0xd,0);
+           else if(dat<=0xa) UniPTEffect(0xf,dat);
+           else if(dat<0xf1) UniPTEffect(0xf,((UWORD)dat*125)/33);
+           else if(dat==0xff) UniPTEffect(0xc,0);  // stop note
+        break;
+
+        default:        // all normal PT effects are handled here :)
+           // Convert pattern jump from Dec to Hex
+           if(eff == 0xd)
+               dat = (((dat&0xf0)>>4)*10)+(dat&0xf);
+           UniPTEffect(eff,dat);
+        break;
+    }
+}
+
+
+
+UBYTE *MED_Convert1(int col)
+{
+    int t;
+    UBYTE a,b,c,d,inst,note,eff,dat;
+    MMD1NOTE *n;
+
+    UniReset();
+    for(t=0; t<64; t++)
+    {   n = &d1note(t,col);
+        a = n->a;
+        b = n->b;
+        c = n->c;
+        d = n->d;
+
+        note = a&0x7f;
+        inst = b&0x3f;
+        eff  = c&0xf;
+        dat  = d;
+
+        if(inst!=0) UniInstrument(inst-1);
+        if(note!=0) UniNote(note+23);
+
+        EffectCvt(eff,dat);
+        UniNewline();
+    }
+
+    return UniDup();
+}
+
+
+UBYTE *MED_Convert0(int col)
+{
+    int t;
+    UBYTE a,b,c,inst,note,eff,dat;
+    MMD0NOTE *n;
+
+    UniReset();
+    for(t=0;t<64;t++)
+    {   n = &d0note(t,col);
+        a = n->a;
+        b = n->b;
+        c = n->c;
+
+        note = a & 0x3f;
+        a  >>= 6;
+        a    = ((a & 1) << 1) | (a >> 1);
+
+        inst = (b >> 4) | (a << 4);
+        eff  = b & 0xf;
+        dat  = c;
+
+        if(inst!=0) UniInstrument(inst-1);
+        if(note!=0) UniNote(note+35);
+
+        EffectCvt(eff,dat);
+        UniNewline();
+    }
+    return UniDup();
+}
+
+
+BOOL LoadMMD0Patterns(void)
+{
+   int      t,row,col;
+   UWORD    numtracks,numlines,maxlines=0,track=0;
+   MMD0NOTE *mmdp;
+   
+   // first, scan patterns to see how many channels are used
+   for(t=0; t<of.numpat; t++)
+   {   _mm_fseek(modfp,ba[t],SEEK_SET);
+       numtracks = _mm_read_UBYTE(modfp);
+       numlines  = _mm_read_UBYTE(modfp);
+
+       if(numtracks>of.numchn) of.numchn = numtracks;
+       if(numlines>maxlines) maxlines = numlines;
+   }
+
+   of.numtrk = of.numpat*of.numchn;
+   if(!AllocTracks()) return 0;
+   if(!AllocPatterns()) return 0;
+
+   if(!(mmd0pat=(MMD0NOTE*)_mm_calloc(of.numchn*(maxlines+1),sizeof(MMD0NOTE)))) return 0;
+
+   // second read: no more mr. nice guy,
+   // really read and convert patterns
+
+   for(t=0; t<of.numpat; t++)
+   {   _mm_fseek(modfp,ba[t],SEEK_SET);
+       numtracks = _mm_read_UBYTE(modfp);
+       numlines  = _mm_read_UBYTE(modfp);
+
+       of.pattrows[t] = numlines+1;
+       memset(mmdp=mmd0pat,0,of.numchn*maxlines*sizeof(MMD0NOTE));
+       for(row=numlines+1; row; row--)
+       {   for(col=numtracks; col; col--,mmdp++)
+           {   mmdp->a = _mm_read_UBYTE(modfp);
+               mmdp->b = _mm_read_UBYTE(modfp);
+               mmdp->c = _mm_read_UBYTE(modfp);
+           }
+       }
+
+       for(col=0; col<of.numchn; col++)
+       {   of.tracks[track] = MED_Convert0(col);
+           track++;
+       }
+    }
+    return 1;
+}
+
+
+BOOL LoadMMD1Patterns(void)
+{
+    int      t,row,col;
+    UWORD    numtracks,numlines,maxlines=0,track=0;
+    MMD1NOTE *mmdp;
+
+    // first, scan patterns to see how many channels are used
+    for(t=0; t<of.numpat; t++)
+    {  _mm_fseek(modfp,ba[t],SEEK_SET);
+       numtracks = _mm_read_M_UWORD(modfp);
+       numlines  = _mm_read_M_UWORD(modfp);
+
+       _mm_fseek(modfp,sizeof(ULONG),SEEK_CUR);
+       if(numtracks>of.numchn) of.numchn = numtracks;
+       if(numlines>maxlines) maxlines = numlines;
+    }
+
+    of.numtrk = of.numpat*of.numchn;
+    if(!AllocTracks()) return 0;
+    if(!AllocPatterns()) return 0;
+
+    if(!(mmd1pat=(MMD1NOTE*)_mm_calloc(of.numchn*(maxlines+1),sizeof(MMD1NOTE)))) return 0;
+
+    // second read: no more mr. nice guy, really read and convert patterns
+    for(t=0; t<of.numpat; t++)
+    {   _mm_fseek(modfp,ba[t],SEEK_SET);
+        numtracks = _mm_read_M_UWORD(modfp);
+        numlines  = _mm_read_M_UWORD(modfp);
+
+        _mm_fseek(modfp,sizeof(ULONG),SEEK_CUR);
+        of.pattrows[t] = numlines;
+        memset(mmdp=mmd1pat,0,of.numchn*maxlines*sizeof(MMD1NOTE));
+
+        for(row=numlines+1; row; row--)
+        {   for(col=numtracks; col; col--,mmdp++)
+            {   mmdp->a = _mm_read_UBYTE(modfp);
+                mmdp->b = _mm_read_UBYTE(modfp);
+                mmdp->c = _mm_read_UBYTE(modfp);
+                mmdp->d = _mm_read_UBYTE(modfp);
+            }
+        }
+
+        for(col=0;col<of.numchn;col++)
+        {   of.tracks[track]=MED_Convert1(col);
+            track++;
+        }
+    }
+    return 1;
+}
+
+
+
+BOOL MED_Load(void)
+{
+    int        t;
+    ULONG      sa[64];
+    InstrHdr   s;
+    SAMPLE     *q;
+    MMD0sample *mss;
+
+    // try to read module header
+
+    mh->id          = _mm_read_M_ULONG(modfp);
+    mh->modlen      = _mm_read_M_ULONG(modfp);
+    mh->MMD0songP   = _mm_read_M_ULONG(modfp);
+    mh->psecnum     = _mm_read_M_UWORD(modfp);
+    mh->pseq        = _mm_read_M_UWORD(modfp);
+    mh->MMD0BlockPP = _mm_read_M_ULONG(modfp);
+    mh->reserved1   = _mm_read_M_ULONG(modfp);
+    mh->InstrHdrPP  = _mm_read_M_ULONG(modfp);
+    mh->reserved2   = _mm_read_M_ULONG(modfp);
+    mh->MMD0expP    = _mm_read_M_ULONG(modfp);
+    mh->reserved3   = _mm_read_M_ULONG(modfp);
+    mh->pstate      = _mm_read_M_UWORD(modfp);
+    mh->pblock      = _mm_read_M_UWORD(modfp);
+    mh->pline       = _mm_read_M_UWORD(modfp);
+    mh->pseqnum     = _mm_read_M_UWORD(modfp);
+    mh->actplayline = _mm_read_M_SWORD(modfp);
+    mh->counter     = _mm_read_UBYTE(modfp);
+    mh->extra_songs = _mm_read_UBYTE(modfp);
+
+    // Seek to MMD0song struct
+    _mm_fseek(modfp,mh->MMD0songP,SEEK_SET);
+
+
+    // Load the MMD0 Song Header
+
+    mss = ms->sample;     // load the sample data first
+    for(t=63; t; t--, mss++)
+    {   mss->rep        = _mm_read_M_UWORD(modfp);
+        mss->replen     = _mm_read_M_UWORD(modfp);
+        mss->midich     = _mm_read_UBYTE(modfp);
+        mss->midipreset = _mm_read_UBYTE(modfp);
+        mss->svol       = _mm_read_UBYTE(modfp);
+        mss->strans     = _mm_read_SBYTE(modfp);
+    }
+
+    ms->numblocks  = _mm_read_M_UWORD(modfp);
+    ms->songlen    = _mm_read_M_UWORD(modfp);
+    _mm_read_UBYTES(ms->playseq,256,modfp);
+    ms->deftempo   = _mm_read_M_UWORD(modfp);
+    ms->playtransp = _mm_read_SBYTE(modfp);
+    ms->flags      = _mm_read_UBYTE(modfp);
+    ms->flags2     = _mm_read_UBYTE(modfp);
+    ms->tempo2     = _mm_read_UBYTE(modfp);
+    _mm_read_UBYTES(ms->trkvol,16,modfp);
+    ms->mastervol  = _mm_read_UBYTE(modfp);
+    ms->numsamples = _mm_read_UBYTE(modfp);
+
+    // check for a bad header
+    if(feof(modfp))
+    {   _mm_errno = MMERR_LOADING_HEADER;
+        return 0;
+    }
+
+    // seek to and read the samplepointer array
+    _mm_fseek(modfp,mh->InstrHdrPP,SEEK_SET);
+    if(!_mm_read_M_ULONGS(sa,ms->numsamples,modfp))
+    {   _mm_errno = MMERR_LOADING_HEADER;
+        return 0;
+    }
+
+    // alloc and read the blockpointer array
+    if(!(ba=(ULONG *)_mm_calloc(ms->numblocks, sizeof(ULONG)))) return 0;
+    _mm_fseek(modfp,mh->MMD0BlockPP,SEEK_SET);
+    if(!_mm_read_M_ULONGS(ba,ms->numblocks,modfp))
+    {   _mm_errno = MMERR_LOADING_HEADER;
+        return 0;
+    }
+
+
+    // copy song positions
+    if(!AllocPositions(ms->songlen)) return 0;
+    for(t=0; t<ms->songlen; t++)
+       of.positions[t] = ms->playseq[t];
+
+    of.initspeed = 6;
+    of.inittempo = ((UWORD)ms->deftempo*125)/33;
+    of.modtype   = strdup(MED_Version);
+    of.numchn    = 0;                         // will be counted later
+    of.numpat    = ms->numblocks;
+    of.numpos    = ms->songlen;
+    of.numins    = ms->numsamples;
+
+    of.numsmp = of.numins;
+    if(!AllocSamples()) return 0;
+    q = of.samples;
+   
+    for(t=0; t<of.numins; t++)
+    {   _mm_fseek(modfp,sa[t],SEEK_SET);
+        s.length = _mm_read_M_ULONG(modfp);
+        s.type   = _mm_read_M_SWORD(modfp);
+       
+        if(feof(modfp))
+        {   _mm_errno = MMERR_LOADING_SAMPLEINFO;
+            return 0;
+        }
+
+        q->samplename = NULL;
+        q->length    = s.length;
+        q->seekpos   = _mm_ftell(modfp);
+        q->loopstart = ms->sample[t].rep<<1;
+        q->loopend   = q->loopstart+(ms->sample[t].replen<<1);
+        q->flags     = SF_SIGNED;
+        q->speed     = 8363;
+        q->volume    = 64;
+
+        if(ms->sample[t].replen>1) q->flags|=SF_LOOP;
+
+        // don't load sample if length>='MMD0' hah.. hah.. very funny.. NOT!
+        if(q->length >= MMD0_string) q->length = 0;
+
+        q++;
+    }
+
+
+    if(mh->id==MMD0_string)
+    {   if(!LoadMMD0Patterns()) return 0;
+    } else if(mh->id==MMD1_string)
+    {   if(!LoadMMD1Patterns()) return 0;
+    } else
+    {   _mm_errno = MMERR_NOT_A_MODULE;
+        return 0;
+    }
+   
+    return 1;
+}
+
+
+MLOADER load_med =
+{   NULL,
+    "MED",
+    "MED loader v0.1",
+    MED_Init,
+    MED_Test,
+    MED_Load,
+    MED_Cleanup,
+    NULL
+};
+
+