diff playercode/load_m15.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_m15.c	Fri Jan 23 16:05:08 1998 +0000
@@ -0,0 +1,410 @@
+/*
+
+ Name: LOAD_M15.C
+
+ Description:
+ 15 instrument MOD loader
+ Also supports Ultimate Sound Tracker (old M15 format)
+
+ 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"
+
+/*************************************************************************
+*************************************************************************/
+
+
+typedef struct MSAMPINFO       // sample header as it appears in a module
+{   CHAR  samplename[22];
+    UWORD length;
+    UBYTE finetune;
+    UBYTE volume;
+    UWORD reppos;
+    UWORD replen;
+} MSAMPINFO;
+
+
+typedef struct MODULEHEADER          // verbatim module header
+{   CHAR       songname[20];         // the songname..
+    MSAMPINFO  samples[15];          // all sampleinfo
+    UBYTE      songlength;           // number of patterns used
+    UBYTE      magic1;               // should be 127
+    UBYTE      positions[128];       // which pattern to play at pos
+} MODULEHEADER;
+
+
+typedef struct MODNOTE
+{   UBYTE a,b,c,d;
+} MODNOTE;
+
+
+/*************************************************************************
+*************************************************************************/
+
+static MODULEHEADER *mh = NULL;       // raw as-is module header
+static MODNOTE *patbuf = NULL;
+static BOOL ust_loader = 0;          // if TRUE, load as a ust module.
+static CHAR nulls[3] = {0,0,0};
+
+static BOOL LoadModuleHeader(MODULEHEADER *mh)
+{
+    int t;
+
+    _mm_read_string(mh->songname,20,modfp);
+
+    for(t=0; t<15; t++)
+    {   MSAMPINFO *s = &mh->samples[t];
+        _mm_read_string(s->samplename,22,modfp);
+        s->length   =_mm_read_M_UWORD(modfp);
+        s->finetune =_mm_read_UBYTE(modfp);
+        s->volume   =_mm_read_UBYTE(modfp);
+        s->reppos   =_mm_read_M_UWORD(modfp);
+        s->replen   =_mm_read_M_UWORD(modfp);
+    }
+
+    mh->songlength  =_mm_read_UBYTE(modfp);
+    mh->magic1      =_mm_read_UBYTE(modfp);               // should be 127
+    _mm_read_UBYTES(mh->positions,128,modfp);
+
+    return(!feof(modfp));
+}
+
+
+static int CheckPatternType(int numpat)
+
+// Checks the patterns in the modfile for UST / 15-inst indications.
+// For example, if an effect 3xx is found, it is assumed that the song
+// is 15-inst.  If a 1xx effect has dat greater than 0x20, it is UST.
+//  Returns:  0 indecisive; 1 = UST; 2 = 15-inst
+
+{
+    int   t;
+    UBYTE eff, dat;
+
+    ust_loader = 1;
+
+    for(t=0; t<numpat*(64U*4); t++)
+    {   // Load the pattern into the temp buffer
+        // and convert it
+
+        _mm_read_UBYTE(modfp);      // read note
+        _mm_read_UBYTE(modfp);      // read inst
+        eff = _mm_read_UBYTE(modfp);
+        dat = _mm_read_UBYTE(modfp);
+        
+        if((eff==3) && (dat!=0) || (eff >= 2))   return 2;
+        if(eff==1)
+        {   if(dat > 0x1f) return 1;
+            if(dat < 0x3)  return 2;
+        }
+        if((eff==2) && (dat > 0x1f)) return 1;
+    }
+
+    return 0;
+}
+
+
+BOOL M15_Test(void)
+{
+    int          t, numpat;
+    MODULEHEADER mh;
+
+    ust_loader = 0;
+
+    if(!LoadModuleHeader(&mh)) return 0;
+    if(mh.magic1>127) return 0;
+
+    for(t=0; t<15; t++)
+    {   // all finetunes should be zero
+        if(mh.samples[t].finetune != 0) return 0;
+
+        // all volumes should be <= 64
+        if(mh.samples[t].volume > 64) return 0;
+
+        // all instrument names should begin with s, st-, or a number
+        if(mh.samples[t].samplename[0] == 's')
+        {   if((memcmp(mh.samples[t].samplename,"st-",3) != 0) &&
+               (memcmp(mh.samples[t].samplename,"ST-",3) != 0) &&
+               (memcmp(mh.samples[t].samplename,nulls,3) != 0))
+                ust_loader = 1;
+        } else if((mh.samples[t].samplename[0] < '0') || (mh.samples[t].samplename[0] > '9'))
+            ust_loader = 1;
+
+        if(mh.samples[t].length > 4999)
+        {   ust_loader = 0;
+            if(mh.samples[t].length > 32768) return 0;
+        }
+
+        if(!ust_loader) return 1;
+
+        if(((mh.samples[t].reppos) + mh.samples[t].replen) > (mh.samples[t].length + 10))
+        {   ust_loader = 1;
+            return 1;
+        }
+        
+    }
+
+    for(numpat=0, t=0; t<mh.songlength; t++)
+    {   if(mh.positions[t] > numpat)
+            numpat = mh.positions[t];
+    }
+
+    numpat++;
+    switch(CheckPatternType(numpat))
+    {   case 0:   // indecisive, so check more clues...
+
+        break;
+
+        case 1:  ust_loader = 1;   break;
+        case 2:  ust_loader = 0;   break;
+    }
+ 
+    return 1;
+}
+
+
+BOOL M15_Init(void)
+{
+    if(!(mh=(MODULEHEADER *)_mm_calloc(1,sizeof(MODULEHEADER)))) return 0;
+    return 1;
+}
+
+
+void M15_Cleanup(void)
+{
+    if(mh!=NULL) free(mh);
+    if(patbuf!=NULL) free(patbuf);
+
+    mh = NULL;
+    patbuf = NULL;
+}
+
+
+/*
+Old (amiga) noteinfo:
+
+ _____byte 1_____   byte2_    _____byte 3_____   byte4_
+/                \ /      \  /                \ /      \
+0000          0000-00000000  0000          0000-00000000
+
+Upper four    12 bits for    Lower four    Effect command.
+bits of sam-  note period.   bits of sam-
+ple number.                  ple number.
+
+*/
+
+
+static void M15_ConvertNote(MODNOTE *n)
+{
+    UBYTE instrument,effect,effdat,note;
+    UWORD period;
+
+    // extract the various information from the 4 bytes that
+    // make up a single note
+
+    instrument = (n->a&0x10)|(n->c>>4);
+    period     = (((UWORD)n->a&0xf)<<8)+n->b;
+    effect     = n->c&0xf;
+    effdat     = n->d;
+
+    // Convert the period to a note number
+
+    note=0;
+    if(period != 0)
+    {   for(note=0; note<60; note++)
+            if(period >= npertab[note]) break;
+        note++;
+        if(note==61) note = 0;
+    }
+
+    if(instrument!=0) UniInstrument(instrument-1);
+    if(note!=0) UniNote(note+23);
+
+    // Convert pattern jump from Dec to Hex
+    if(effect == 0xd)
+        effdat = (((effdat&0xf0)>>4)*10)+(effdat&0xf);
+
+    if(ust_loader)
+    {   switch(effect)
+        {   case 0:  break;
+            case 1:
+                UniPTEffect(0,effdat);
+            break;
+
+            case 2:  
+                if(effdat&0xf) UniPTEffect(1,effdat&0xf);
+                if(effdat>>2)  UniPTEffect(2,effdat>>2);
+            break;
+
+            case 3:  break;
+
+            default:
+                UniPTEffect(effect,effdat);
+            break;
+        }
+    } else UniPTEffect(effect,effdat);
+}
+
+
+static UBYTE *M15_ConvertTrack(MODNOTE *n)
+{
+    int t;
+
+    UniReset();
+    for(t=0; t<64; t++)
+    {   M15_ConvertNote(n);
+        UniNewline();
+        n += 4;
+    }
+    return UniDup();
+}
+
+
+
+static BOOL M15_LoadPatterns(void)
+//  Loads all patterns of a modfile and converts them into the
+//  3 byte format.
+{
+    int t,s,tracks=0;
+
+    if(!AllocPatterns()) return 0;
+    if(!AllocTracks()) return 0;
+
+    // Allocate temporary buffer for loading
+    // and converting the patterns
+
+    if(!(patbuf=(MODNOTE *)_mm_calloc(64U*4,sizeof(MODNOTE)))) return 0;
+
+    for(t=0; t<of.numpat; t++)
+    {   // Load the pattern into the temp buffer
+        // and convert it
+
+        for(s=0; s<(64U*4); s++)
+        {   patbuf[s].a=_mm_read_UBYTE(modfp);
+            patbuf[s].b=_mm_read_UBYTE(modfp);
+            patbuf[s].c=_mm_read_UBYTE(modfp);
+            patbuf[s].d=_mm_read_UBYTE(modfp);
+        }
+
+        for(s=0; s<4; s++)
+            if(!(of.tracks[tracks++]=M15_ConvertTrack(patbuf+s))) return 0;
+    }
+
+    return 1;
+}
+
+
+BOOL M15_Load(void)
+{
+    int        t;
+    SAMPLE     *q;
+    MSAMPINFO  *s;           // old module sampleinfo
+
+    // try to read module header
+
+    if(!LoadModuleHeader(mh))
+    {   _mm_errno = MMERR_LOADING_HEADER;
+        return 0;
+    }
+
+
+    if(ust_loader)
+        of.modtype = strdup("Ultimate Soundtracker");
+    else
+        of.modtype = strdup("Soundtracker");
+
+    // set module variables
+
+    of.initspeed = 6;
+    of.inittempo = 125;
+    of.numchn    = 4;                           // get number of channels
+    of.songname  = DupStr(mh->songname,20);     // make a cstr of songname
+    of.numpos    = mh->songlength;              // copy the songlength
+
+    if(!AllocPositions(of.numpos)) return 0;
+    for(t=0; t<of.numpos; t++)
+        of.positions[t] = mh->positions[t];
+
+
+    // Count the number of patterns
+
+    of.numpat = 0;
+
+    for(t=0; t<of.numpos; t++)
+    {   if(of.positions[t] > of.numpat)
+            of.numpat = of.positions[t];
+    }
+    of.numpat++;
+    of.numtrk = of.numpat*4;
+
+    // Finally, init the sampleinfo structures
+
+    of.numins = of.numsmp = 15;
+    if(!AllocSamples()) return 0;
+
+    s = mh->samples;          // init source pointer
+    q = of.samples;
+    
+    for(t=0; t<of.numins; t++)
+    {   // convert the samplename
+        q->samplename = DupStr(s->samplename,22);
+
+        // init the sampleinfo variables and
+        // convert the size pointers to longword format
+
+        q->speed     = finetune[s->finetune&0xf];
+        q->volume    = s->volume;
+        if(ust_loader)
+            q->loopstart = s->reppos;
+        else
+            q->loopstart = s->reppos<<1;
+        q->loopend   = q->loopstart+(s->replen<<1);
+        q->length    = s->length<<1;
+
+        q->flags = SF_SIGNED | SF_UST_LOOP;
+        if(s->replen>1) q->flags |= SF_LOOP;
+
+        // fix replen if repend>length
+
+        if(q->loopend>q->length) q->loopend = q->length;
+
+        s++;    // point to next source sampleinfo
+        q++;
+    }
+
+    if(!M15_LoadPatterns()) return 0;
+
+    ust_loader = 0;
+    return 1;
+}
+
+
+CHAR *M15_LoadTitle(void)
+{
+   CHAR s[20];
+
+   fseek(modfp,0,SEEK_SET);
+   if(!fread(s,22,1,modfp)) return NULL;
+
+   return(DupStr(s,20));
+}
+
+
+MLOADER load_m15 =
+{   NULL,
+    "15-instrument module",
+    "Portable MOD-15 loader v0.1",
+    M15_Init,
+    M15_Test,
+    M15_Load,
+    M15_Cleanup,
+    M15_LoadTitle
+};