#include #include #include #include #include "mloader.h" #include "munitrk.h" typedef struct FARSAMPLE{ char samplename[32]; ULONG length; UBYTE finetune; UBYTE volume; ULONG reppos; ULONG repend; UBYTE type; UBYTE loop; } FARSAMPLE; typedef struct FARHEADER1{ UBYTE id[4]; // file magic char songname[40]; // songname char blah[3]; // 13,10,26 UWORD headerlen; // remaining length of header in bytes UBYTE version; UBYTE onoff[16]; UBYTE edit1[9]; UBYTE speed; UBYTE panning[16]; UBYTE edit2[4]; UWORD stlen; } FARHEADER1; typedef struct FARHEADER2{ UBYTE orders[256]; UBYTE numpat; UBYTE snglen; UBYTE loopto; UWORD patsiz[256]; } FARHEADER2; typedef struct FARNOTE{ UBYTE note,ins,vol,eff; } FARNOTE; char FAR_Version[]="Farandole"; static FARHEADER1 *mh1; static FARHEADER2 *mh2; static FARNOTE *pat; BOOL FAR_Test(void) { char id[4]; rewind(modfp); if(!fread(&id,4,1,modfp)) return 0; return(!strncmp(id,"FARū",4)); } BOOL FAR_Init(void) { mh1=NULL; mh2=NULL; pat=NULL; if(!(mh1=(FARHEADER1 *)MyMalloc(sizeof(FARHEADER1)))) return 0; if(!(mh2=(FARHEADER2 *)MyMalloc(sizeof(FARHEADER2)))) return 0; if(!(pat=(FARNOTE *)MyMalloc(16*256*sizeof(FARNOTE)))) return 0; return 1; } void FAR_Cleanup(void) { if(mh1!=NULL) free(mh1); if(mh2!=NULL) free(mh2); if(pat!=NULL) free(pat); } UBYTE *FAR_ConvertTrack(FARNOTE *n,int rows) { int t; UniReset(); for(t=0;tnote){ UniInstrument(n->ins); UniNote(n->note+23+12); } if(n->vol&0xf){ UniPTEffect(0xc,(n->vol&0xf)<<2); } switch(n->eff>>4){ case 0xf: UniPTEffect(0xf,n->eff&0xf); break; // others not yet implemented } UniNewline(); n+=16; } return UniDup(); } BOOL FAR_Load(void) { int t,u,tracks=0; INSTRUMENT *d; SAMPLE *q; FARSAMPLE s; UBYTE smap[8]; rewind(modfp); // try to read module header (first part) if(!fread(mh1,sizeof(FARHEADER1),1,modfp)){ myerr=ERROR_LOADING_HEADER; return 0; } // printf("Farandole version %d.%d\n",mh1->version>>4,mh1->version&0xf); // init modfile data of.modtype=strdup(FAR_Version); of.songname=DupStr(mh1->songname,40); of.numchn=16; of.initspeed=mh1->speed; of.inittempo=88; for(t=0;t<16;t++) of.panning[t]=mh1->panning[t]<<4; // read songtext into comment field if(!ReadComment(mh1->stlen)) return 0; // try to read module header (second part) if(!fread(mh2,sizeof(FARHEADER2),1,modfp)){ myerr=ERROR_LOADING_HEADER; return 0; } // of.numpat=mh2->numpat; of.numpos=mh2->snglen; memcpy(of.positions,mh2->orders,256); // count number of patterns stored in file of.numpat=0; for(t=0;t<256;t++){ if(mh2->patsiz[t]) if((t+1)>of.numpat) of.numpat=t+1; } of.numtrk=of.numpat*of.numchn; // seek across eventual new data fseek(modfp,mh1->headerlen-(869+mh1->stlen),SEEK_CUR); // printf("%s\n%d patterns\n%d pos\n",of.songname,of.numpat,of.songlength); // alloc track and pattern structures if(!AllocTracks()) return 0; if(!AllocPatterns()) return 0; for(t=0;tpatsiz[t]){ fread(&rows,1,1,modfp); fread(&tempo,1,1,modfp); if(!fread(pat,mh2->patsiz[t]-2,1,modfp)){ myerr=ERROR_LOADING_PATTERN; return 0; }; } of.pattrows[t]=rows+2; for(u=0;u<16;u++){ if(!(of.tracks[tracks++]=FAR_ConvertTrack(&pat[u],rows+2))) return 0; } } // read sample map if(!fread(smap,8,1,modfp)){ myerr=ERROR_LOADING_HEADER; return 0; } // count number of samples used of.numins=0; for(t=0;t<64;t++){ if(smap[t>>3] & (1 << (t&7))) of.numins++; } // alloc sample structs if(!AllocInstruments()) return 0; d=of.instruments; for(t=0;t<64;t++){ if(smap[t>>3] & (1 << (t&7))){ d->numsmp=1; if(!AllocSamples(d)) return 0; q=d->samples; // and load sample info if(fread(&s,sizeof(FARSAMPLE),1,modfp)!=1){ myerr=ERROR_LOADING_SAMPLEINFO; return 0; } d->insname=DupStr(s.samplename,32); q->length=s.length; q->loopstart=s.reppos; q->loopend=s.repend; q->volume=64; q->c2spd=8363; q->flags=SF_SIGNED; if(s.type&1) q->flags|=SF_16BITS; if(s.loop) q->flags|=SF_LOOP; q->seekpos=ftell(modfp); // printf("Sample %d : name %s %ld %ld %ld %ld\n",t,d->samplename,d->length,d->loopstart,d->loopend,d->seekpos); fseek(modfp,q->length,SEEK_CUR); } d++; } return 1; } LOADER farload={ NULL, "FAR", "FAR loader v0.1", FAR_Init, FAR_Test, FAR_Load, FAR_Cleanup };