Mercurial > ~darius > hgwebdir.cgi > mikmod
view playercode/load_med.c @ 11:d5cb2cfc8eca
Initial revision
author | darius |
---|---|
date | Fri, 23 Jan 1998 16:05:11 +0000 |
parents | 5d614bcc4287 |
children |
line wrap: on
line source
/* 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 };