Mercurial > ~darius > hgwebdir.cgi > mikmod
view playercode/load_it.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_IT.C Description: ImpulseTracker (IT) module loader Portability: All systems - all compilers (hopefully) Copyright 1997 by Jake Stine and Divine Entertainment 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 ITNOTE { UBYTE note,ins,volpan,cmd,inf; } ITNOTE; UBYTE *IT_ConvertTrack(ITNOTE *tr,UWORD numrows); // Raw IT header struct: typedef struct ITHEADER { CHAR songname[26]; UBYTE blank01[2]; UWORD ordnum; UWORD insnum; UWORD smpnum; UWORD patnum; UWORD cwt; // Created with tracker (y.xx = 0x0yxx) UWORD cmwt; // Compatable with tracker ver > than val. UWORD flags; UWORD special; // bit 0 set = song message attached UBYTE globvol; UBYTE mixvol; // mixing volume [ignored] UBYTE initspeed; UBYTE inittempo; UBYTE pansep; // panning separation between channels UBYTE zerobyte; UWORD msglength; ULONG msgoffset; UBYTE blank02[4]; UBYTE pantable[64]; UBYTE voltable[64]; } ITHEADER; // Raw IT sampleinfo struct: typedef struct ITSAMPLE { CHAR filename[12]; UBYTE zerobyte; UBYTE globvol; UBYTE flag; UBYTE volume; UBYTE panning; CHAR sampname[28]; UWORD convert; // sample conversion flag ULONG length; ULONG loopbeg; ULONG loopend; ULONG c5spd; ULONG susbegin; ULONG susend; ULONG sampoffset; UBYTE vibspeed; UBYTE vibdepth; UBYTE vibrate; UBYTE vibwave; // 0 = sine; 1 = rampdown; 2 = square; 3 = random (speed ignored) UBYTE noteindex; // for converting c5spd to finetune } ITSAMPLE; typedef struct ITINSTHEADER { ULONG size; // (dword) Instrument size CHAR filename[12]; // (char) Instrument filename UBYTE zerobyte; // (byte) Instrument type (always 0) UBYTE volflg; UBYTE volpts; UBYTE volbeg; // (byte) Volume loop start (node) UBYTE volend; // (byte) Volume loop end (node) UBYTE volsusbeg; // (byte) Volume sustain begin (node) UBYTE volsusend; // (byte) Volume Sustain end (node) UBYTE panflg; UBYTE panpts; UBYTE panbeg; // (byte) channel loop start (node) UBYTE panend; // (byte) channel loop end (node) UBYTE pansusbeg; // (byte) cahnnel sustain begin (node) UBYTE pansusend; // (byte) channel Sustain end (node) UBYTE pitflg; UBYTE pitpts; UBYTE pitbeg; // (byte) pitch loop start (node) UBYTE pitend; // (byte) pitch loop end (node) UBYTE pitsusbeg; // (byte) pitch sustain begin (node) UBYTE pitsusend; // (byte) pitch Sustain end (node) UWORD blank; UBYTE globvol; UBYTE chanpan; UWORD fadeout; // Envelope end / NNA volume fadeout UBYTE dnc; // Duplicate note check UBYTE dca; // Duplicate check action UBYTE dct; // Duplicate check type UBYTE nna; // New Note Action [0,1,2,3] UWORD trkvers; // tracker version used to save [in files only] UBYTE ppsep; // Pitch-pan Separation UBYTE ppcenter; // Pitch-pan Center UBYTE rvolvar; // random volume varations UBYTE rpanvar; // random panning varations UWORD numsmp; // Number of samples in instrument [in files only] CHAR name[26]; // Instrument name UBYTE blank01[6]; UWORD samptable[120]; // sample for each note [note / samp pairs] UBYTE volenv[200]; // volume envelope (IT 1.x stuff) UBYTE oldvoltick[25]; // volume tick position (IT 1.x stuff) UBYTE volnode[25]; // aplitude of volume nodes UWORD voltick[25]; // tick value of volume nodes SBYTE pannode[25]; // panenv - node points UWORD pantick[25]; // tick value of panning nodes SBYTE pitnode[25]; // pitchenv - node points UWORD pittick[25]; // tick value of pitch nodes } ITINSTHEADER; /************************************************************************** **************************************************************************/ extern SBYTE remap[64]; // for removing empty channels extern UBYTE *poslookup; // S3M/IT fix - removing blank patterns needs a // lookup table to fix position-jump commands static ULONG *paraptr = NULL; // parapointer array (see IT docs) static ITHEADER *mh = NULL; static ITNOTE *itpat = NULL; // allocate to space for one full pattern static UBYTE *mask = NULL; // arrays allocated to 64 elements and used for static ITNOTE *last = NULL; // uncompressing IT's pattern information static int numtrk = 0; static int old_effect; // if set, use S3M old-effects stuffs static int *noteindex; CHAR IT_Version[] = "ImpulseTracker x.xx"; BOOL IT_Test(void) { UBYTE id[4]; if(!_mm_read_UBYTES(id,4,modfp)) return 0; if(!memcmp(id,"IMPM",4)) return 1; return 0; } BOOL IT_Init(void) { if((mh=(ITHEADER *)_mm_calloc(1,sizeof(ITHEADER)))==NULL) return 0; if((poslookup=(UBYTE *)_mm_malloc(256*sizeof(UBYTE)))==NULL) return 0; if((itpat=(ITNOTE *)_mm_malloc(200*64*sizeof(ITNOTE)))==NULL) return 0; if((mask=(UBYTE *)_mm_malloc(64*sizeof(UBYTE)))==NULL) return 0; if((last=(ITNOTE *)_mm_malloc(64*sizeof(ITNOTE)))==NULL) return 0; return 1; } void IT_Cleanup(void) { if(mh!=NULL) free(mh); if(poslookup!=NULL) free(poslookup); if(itpat!=NULL) free(itpat); if(mask!=NULL) free(mask); if(last!=NULL) free(last); if(paraptr!=NULL) free(paraptr); if(noteindex!=NULL) free(noteindex); mh = NULL; poslookup = NULL; itpat = NULL; mask = NULL; last = NULL; paraptr = NULL; noteindex = NULL; } BOOL IT_GetNumChannels(UWORD patrows) // Because so many IT files have 64 channels as the set number used, but really // only use far less (usually 8 to 12 still), I had to make this function, // which determines the number of channels that are actually USED by a pattern. // // For every channel that's used, it sets the appropriate array entry of the // global varialbe 'isused' // // NOTE: You must first seek to the file location of the pattern before calling // this procedure. // Returns 1 on error { int row=0,flag,ch; do { flag = _mm_read_UBYTE(modfp); if(flag == EOF) { _mm_errno = MMERR_LOADING_PATTERN; return 1; } if(flag == 0) { row++; } else { ch = (flag-1) & 63; remap[ch] = 0; if(flag & 128) mask[ch] = _mm_read_UBYTE(modfp); if(mask[ch] & 1) _mm_read_UBYTE(modfp); if(mask[ch] & 2) _mm_read_UBYTE(modfp); if(mask[ch] & 4) _mm_read_UBYTE(modfp); if(mask[ch] & 8) { _mm_read_UBYTE(modfp); _mm_read_UBYTE(modfp); } } } while(row < patrows); return 0; } BOOL IT_ReadPattern(UWORD patrows) { int blah; int row=0,flag,ch; ITNOTE *itt = itpat, dummy,*n,*l; memset(itt,255,patrows*of.numchn*sizeof(ITNOTE)); do { flag = _mm_read_UBYTE(modfp); if(feof(modfp)) { _mm_errno = MMERR_LOADING_PATTERN; return 0; } if(flag == 0) { itt = &itt[of.numchn]; row++; } else { ch = remap[(flag-1) & 63]; if(ch != -1) { n = &itt[ch]; l = &last[ch]; } else { n = l = &dummy; } if(flag & 128) mask[ch] = _mm_read_UBYTE(modfp); if(mask[ch] & 1) if((l->note = n->note = _mm_read_UBYTE(modfp)) == 255) { l->note = n->note = 253; } if(mask[ch] & 2) l->ins = n->ins = _mm_read_UBYTE(modfp); if(mask[ch] & 4) l->volpan = n->volpan = _mm_read_UBYTE(modfp); if(mask[ch] & 8) { l->cmd = n->cmd = _mm_read_UBYTE(modfp); l->inf = n->inf = _mm_read_UBYTE(modfp); } if(mask[ch] & 16) n->note = l->note; if(mask[ch] & 32) n->ins = l->ins; if(mask[ch] & 64) n->volpan = l->volpan; if(mask[ch] & 128) { n->cmd = l->cmd; n->inf = l->inf; } } } while(row < patrows); for(blah=0; blah<of.numchn; blah++) of.tracks[numtrk++] = IT_ConvertTrack(&itpat[blah],patrows); return 1; } void S3MIT_ProcessCmd(UBYTE cmd, UBYTE inf, BOOL oldeffect); // table for porta-to-note command within volume/panning column static UBYTE portatable[] = "1, 4, 8, 16, 32, 64, 96, 128, 255"; UBYTE *IT_ConvertTrack(ITNOTE *tr, UWORD numrows) { int t; UBYTE note,ins,volpan; UniReset(); for(t=0; t<numrows; t++) { note = tr[t*of.numchn].note; ins = tr[t*of.numchn].ins; volpan = tr[t*of.numchn].volpan; if(note!=255) { if(note==253) UniWrite(UNI_KEYOFF); else if(note==254) UniPTEffect(0xc,0); // <- note cut command else UniNote(note); } if((ins != 0) && (ins < 100)) UniInstrument(ins-1); // process volume / panning column // volume / panning effects do NOT all share the same memory address // yet. That requires more work than I care to apply at the moment ;) if(volpan<=64) { UniVolEffect(VOL_VOLUME,volpan); } else if((volpan>=65) && (volpan<=74)) // fine volume slide up (65-74) { UniVolEffect(VOL_VOLSLIDE,0x0f + ((volpan-65)<<4)); } else if((volpan>=75) && (volpan<=84)) // fine volume slide down (75-84) { UniVolEffect(VOL_VOLSLIDE,0xf0 + (volpan-75)); } else if((volpan>=85) && (volpan<=94)) // volume slide up (85-94) { UniVolEffect(VOL_VOLSLIDE,((volpan-85)<<4)); } else if((volpan>=95) && (volpan<=104)) // volume slide down (95-104) { UniVolEffect(VOL_VOLSLIDE,(volpan-95)); } else if((volpan>=105) && (volpan<=114)) // pitch slide up (105-114) { UniVolEffect(VOL_PITCHSLIDEDN,((volpan-105)<<4)); } else if((volpan>=115) && (volpan<=124)) // pitch slide down (115-124) { UniVolEffect(VOL_PITCHSLIDEUP,(volpan-115)); } else if((volpan>=128) && (volpan<=192)) { UniVolEffect(VOL_PANNING,((volpan-128) == 64) ? 255 : ((volpan-128) << 2)); } else if((volpan>=193) && (volpan<=202)) // portamento to note { UniVolEffect(VOL_PORTAMENTO,portatable[volpan-193]); } else if((volpan>=203) && (volpan<=212)) // vibrato { UniVolEffect(VOL_VIBRATO,(volpan-203)); } S3MIT_ProcessCmd(tr[t*of.numchn].cmd,tr[t*of.numchn].inf,old_effect); UniNewline(); } return UniDup(); } int cvt_c5spd_to_finetune(ULONG c5spd, int sampnum) { int ctmp=0,tmp,note=1,finetune=0; c5spd/=2; do { tmp = getfrequency(of.flags,getlinearperiod(note,0)); if(tmp >= c5spd) break; ctmp = tmp; note++; } while(1); if(tmp != c5spd) { if((tmp-c5spd) < (c5spd-ctmp)) while(tmp>c5spd) tmp = getfrequency(of.flags,getlinearperiod(note,--finetune)); else { note--; while(ctmp<c5spd) ctmp = getfrequency(of.flags,getlinearperiod(note,++finetune)); } } noteindex[sampnum] = note-48; return finetune; } BOOL IT_Load(void) { int t,u,lp; INSTRUMENT *d; SAMPLE *q; numtrk = 0; // try to read module header _mm_read_I_ULONG(modfp); // kill the 4 byte header _mm_read_string(mh->songname,26,modfp); _mm_read_UBYTES(mh->blank01,2,modfp); mh->ordnum =_mm_read_I_UWORD(modfp); mh->insnum =_mm_read_I_UWORD(modfp); mh->smpnum =_mm_read_I_UWORD(modfp); mh->patnum =_mm_read_I_UWORD(modfp); mh->cwt =_mm_read_I_UWORD(modfp); mh->cmwt =_mm_read_I_UWORD(modfp); mh->flags =_mm_read_I_UWORD(modfp); mh->special =_mm_read_I_UWORD(modfp); mh->globvol =_mm_read_UBYTE(modfp); mh->mixvol =_mm_read_UBYTE(modfp); mh->initspeed =_mm_read_UBYTE(modfp); mh->inittempo =_mm_read_UBYTE(modfp); mh->pansep =_mm_read_UBYTE(modfp); mh->zerobyte =_mm_read_UBYTE(modfp); mh->msglength =_mm_read_I_UWORD(modfp); mh->msgoffset =_mm_read_I_ULONG(modfp); _mm_read_UBYTES(mh->blank02,4,modfp); _mm_read_UBYTES(mh->pantable,64,modfp); _mm_read_UBYTES(mh->voltable,64,modfp); if(feof(modfp)) { _mm_errno = MMERR_LOADING_HEADER; return 0; } // set module variables of.modtype = strdup(IT_Version); of.modtype[15] = (mh->cwt >> 8) + 0x30; of.modtype[17] = ((mh->cwt >> 4) & 0xf) + 0x30; of.modtype[18] = ((mh->cwt) & 0xf) + 0x30; of.songname = DupStr(mh->songname,26); // make a cstr of songname of.reppos = 0; of.numpat = mh->patnum; of.numins = mh->insnum; of.numsmp = mh->smpnum; of.initspeed = mh->initspeed; of.inittempo = mh->inittempo; of.initvolume = mh->globvol; old_effect = 0; if(mh->flags & 8) { of.flags |= (UF_XMPERIODS | UF_LINEAR); old_effect |= 2; } if((mh->cwt >= 0x106) && (mh->flags & 16)) old_effect |= 1; // set panning positions for(t=0; t<64; t++) { if(mh->pantable[t] < 64) of.panning[t] = mh->pantable[t] << 2; else if(mh->pantable[t]==64) of.panning[t] = 255; else if(mh->pantable[t]==100) of.panning[t] = PAN_SURROUND; } // set channel volumes memcpy(of.chanvol,mh->voltable,64); // read the order data if(!AllocPositions(mh->ordnum)) return 0; for(t=0; t<mh->ordnum; t++) of.positions[t] = _mm_read_UBYTE(modfp); if(feof(modfp)) { _mm_errno = MMERR_LOADING_HEADER; return 0; } of.numpos = 0; for(t=0; t<mh->ordnum; t++) { of.positions[of.numpos] = of.positions[t]; poslookup[t] = of.numpos; // bug fix for FREAKY S3Ms / ITs if(of.positions[t]<254) of.numpos++; } if((paraptr=(ULONG *)_mm_malloc((mh->insnum+mh->smpnum+of.numpat)*sizeof(ULONG))) == NULL) return 0; // read the instrument, sample, and pattern parapointers _mm_read_I_ULONGS(paraptr,mh->insnum+mh->smpnum+of.numpat,modfp); // now is a good time to check if the header was too short :) if(feof(modfp)) { _mm_errno = MMERR_LOADING_HEADER; return 0; } // Check for and load song comment if(mh->special & 1) { _mm_fseek(modfp,(long)(mh->msgoffset),SEEK_SET); if(!ReadComment(mh->msglength)) return 0; } if(!(mh->flags & 4)) of.numins = of.numsmp; if(!AllocSamples()) return 0; if((noteindex=(int *)_mm_malloc(mh->smpnum*sizeof(int)))==NULL) return 0; q = of.samples; // Load all samples (they're used either way) for(t=0; t<mh->smpnum; t++) { ITSAMPLE s; // seek to sample position _mm_fseek(modfp,(long)(paraptr[mh->insnum+t] + 4),SEEK_SET); // and load sample info _mm_read_string(s.filename,12,modfp); s.zerobyte = _mm_read_UBYTE(modfp); s.globvol = _mm_read_UBYTE(modfp); s.flag = _mm_read_UBYTE(modfp); s.volume = _mm_read_UBYTE(modfp); _mm_read_string(s.sampname,26,modfp); s.convert = _mm_read_UBYTE(modfp); s.panning = _mm_read_UBYTE(modfp); s.length = _mm_read_I_ULONG(modfp); s.loopbeg = _mm_read_I_ULONG(modfp); s.loopend = _mm_read_I_ULONG(modfp); s.c5spd = _mm_read_I_ULONG(modfp); s.susbegin = _mm_read_I_ULONG(modfp); s.susend = _mm_read_I_ULONG(modfp); s.sampoffset = _mm_read_I_ULONG(modfp); s.vibspeed = _mm_read_UBYTE(modfp); s.vibdepth = _mm_read_UBYTE(modfp); s.vibrate = _mm_read_UBYTE(modfp); s.vibwave = _mm_read_UBYTE(modfp); // Generate an error if c5spd is > 512k, or samplelength > 256 megs // (nothing would EVER be that high) if(feof(modfp) || (s.c5spd > 0x7ffffL) || (s.length > 0xfffffffUL) || (s.loopbeg > 0xfffffffUL) || (s.loopend > 0xfffffffUL)) { _mm_errno = MMERR_LOADING_SAMPLEINFO; return 0; } q->samplename = DupStr(s.sampname,26); q->speed = s.c5spd / 2; q->panning = ((s.panning & 127)==64) ? 255 : (s.panning & 127) << 2; q->length = s.length; q->loopstart = s.loopbeg; q->loopend = s.loopend; q->volume = s.volume; q->globvol = s.globvol; q->seekpos = s.sampoffset; // =================================== // Convert speed to XM linear finetune if(of.flags & UF_LINEAR) q->speed = cvt_c5spd_to_finetune(s.c5spd, t); if(s.panning & 128) q->flags |= SF_OWNPAN; if(s.vibrate) { q->vibflags |= AV_IT; q->vibtype = s.vibwave; q->vibsweep = s.vibrate * 2; q->vibdepth = s.vibdepth; q->vibrate = s.vibspeed; } if(s.flag & 2) q->flags |= SF_16BITS; if(s.flag & 16) q->flags |= SF_LOOP; if(s.flag & 64) q->flags |= SF_BIDI; if(mh->cwt >= 0x200) { if(s.convert & 1) q->flags |= SF_SIGNED; if(s.convert & 4) q->flags |= SF_DELTA; } q++; } // Load instruments if instrument mode flag enabled if(mh->flags & 4) { if(!AllocInstruments()) return 0; d = of.instruments; of.flags |= UF_NNA | UF_INST; for(t=0; t<mh->insnum; t++) { ITINSTHEADER ih; // seek to instrument position _mm_fseek(modfp,paraptr[t]+4,SEEK_SET); // and load instrument info _mm_read_string(ih.filename,12,modfp); ih.zerobyte = _mm_read_UBYTE(modfp); if(mh->cwt < 0x200) // load IT 1.xx inst header { ih.volflg = _mm_read_UBYTE(modfp); ih.volbeg = _mm_read_UBYTE(modfp); ih.volend = _mm_read_UBYTE(modfp); ih.volsusbeg = _mm_read_UBYTE(modfp); ih.volsusend = _mm_read_UBYTE(modfp); _mm_read_I_UWORD(modfp); ih.fadeout = _mm_read_I_UWORD(modfp); ih.nna = _mm_read_UBYTE(modfp); ih.dnc = _mm_read_UBYTE(modfp); } else // Read IT200+ header { ih.nna = _mm_read_UBYTE(modfp); ih.dct = _mm_read_UBYTE(modfp); ih.dca = _mm_read_UBYTE(modfp); ih.fadeout = _mm_read_I_UWORD(modfp); ih.ppsep = _mm_read_UBYTE(modfp); ih.ppcenter = _mm_read_UBYTE(modfp); ih.globvol = _mm_read_UBYTE(modfp); ih.chanpan = _mm_read_UBYTE(modfp); ih.rvolvar = _mm_read_UBYTE(modfp); ih.rpanvar = _mm_read_UBYTE(modfp); } ih.trkvers = _mm_read_I_UWORD(modfp); ih.numsmp = _mm_read_UBYTE(modfp); _mm_read_UBYTE(modfp); _mm_read_string(ih.name,26,modfp); _mm_read_UBYTES(ih.blank01,6,modfp); _mm_read_I_UWORDS(ih.samptable,120,modfp); if(mh->cwt < 0x200) // load IT 1xx volume envelope { _mm_read_UBYTES(ih.volenv,200,modfp); for(lp=0; lp<25; lp++) { ih.oldvoltick[lp] = _mm_read_UBYTE(modfp); ih.volnode[lp] = _mm_read_UBYTE(modfp); } } else // load IT 2xx vol & chanpan & pitch envs { ih.volflg = _mm_read_UBYTE(modfp); ih.volpts = _mm_read_UBYTE(modfp); ih.volbeg = _mm_read_UBYTE(modfp); ih.volend = _mm_read_UBYTE(modfp); ih.volsusbeg = _mm_read_UBYTE(modfp); ih.volsusend = _mm_read_UBYTE(modfp); for(lp=0; lp<25; lp++) { ih.volnode[lp] = _mm_read_UBYTE(modfp); ih.voltick[lp] = _mm_read_I_UWORD(modfp); } _mm_read_UBYTE(modfp); ih.panflg = _mm_read_UBYTE(modfp); ih.panpts = _mm_read_UBYTE(modfp); ih.panbeg = _mm_read_UBYTE(modfp); ih.panend = _mm_read_UBYTE(modfp); ih.pansusbeg = _mm_read_UBYTE(modfp); ih.pansusend = _mm_read_UBYTE(modfp); for(lp=0; lp<25; lp++) { ih.pannode[lp] = _mm_read_SBYTE(modfp); ih.pantick[lp] = _mm_read_I_UWORD(modfp); } _mm_read_UBYTE(modfp); ih.pitflg = _mm_read_UBYTE(modfp); ih.pitpts = _mm_read_UBYTE(modfp); ih.pitbeg = _mm_read_UBYTE(modfp); ih.pitend = _mm_read_UBYTE(modfp); ih.pitsusbeg = _mm_read_UBYTE(modfp); ih.pitsusend = _mm_read_UBYTE(modfp); for(lp=0; lp<25; lp++) { ih.pitnode[lp] = _mm_read_SBYTE(modfp); ih.pittick[lp] = _mm_read_I_UWORD(modfp); } _mm_read_UBYTE(modfp); } if(feof(modfp)) { _mm_errno = MMERR_LOADING_SAMPLEINFO; return 0; } d->volflg |= EF_VOLENV; d->insname = DupStr(ih.name,26); d->nnatype = ih.nna; if(mh->cwt < 0x200) { d->volfade = ih.fadeout << 6; if(ih.dnc) { d->dct = DCT_NOTE; d->dca = DCA_CUT; } if(ih.volflg & 1) d->volflg |= EF_ON; if(ih.volflg & 2) d->volflg |= EF_LOOP; if(ih.volflg & 4) d->volflg |= EF_SUSTAIN; // XM conversion of IT envelope Array d->volbeg = ih.volbeg; d->volend = ih.volend; d->volsusbeg = ih.volsusbeg; d->volsusend = ih.volsusend; if(ih.volflg & 1) { for(u=0; u<25; u++) if(ih.oldvoltick[d->volpts] != 0xff) { d->volenv[d->volpts].val = (ih.volnode[d->volpts] << 2); d->volenv[d->volpts].pos = ih.oldvoltick[d->volpts]; d->volpts++; } else break; } } else { d->panning = ((ih.chanpan&127) == 64) ? 255 : (ih.chanpan&127)<<2; if(!(ih.chanpan & 128)) d->flags |= IF_OWNPAN; if(!(ih.ppsep & 128)) { d->pitpansep = ih.ppsep << 2; d->pitpancenter= ih.ppcenter; d->flags |= IF_PITCHPAN; } d->globvol = ih.globvol >> 1; d->volfade = ih.fadeout << 5; d->dct = ih.dct; d->dca = ih.dca; if(mh->cwt >= 0x204) { d->rvolvar = ih.rvolvar; d->rpanvar = ih.rpanvar; } if(ih.volflg & 1) d->volflg |= EF_ON; if(ih.volflg & 2) d->volflg |= EF_LOOP; if(ih.volflg & 4) d->volflg |= EF_SUSTAIN; if(ih.panflg & 1) d->panflg |= EF_ON; if(ih.panflg & 2) d->panflg |= EF_LOOP; if(ih.panflg & 4) d->panflg |= EF_SUSTAIN; if(ih.pitflg & 1) d->pitflg |= EF_ON; if(ih.pitflg & 2) d->pitflg |= EF_LOOP; if(ih.pitflg & 4) d->pitflg |= EF_SUSTAIN; d->volpts = ih.volpts; d->volbeg = ih.volbeg; d->volend = ih.volend; d->volsusbeg = ih.volsusbeg; d->volsusend = ih.volsusend; for(u=0; u<ih.volpts; u++) { d->volenv[u].val = (ih.volnode[u] << 2); d->volenv[u].pos = ih.voltick[u]; } d->panpts = ih.panpts; d->panbeg = ih.panbeg; d->panend = ih.panend; d->pansusbeg = ih.pansusbeg; d->pansusend = ih.pansusend; for(u=0; u<ih.panpts; u++) { d->panenv[u].val = (ih.pannode[u]+32) << 2; d->panenv[u].pos = ih.pantick[u]; } d->pitpts = ih.pitpts; d->pitbeg = ih.pitbeg; d->pitend = ih.pitend; d->pitsusbeg = ih.pitsusbeg; d->pitsusend = ih.pitsusend; for(u=0; u<ih.pitpts; u++) { d->pitenv[u].val = (ih.pitnode[u]+32); d->pitenv[u].pos = ih.pittick[u]; } } if(of.flags & UF_LINEAR) { for(u=0; u<120; u++) { d->samplenote[u] = (ih.samptable[u] & 255); d->samplenumber[u] = (ih.samptable[u] >> 8) ? ((ih.samptable[u] >> 8) - 1) : 255; if(d->samplenumber[u]!=255) d->samplenote[u] += noteindex[d->samplenumber[u]]; } } else { for(u=0; u<120; u++) { d->samplenote[u] = (ih.samptable[u] & 255); d->samplenumber[u] = (ih.samptable[u] >> 8) ? ((ih.samptable[u] >> 8) - 1) : 255; } } d++; } } else if(of.flags & UF_LINEAR) { if(!AllocInstruments()) return 0; d = of.instruments; of.flags |= UF_INST; for(t=0; t<mh->smpnum; t++, d++) { for(u=0; u<120; u++) d->samplenote[u] += noteindex[d->samplenumber[u]]; } } // Figure out how many channels this blasted song actually uses (what // ever happened to common courtesy of storing this simple value // somewhere in the damn module, eh!?) of.numchn = 0; memset(remap,-1,64*sizeof(UBYTE)); for(t=0; t<of.numpat; t++) { UWORD packlen; // seek to pattern position if(paraptr[mh->insnum+mh->smpnum+t] != 0) // No parapointer = pattern of 64 rows, EMPTY { _mm_fseek(modfp,(((long)paraptr[mh->insnum+mh->smpnum+t])),SEEK_SET); packlen = _mm_read_I_UWORD(modfp); packlen = _mm_read_I_UWORD(modfp); // read pattern length (# of rows) _mm_read_I_ULONG(modfp); if(IT_GetNumChannels(packlen)) return 0; } } // give each of them a different number for(t=0; t<64; t++) { if(remap[t]==0) { remap[t] = of.numchn; of.numchn++; } } of.numtrk = of.numpat*of.numchn; if(!AllocPatterns()) return 0; if(!AllocTracks()) return 0; for(t=0; t<of.numpat; t++) { UWORD packlen; // seek to pattern position if(paraptr[mh->insnum+mh->smpnum+t] == 0) // No parapointer = pattern of 64 rows, EMPTY { of.pattrows[t] = 64; for(u=0; u<of.numchn; u++) { int k; UniReset(); for(k=0; k<64; k++) UniNewline(); of.tracks[numtrk++] = UniDup(); } } else { _mm_fseek(modfp,(((long)paraptr[mh->insnum+mh->smpnum+t])),SEEK_SET); packlen = _mm_read_I_UWORD(modfp); of.pattrows[t] = _mm_read_I_UWORD(modfp); _mm_read_I_ULONG(modfp); if(!IT_ReadPattern(of.pattrows[t])) return 0; } } return 1; } CHAR *IT_LoadTitle(void) { CHAR s[26]; _mm_fseek(modfp,4,SEEK_SET); if(!fread(s,26,1,modfp)) return NULL; return(DupStr(s,26)); } MLOADER load_it = { NULL, "IT", "Portable IT loader v0.2", IT_Init, IT_Test, IT_Load, IT_Cleanup, IT_LoadTitle };