Mercurial > ~darius > hgwebdir.cgi > mikmod
diff playercode/load_dsm.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_dsm.c Fri Jan 23 16:05:08 1998 +0000 @@ -0,0 +1,314 @@ +/* + + Name: LOAD_DSM.C + + Description: + DSIK Internal Format (DSM) 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" + + +typedef struct DSMNOTE +{ UBYTE note,ins,vol,cmd,inf; +} DSMNOTE; + + +typedef struct DSMINST +{ CHAR filename[13]; + UWORD flags; + UBYTE volume; + ULONG length; + ULONG loopstart; + ULONG loopend; + ULONG reserved1; + UWORD c2spd; + UWORD reserved2; + CHAR samplename[28]; +} DSMINST; + + +typedef struct DSMSONG +{ CHAR songname[28]; + UWORD reserved1; + UWORD flags; + ULONG reserved2; + UWORD numord; + UWORD numsmp; + UWORD numpat; + UWORD numtrk; + UBYTE globalvol; + UBYTE mastervol; + UBYTE speed; + UBYTE bpm; + UBYTE panpos[16]; + UBYTE orders[128]; +} DSMSONG; + + + +static CHAR *SONGID = "SONG"; +static CHAR *INSTID = "INST"; +static CHAR *PATTID = "PATT"; + + +static UBYTE blockid[4]; +static ULONG blockln; +static ULONG blocklp; +static DSMSONG *mh = NULL; +static DSMNOTE *dsmbuf = NULL; + +static CHAR DSM_Version[] = "DSIK DSM-format"; + + +BOOL DSM_Test(void) +{ + UBYTE id[12]; + + if(_mm_read_UBYTES((UBYTE *)id,12,modfp)) return 0; + if(!memcmp(id,"RIFF",4) && !memcmp(&id[8],"DSMF",4)) return 1; + + return 0; +} + + +BOOL DSM_Init(void) +{ + if(!(dsmbuf=(DSMNOTE *)_mm_malloc(16*64*sizeof(DSMNOTE)))) return 0; + if(!(mh=(DSMSONG *)_mm_calloc(1,sizeof(DSMSONG)))) return 0; + return 1; +} + + +void DSM_Cleanup(void) +{ + if(dsmbuf!=NULL) free(dsmbuf); + if(mh!=NULL) free(mh); + + dsmbuf = NULL; + mh = NULL; +} + + +BOOL GetBlockHeader(void) +{ + // make sure we're at the right position for reading the + // next riff block, no matter how many bytes read + + _mm_fseek(modfp, blocklp+blockln, SEEK_SET); + + while(1) + { _mm_read_UBYTES(blockid,4,modfp); + blockln = _mm_read_I_ULONG(modfp); + if(feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + if(memcmp(blockid,SONGID,4) && memcmp(blockid,INSTID,4) && memcmp(blockid,PATTID,4)) + { //printf("Skipping unknown block type %4.4s\n",&blockid); + _mm_fseek(modfp, blockln, SEEK_CUR); + } else break; + } + + blocklp = _mm_ftell(modfp); + return 1; +} + + +BOOL DSM_ReadPattern(void) +{ + int row=0,flag; + DSMNOTE *n; + + // clear pattern data + memset(dsmbuf,255,16*64*sizeof(DSMNOTE)); + _mm_read_UBYTE(modfp); + _mm_read_UBYTE(modfp); + + while(row<64) + { flag = _mm_read_UBYTE(modfp); + if(feof(modfp)) + { _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + if(flag) + { n = &dsmbuf[((flag&0xf)*64)+row]; + if(flag&0x80) n->note = _mm_read_UBYTE(modfp); + if(flag&0x40) n->ins = _mm_read_UBYTE(modfp); + if(flag&0x20) n->vol = _mm_read_UBYTE(modfp); + if(flag&0x10) + { n->cmd = _mm_read_UBYTE(modfp); + n->inf = _mm_read_UBYTE(modfp); + } + } else row++; + } + return 1; +} + + +UBYTE *DSM_ConvertTrack(DSMNOTE *tr) +{ + int t; + UBYTE note,ins,vol,cmd,inf; + + UniReset(); + for(t=0; t<64; t++) + { note = tr[t].note; + ins = tr[t].ins; + vol = tr[t].vol; + cmd = tr[t].cmd; + inf = tr[t].inf; + + if(ins!=0 && ins!=255) UniInstrument(ins-1); + if(note!=255) UniNote(note-1); // <- normal note + if(vol<65) UniPTEffect(0xc,vol); + + if(cmd!=255) + { if(cmd==0x8) + { if(inf<=0x80) + { inf = (inf<0x80) ? inf<<1 : 255; + UniPTEffect(cmd,inf); + } + } else if(cmd==0xb) + { if(inf<=0x7f) UniPTEffect(cmd,inf); + } else + { // Convert pattern jump from Dec to Hex + if(cmd == 0xd) + inf = (((inf&0xf0)>>4)*10)+(inf&0xf); + UniPTEffect(cmd,inf); + } + } + UniNewline(); + } + return UniDup(); +} + + +BOOL DSM_Load(void) +{ + int t; + DSMINST s; + SAMPLE *q; + int cursmp = 0, curpat = 0, track = 0; + + blocklp = 0; + blockln = 12; + + if(!GetBlockHeader()) return 0; + if(memcmp(blockid,SONGID,4)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + _mm_read_UBYTES(mh->songname,28,modfp); + mh->reserved1 = _mm_read_I_UWORD(modfp); + mh->flags = _mm_read_I_UWORD(modfp); + mh->reserved2 = _mm_read_I_ULONG(modfp); + mh->numord = _mm_read_I_UWORD(modfp); + mh->numsmp = _mm_read_I_UWORD(modfp); + mh->numpat = _mm_read_I_UWORD(modfp); + mh->numtrk = _mm_read_I_UWORD(modfp); + mh->globalvol = _mm_read_UBYTE(modfp); + mh->mastervol = _mm_read_UBYTE(modfp); + mh->speed = _mm_read_UBYTE(modfp); + mh->bpm = _mm_read_UBYTE(modfp); + _mm_read_UBYTES(mh->panpos,16,modfp); + _mm_read_UBYTES(mh->orders,128,modfp); + + // set module variables + of.initspeed = mh->speed; + of.inittempo = mh->bpm; + of.modtype = strdup(DSM_Version); + of.numchn = mh->numtrk; + of.numpat = mh->numpat; + of.numtrk = of.numchn*of.numpat; + of.songname = DupStr(mh->songname,28); // make a cstr of songname + + for(t=0; t<16; t++) + of.panning[t] = mh->panpos[t]<0x80 ? (mh->panpos[t]<<1) : 255; + + if(!AllocPositions(mh->numord)) return 0; + of.numpos = 0; + for(t=0; t<mh->numord; t++) + { of.positions[of.numpos] = mh->orders[t]; + if(mh->orders[t]<254) of.numpos++; + } + + of.numins = of.numsmp = mh->numsmp; + + if(!AllocSamples()) return 0; + if(!AllocTracks()) return 0; + if(!AllocPatterns()) return 0; + + while(cursmp<of.numins || curpat<of.numpat) + { if(!GetBlockHeader()) return 0; + if(!memcmp(blockid,INSTID,4) && cursmp<of.numins) + { q = &of.samples[cursmp]; + + // try to read sample info + _mm_read_UBYTES(s.filename,13,modfp); + s.flags = _mm_read_I_UWORD(modfp); + s.volume = _mm_read_UBYTE(modfp); + s.length = _mm_read_I_ULONG(modfp); + s.loopstart = _mm_read_I_ULONG(modfp); + s.loopend = _mm_read_I_ULONG(modfp); + s.reserved1 = _mm_read_I_ULONG(modfp); + s.c2spd = _mm_read_I_UWORD(modfp); + s.reserved2 = _mm_read_I_UWORD(modfp); + _mm_read_UBYTES(s.samplename,28,modfp); + + q->samplename= DupStr(s.samplename,28); + q->seekpos = _mm_ftell(modfp); + q->speed = s.c2spd; + q->length = s.length; + q->loopstart = s.loopstart; + q->loopend = s.loopend; + q->volume = s.volume; + + if(s.flags&1) q->flags|=SF_LOOP; + if(s.flags&2) q->flags|=SF_SIGNED; + cursmp++; + } else if(!memcmp(blockid,PATTID,4) && curpat<of.numpat) + { DSM_ReadPattern(); + for(t=0; t<of.numchn; t++) + if(!(of.tracks[track++] = DSM_ConvertTrack(&dsmbuf[t*64]))) return 0; + curpat++; + } + } + + return 1; +} + + +CHAR *DSM_LoadTitle(void) +{ + CHAR s[28]; + + _mm_fseek(modfp,12,SEEK_SET); + if(!fread(s,28,1,modfp)) return NULL; + + return(DupStr(s,28)); +} + + +MLOADER load_dsm = +{ NULL, + "DSM", + "Portable DSM loader v0.1", + DSM_Init, + DSM_Test, + DSM_Load, + DSM_Cleanup, + DSM_LoadTitle +}; +