Mercurial > ~darius > hgwebdir.cgi > mikmod
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 +};