#include #include #include #include #include "mloader.h" #include "munitrk.h" /************************************************************************* *************************************************************************/ typedef struct MSAMPINFO{ // sample header as it appears in a module UBYTE samplename[22]; UWORD length; UBYTE finetune; UBYTE volume; UWORD reppos; UWORD replen; } MSAMPINFO; typedef struct MODULEHEADER{ // verbatim module header UBYTE songname[20]; // the songname.. MSAMPINFO samples[31]; // all sampleinfo UBYTE songlength; // number of patterns used UBYTE magic1; // should be 127 UBYTE positions[128]; // which pattern to play at pos UBYTE magic2[4]; // string "M.K." or "FLT4" or "FLT8" } MODULEHEADER; typedef struct MODTYPE{ // struct to identify type of module char id[4]; UBYTE channels; char *name; } MODTYPE; typedef struct MODNOTE{ UBYTE a,b,c,d; } MODNOTE; /************************************************************************* *************************************************************************/ char protracker[]="Protracker"; char startracker[]="Startracker"; char fasttracker[]="Fasttracker"; char ins15tracker[]="15-instrument"; char oktalyzer[]="Oktalyzer"; char taketracker[]="TakeTracker"; MODTYPE modtypes[]={ "M.K.",4,protracker, // protracker 4 channel "M!K!",4,protracker, // protracker 4 channel "FLT4",4,startracker, // startracker 4 channel "4CHN",4,fasttracker, // fasttracker 4 channel "6CHN",6,fasttracker, // fasttracker 6 channel "8CHN",8,fasttracker, // fasttracker 8 channel "CD81",8,oktalyzer, // atari oktalyzer 8 channel "OKTA",8,oktalyzer, // atari oktalyzer 8 channel "16CN",16,taketracker, // taketracker 16 channel "32CN",32,taketracker, // taketracker 32 channel " ",4,ins15tracker // 15-instrument 4 channel }; static MODULEHEADER *mh; // raw as-is module header static MODNOTE *patbuf; BOOL MOD_Test(void) { int t; char id[4]; fseek(modfp,sizeof(MODULEHEADER)-4,SEEK_SET); if(!fread(id,4,1,modfp)) return 0; // find out which ID string for(t=0;t<10;t++){ if(!memcmp(id,modtypes[t].id,4)) return 1; } return 0; } BOOL MOD_Init(void) { patbuf=NULL; if(!(mh=MyCalloc(1,sizeof(MODULEHEADER)))) return 0; return 1; } void MOD_Cleanup(void) { if(mh!=NULL) free(mh); if(patbuf!=NULL) free(patbuf); } /* 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. */ UWORD npertab[60]={ // -> Tuning 0 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906, 856,808,762,720,678,640,604,570,538,508,480,453, 428,404,381,360,339,320,302,285,269,254,240,226, 214,202,190,180,170,160,151,143,135,127,120,113, 107,101,95,90,85,80,75,71,67,63,60,56 }; void 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); } UniPTEffect(effect,effdat); } UWORD rword(UWORD p) /* Motorola word -> intel word */ { return( ((p&0x00ff)<<8) | ((p&0xff00)>>8) ); } void cword(UWORD *p) { *p=rword(*p); } UBYTE *ConvertTrack(MODNOTE *n) { int t; UniReset(); for(t=0;t<64;t++){ ConvertNote(n); UniNewline(); n+=of.numchn; } return UniDup(); } BOOL ML_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=MyCalloc(64U*of.numchn,sizeof(MODNOTE)))) return 0; for(t=0;tmagic2,modtypes[modtype].id,4)) break; } if(modtype==10){ // unknown modtype myerr=ERROR_NOT_A_MODULE; return 0; } // sample info to intel format for(t=0;t<31;t++){ cword(&mh->samples[t].length); cword(&mh->samples[t].reppos); cword(&mh->samples[t].replen); } /* set module variables */ of.initspeed=6; of.inittempo=125; of.numchn=modtypes[modtype].channels; // get number of channels of.modtype=strdup(modtypes[modtype].name); // get ascii type of mod of.songname=DupStr(mh->songname,20); // make a cstr of songname of.numpos=mh->songlength; // copy the songlength memcpy(of.positions,mh->positions,128); // copy the position array /* Count the number of patterns */ of.numpat=0; for(t=0;t<128;t++){ // <-- BUGFIX... have to check ALL positions if(of.positions[t] > of.numpat){ of.numpat=of.positions[t]; } } of.numpat++; of.numtrk=of.numpat*of.numchn; // Finally, init the sampleinfo structures of.numins=31; if(!AllocInstruments()) return 0; s=mh->samples; // init source pointer d=of.instruments; // init dest pointer for(t=0;tnumsmp=1; if(!AllocSamples(d)) return 0; q=d->samples; // convert the samplename d->insname=DupStr(s->samplename,22); /* init the sampleinfo variables and convert the size pointers to longword format */ q->c2spd=finetune[s->finetune&0xf]; q->volume=s->volume; q->loopstart=s->reppos<<1; q->loopend=q->loopstart+(s->replen<<1); q->length=s->length<<1; q->seekpos=0; q->flags=SF_SIGNED; 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 d++; // point to next destiny sampleinfo } if(!ML_LoadPatterns()) return 0; return 1; } LOADER modload={ NULL, "Standard module", "MOD loader v0.11", MOD_Init, MOD_Test, MOD_Load, MOD_Cleanup };