home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <malloc.h>
- #include "mloader.h"
- #include "munitrk.h"
-
- /**************************************************************************
- **************************************************************************/
-
-
- typedef struct XMHEADER{
- char id[17]; // ID text: 'Extended module: '
- char songname[21]; // Module name, padded with zeroes and 0x1a at the end
- char trackername[20]; // Tracker name
- UWORD version; // (word) Version number, hi-byte major and low-byte minor
- ULONG headersize; // Header size
- UWORD songlength; // (word) Song length (in patten order table)
- UWORD restart; // (word) Restart position
- UWORD numchn; // (word) Number of channels (2,4,6,8,10,...,32)
- UWORD numpat; // (word) Number of patterns (max 256)
- UWORD numins; // (word) Number of instruments (max 128)
- UWORD flags; // (word) Flags: bit 0: 0 = Amiga frequency table (see below) 1 = Linear frequency table
- UWORD tempo; // (word) Default tempo
- UWORD bpm; // (word) Default BPM
- UBYTE orders[256]; // (byte) Pattern order table
- } XMHEADER;
-
-
- typedef struct XMINSTHEADER{
- ULONG size; // (dword) Instrument size
- char name[22]; // (char) Instrument name
- UBYTE type; // (byte) Instrument type (always 0)
- UWORD numsmp; // (word) Number of samples in instrument
- ULONG ssize; //
- } XMINSTHEADER;
-
-
- typedef struct XMPATCHHEADER{
- UBYTE what[96]; // (byte) Sample number for all notes
- UBYTE volenv[48]; // (byte) Points for volume envelope
- UBYTE panenv[48]; // (byte) Points for panning envelope
- UBYTE volpts; // (byte) Number of volume points
- UBYTE panpts; // (byte) Number of panning points
- UBYTE volsus; // (byte) Volume sustain point
- UBYTE volbeg; // (byte) Volume loop start point
- UBYTE volend; // (byte) Volume loop end point
- UBYTE pansus; // (byte) Panning sustain point
- UBYTE panbeg; // (byte) Panning loop start point
- UBYTE panend; // (byte) Panning loop end point
- UBYTE volflg; // (byte) Volume type: bit 0: On; 1: Sustain; 2: Loop
- UBYTE panflg; // (byte) Panning type: bit 0: On; 1: Sustain; 2: Loop
- UBYTE vibflg; // (byte) Vibrato type
- UBYTE vibsweep; // (byte) Vibrato sweep
- UBYTE vibdepth; // (byte) Vibrato depth
- UBYTE vibrate; // (byte) Vibrato rate
- UWORD volfade; // (word) Volume fadeout
- UWORD reserved[11]; // (word) Reserved
- } XMPATCHHEADER;
-
-
- typedef struct XMWAVHEADER{
- ULONG length; // (dword) Sample length
- ULONG loopstart; // (dword) Sample loop start
- ULONG looplength; // (dword) Sample loop length
- UBYTE volume; // (byte) Volume
- BYTE finetune; // (byte) Finetune (signed byte -128..+127)
- UBYTE type; // (byte) Type: Bit 0-1: 0 = No loop, 1 = Forward loop,
- // 2 = Ping-pong loop;
- // 4: 16-bit sampledata
- UBYTE panning; // (byte) Panning (0-255)
- BYTE relnote; // (byte) Relative note number (signed byte)
- UBYTE reserved; // (byte) Reserved
- char samplename[22]; // (char) Sample name
- } XMWAVHEADER;
-
-
- typedef struct XMPATHEADER{
- ULONG size; // (dword) Pattern header length
- UBYTE packing; // (byte) Packing type (always 0)
- UWORD numrows; // (word) Number of rows in pattern (1..256)
- UWORD packsize; // (word) Packed patterndata size
- } XMPATHEADER;
-
- typedef struct MTMNOTE{
- UBYTE a,b,c;
- } MTMNOTE;
-
-
- typedef struct XMNOTE{
- UBYTE note,ins,vol,eff,dat;
- }XMNOTE;
-
- XMNOTE *xmpat;
-
- /**************************************************************************
- **************************************************************************/
-
-
-
- static XMHEADER *mh;
-
- char XM_Version[]="XM";
-
-
-
- BOOL XM_Test(void)
- {
- char id[17];
- rewind(modfp);
- if(!fread(id,17,1,modfp)) return 0;
- if(!memcmp(id,"Extended Module: ",17)) return 1;
- return 0;
- }
-
-
- BOOL XM_Init(void)
- {
- mh=NULL;
- if(!(mh=MyCalloc(1,sizeof(XMHEADER)))) return 0;
- return 1;
- }
-
-
- void XM_Cleanup(void)
- {
- if(mh!=NULL) free(mh);
- }
-
-
- void XM_ReadNote(XMNOTE *n)
- {
- UBYTE cmp;
- memset(n,0,sizeof(XMNOTE));
-
- cmp=fgetc(modfp);
-
- if(cmp&0x80){
- if(cmp&1) n->note=fgetc(modfp);
- if(cmp&2) n->ins=fgetc(modfp);
- if(cmp&4) n->vol=fgetc(modfp);
- if(cmp&8) n->eff=fgetc(modfp);
- if(cmp&16) n->dat=fgetc(modfp);
- }
- else{
- n->note=cmp;
- n->ins=fgetc(modfp);
- n->vol=fgetc(modfp);
- n->eff=fgetc(modfp);
- n->dat=fgetc(modfp);
- }
- }
-
-
- UBYTE *XM_Convert(XMNOTE *xmtrack,UWORD rows)
- {
- int t;
- UBYTE note,ins,vol,eff,dat;
-
- UniReset();
-
- for(t=0;t<rows;t++){
-
- note=xmtrack->note;
- ins=xmtrack->ins;
- vol=xmtrack->vol;
- eff=xmtrack->eff;
- dat=xmtrack->dat;
-
- if(note!=0){
- UniNote(note-1);
- }
-
- if(ins!=0){
- UniInstrument(ins-1);
- }
-
- // printf("Vol:%d\n",vol);
-
- switch(vol>>4){
-
- case 0x6: // volslide down
- if(vol&0xf){
- UniWrite(UNI_XMEFFECTA);
- UniWrite(vol&0xf);
- }
- break;
-
- case 0x7: // volslide up
- if(vol&0xf){
- UniWrite(UNI_XMEFFECTA);
- UniWrite(vol<<4);
- }
- break;
-
- /* volume-row fine volume slide is compatible with protracker
- EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as
- opposed to 'take the last sliding value'.
- */
-
- case 0x8: // finevol down
- UniPTEffect(0xe,0xb0 | (vol&0xf));
- break;
-
- case 0x9: // finevol up
- UniPTEffect(0xe,0xa0 | (vol&0xf));
- break;
-
- case 0xa: // set vibrato speed
- UniPTEffect(0x4,vol<<4);
- break;
-
- case 0xb: // vibrato
- UniPTEffect(0x4,vol&0xf);
- break;
-
- case 0xc: // set panning
- UniPTEffect(0x8,vol<<4);
- break;
-
- case 0xd: // panning slide left
- // only slide when data nibble not zero:
-
- if(vol&0xf){
- UniWrite(UNI_XMEFFECTP);
- UniWrite(vol&0xf);
- }
- break;
-
- case 0xe: // panning slide right
- // only slide when data nibble not zero:
-
- if(vol&0xf){
- UniWrite(UNI_XMEFFECTP);
- UniWrite(vol<<4);
- }
- break;
-
- case 0xf: // tone porta
- UniPTEffect(0x3,vol<<4);
- break;
-
- default:
- if(vol>=0x10 && vol<=0x50){
- UniPTEffect(0xc,vol-0x10);
- }
- }
-
- // if(eff>0xf) printf("Effect %d",eff);
-
- switch(eff){
-
- case 'G'-55: // G - set global volume
- break;
-
- case 'H'-55: // H - global volume slide
- break;
-
- case 'K'-55: // K - keyoff
- UniNote(96);
- break;
-
- case 'L'-55: // L - set envelope position
- break;
-
- case 'P'-55: // P - panning slide
- UniWrite(UNI_XMEFFECTP);
- UniWrite(dat);
- break;
-
- case 'R'-55: // R - multi retrig note
- UniWrite(UNI_S3MEFFECTQ);
- UniWrite(dat);
- break;
-
- case 'T'-55:
- UniPTEffect(0x6,dat);
- break;
-
- case 'X'-55:
- if((dat>>4)==1){ // X1 extra fine porta up
-
-
- }
- else{ // X2 extra fine porta down
-
- }
- break;
-
- default:
- if(eff==0xa){
- UniWrite(UNI_XMEFFECTA);
- UniWrite(dat);
- }
- else if(eff<=0xf) UniPTEffect(eff,dat);
- break;
- }
-
- UniNewline();
- xmtrack++;
- }
- return UniDup();
- }
-
-
-
- BOOL XM_Load(void)
- {
- INSTRUMENT *d;
- SAMPLE *q;
- int t,u,v,p,numtrk;
- long next;
-
- rewind(modfp);
-
- // try to read module header
-
- if(!fread(mh,sizeof(XMHEADER),1,modfp)){
- myerr=ERROR_LOADING_HEADER;
- return 0;
- }
-
- /* set module variables */
-
- of.initspeed=mh->tempo;
- of.inittempo=mh->bpm;
- of.modtype=DupStr(mh->trackername,20);
- of.numchn=mh->numchn;
- of.numpat=mh->numpat;
- of.numtrk=(UWORD)of.numpat*of.numchn; // get number of channels
- of.songname=DupStr(mh->songname,20); // make a cstr of songname
- of.numpos=mh->songlength; // copy the songlength
- of.numins=mh->numins;
- of.flags|=UF_XMPERIODS;
- if(mh->flags&1) of.flags|=UF_LINEAR;
-
- memcpy(of.positions,mh->orders,256);
-
- of.numpat=0;
- for(t=0;t<of.numpos;t++){
- if(of.positions[t]>of.numpat) of.numpat=of.positions[t];
- }
- of.numpat++;
-
- /* printf("Modtype :%s\n",of.modtype);
- printf("Version :%x\n",mh->version);
- printf("Song :%s\n",of.songname);
- printf("Speed :%d,%d\n",of.initspeed,of.inittempo);
- printf("Channels:%d\n",of.numchn);
- printf("Numins :%d\n",mh->numins);
- */
- if(!AllocTracks()) return 0;
- if(!AllocPatterns()) return 0;
-
- numtrk=0;
- for(t=0;t<mh->numpat;t++){
- XMPATHEADER ph;
-
- // printf("Reading pattern %d\n",t);
-
- fread(&ph,sizeof(XMPATHEADER),1,modfp);
-
-
- // printf("headln: %ld\n",ph.size);
- // printf("numrows: %d\n",ph.numrows);
- // printf("packsize:%d\n",ph.packsize);
-
- of.pattrows[t]=ph.numrows;
-
- /*
- Gr8.. when packsize is 0, don't try to load a pattern.. it's empty.
- This bug was discovered thanks to Khyron's module..
- */
-
- if(!(xmpat=MyCalloc(ph.numrows*of.numchn,sizeof(XMNOTE)))) return 0;
-
- if(ph.packsize>0){
- for(u=0;u<ph.numrows;u++){
- for(v=0;v<of.numchn;v++){
- XM_ReadNote(&xmpat[(v*ph.numrows)+u]);
- }
- }
- }
-
- for(v=0;v<of.numchn;v++){
- of.tracks[numtrk++]=XM_Convert(&xmpat[v*ph.numrows],ph.numrows);
- }
-
- free(xmpat);
- }
-
- if(!AllocInstruments()) return 0;
-
- d=of.instruments;
-
- for(t=0;t<of.numins;t++){
- XMINSTHEADER ih;
-
- // printf("Reading instrument %d\n",t);
-
- fread(&ih,sizeof(XMINSTHEADER),1,modfp);
-
- /* printf("Size: %ld\n",ih.size);
- printf("Name: %22.22s\n",ih.name);
- printf("Samples:%d\n",ih.numsmp);
- printf("sampleheadersize:%ld\n",ih.ssize);
- */
- d->insname=DupStr(ih.name,22);
- d->numsmp=ih.numsmp;
-
- if(!AllocSamples(d)) return 0;
-
- if(ih.numsmp>0){
- XMPATCHHEADER pth;
- XMWAVHEADER wh;
-
- fread(&pth,sizeof(XMPATCHHEADER),1,modfp);
-
- memcpy(d->samplenumber,pth.what,96);
-
- d->volfade=pth.volfade;
-
- // printf("Volfade %x\n",d->volfade);
-
- memcpy(d->volenv,pth.volenv,48);
- d->volflg=pth.volflg;
- d->volsus=pth.volsus;
- d->volbeg=pth.volbeg;
- d->volend=pth.volend;
- d->volpts=pth.volpts;
-
- /* printf("volume points : %d\n"
- "volflg : %d\n"
- "volbeg : %d\n"
- "volend : %d\n"
- "volsus : %d\n",
- d->volpts,
- d->volflg,
- d->volbeg,
- d->volend,
- d->volsus);
- */
- // scale volume envelope:
-
- for(p=0;p<d->volpts;p++){
- d->volenv[p].val<<=2;
- // printf("%d,%d,",d->volenv[p].pos,d->volenv[p].val);
- }
-
- memcpy(d->panenv,pth.panenv,48);
- d->panflg=pth.panflg;
- d->pansus=pth.pansus;
- d->panbeg=pth.panbeg;
- d->panend=pth.panend;
- d->panpts=pth.panpts;
-
- /* printf("Panning points : %d\n"
- "panflg : %d\n"
- "panbeg : %d\n"
- "panend : %d\n"
- "pansus : %d\n",
- d->panpts,
- d->panflg,
- d->panbeg,
- d->panend,
- d->pansus);
- */
- // scale panning envelope:
-
- for(p=0;p<d->panpts;p++){
- d->panenv[p].val<<=2;
- // printf("%d,%d,",d->panenv[p].pos,d->panenv[p].val);
- }
-
- // for(u=0;u<256;u++){
- // printf("%2.2x ",fgetc(modfp));
- // }
-
- next=0;
-
- for(u=0;u<ih.numsmp;u++){
- q=&d->samples[u];
-
- fread(&wh,sizeof(XMWAVHEADER),1,modfp);
- // printf("wav %d:%22.22s\n",u,wh.samplename);
-
- q->samplename =DupStr(wh.samplename,22);
- q->length =wh.length;
- q->loopstart =wh.loopstart;
- q->loopend =wh.loopstart+wh.looplength;
- q->volume =wh.volume;
- q->c2spd =wh.finetune+128;
- q->transpose =wh.relnote;
- q->panning =wh.panning;
- q->seekpos =next;
-
- if(wh.type&0x10){
- q->length>>=1;
- q->loopstart>>=1;
- q->loopend>>=1;
- }
-
- next+=wh.length;
-
- // printf("Type %u\n",wh.type);
- // printf("Trans %d\n",wh.relnote);
-
- q->flags|=SF_OWNPAN;
- if(wh.type&0x3) q->flags|=SF_LOOP;
- if(wh.type&0x2) q->flags|=SF_BIDI;
-
- if(wh.type&0x10) q->flags|=SF_16BITS;
- q->flags|=SF_DELTA;
- q->flags|=SF_SIGNED;
- }
-
- for(u=0;u<ih.numsmp;u++) d->samples[u].seekpos+=ftell(modfp);
-
- fseek(modfp,next,SEEK_CUR);
- }
-
- d++;
- }
-
-
- return 1;
- }
-
-
-
- LOADER xmload={
- NULL,
- "XM",
- "XM loader v0.3 - for your ears only / MikMak",
- XM_Init,
- XM_Test,
- XM_Load,
- XM_Cleanup
- };
-
-