X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dosdemo;a=blobdiff_plain;f=libs%2Fmikmod%2Floaders%2Fload_it.c;fp=libs%2Fmikmod%2Floaders%2Fload_it.c;h=efe63a996781a3074a6bd937ff1a884b27bee03f;hp=0000000000000000000000000000000000000000;hb=cf94899f4f4d8535074db6421245b973d2fcde8c;hpb=8024ae981f39d370af5cceb3cb97f62820b0a120 diff --git a/libs/mikmod/loaders/load_it.c b/libs/mikmod/loaders/load_it.c new file mode 100644 index 0000000..efe63a9 --- /dev/null +++ b/libs/mikmod/loaders/load_it.c @@ -0,0 +1,1020 @@ +/* MikMod sound library + (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file + AUTHORS for complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +/*============================================================================== + + $Id$ + + Impulse tracker (IT) module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#ifdef HAVE_MEMORY_H +#include +#endif +#include + +#include "mikmod_internals.h" +#include "mikmod_ctype.h" + +#ifdef SUNOS +extern int fprintf(FILE *, const char *, ...); +#endif + +/*========== Module structure */ + +/* header */ +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; /* Compatible 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; + +/* sample information */ +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) */ +} ITSAMPLE; + +/* instrument information */ + +#define ITENVCNT 25 +#define ITNOTECNT 120 +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) channel 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 [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 [files only] */ + CHAR name[26]; /* Instrument name */ + UBYTE blank01[6]; + UWORD samptable[ITNOTECNT];/* sample for each note [note / samp pairs] */ + UBYTE volenv[200]; /* volume envelope (IT 1.x stuff) */ + UBYTE oldvoltick[ITENVCNT];/* volume tick position (IT 1.x stuff) */ + UBYTE volnode[ITENVCNT]; /* amplitude of volume nodes */ + UWORD voltick[ITENVCNT]; /* tick value of volume nodes */ + SBYTE pannode[ITENVCNT]; /* panenv - node points */ + UWORD pantick[ITENVCNT]; /* tick value of panning nodes */ + SBYTE pitnode[ITENVCNT]; /* pitchenv - node points */ + UWORD pittick[ITENVCNT]; /* tick value of pitch nodes */ +} ITINSTHEADER; + +/* unpacked note */ + +typedef struct ITNOTE { + UBYTE note,ins,volpan,cmd,inf; +} ITNOTE; + +/*========== Loader data */ + +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 unsigned int old_effect; /* if set, use S3M old-effects stuffs */ + +static const CHAR* IT_Version[]={ + "ImpulseTracker . ", + "Compressed ImpulseTracker . ", + "ImpulseTracker 2.14p3", + "Compressed ImpulseTracker 2.14p3", + "ImpulseTracker 2.14p4", + "Compressed ImpulseTracker 2.14p4", +}; + +/* table for porta-to-note command within volume/panning column */ +static const UBYTE portatable[10]= {0,1,4,8,16,32,64,96,128,255}; + +/*========== Loader code */ + +static BOOL IT_Test(void) +{ + UBYTE id[4]; + + if(!_mm_read_UBYTES(id,4,modreader)) return 0; + if(!memcmp(id,"IMPM",4)) return 1; + return 0; +} + +static BOOL IT_Init(void) +{ + if(!(mh=(ITHEADER*)MikMod_malloc(sizeof(ITHEADER)))) return 0; + if(!(poslookup=(UBYTE*)MikMod_malloc(256*sizeof(UBYTE)))) return 0; + if(!(itpat=(ITNOTE*)MikMod_malloc(200*64*sizeof(ITNOTE)))) return 0; + if(!(mask=(UBYTE*)MikMod_malloc(64*sizeof(UBYTE)))) return 0; + if(!(last=(ITNOTE*)MikMod_malloc(64*sizeof(ITNOTE)))) return 0; + + return 1; +} + +static void IT_Cleanup(void) +{ + FreeLinear(); + + MikMod_free(mh); + MikMod_free(poslookup); + MikMod_free(itpat); + MikMod_free(mask); + MikMod_free(last); + MikMod_free(paraptr); + MikMod_free(origpositions); + mh=NULL; + poslookup=NULL; + itpat=NULL; + mask=NULL; + last=NULL; + paraptr=NULL; + origpositions=NULL; +} + +/* Because so many IT files have 64 channels as the set number used, but really + only use far less (usually from 8 to 24 still), I had to make this function, + which determines the number of channels that are actually USED by a pattern. + + NOTE: You must first seek to the file location of the pattern before calling + this procedure. + + Returns 0 on error +*/ +static BOOL IT_GetNumChannels(UWORD patrows) +{ + int row=0,flag,ch; + + do { + if((flag=_mm_read_UBYTE(modreader))==EOF) { + _mm_errno=MMERR_LOADING_PATTERN; + return 0; + } + if(!flag) + row++; + else { + ch=(flag-1)&63; + remap[ch]=0; + if(flag & 128) mask[ch]=_mm_read_UBYTE(modreader); + if(mask[ch]&1) _mm_skip_BYTE(modreader); + if(mask[ch]&2) _mm_skip_BYTE(modreader); + if(mask[ch]&4) _mm_skip_BYTE(modreader); + if(mask[ch]&8) { _mm_skip_BYTE(modreader);_mm_skip_BYTE(modreader); } + } + } while(rownote=n->note=_mm_read_UBYTE(modreader))==255) + l->note=n->note=253; + if(mask[ch]&2) + l->ins=n->ins=_mm_read_UBYTE(modreader); + if(mask[ch]&4) + l->volpan=n->volpan=_mm_read_UBYTE(modreader); + if(mask[ch]&8) { + l->cmd=n->cmd=_mm_read_UBYTE(modreader); + l->inf=n->inf=_mm_read_UBYTE(modreader); + } + 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(rowsongname,26,modreader); + _mm_read_UBYTES(mh->blank01,2,modreader); + mh->ordnum =_mm_read_I_UWORD(modreader); + mh->insnum =_mm_read_I_UWORD(modreader); + mh->smpnum =_mm_read_I_UWORD(modreader); + mh->patnum =_mm_read_I_UWORD(modreader); + mh->cwt =_mm_read_I_UWORD(modreader); + mh->cmwt =_mm_read_I_UWORD(modreader); + mh->flags =_mm_read_I_UWORD(modreader); + mh->special =_mm_read_I_UWORD(modreader); + mh->globvol =_mm_read_UBYTE(modreader); + mh->mixvol =_mm_read_UBYTE(modreader); + mh->initspeed =_mm_read_UBYTE(modreader); + mh->inittempo =_mm_read_UBYTE(modreader); + mh->pansep =_mm_read_UBYTE(modreader); + mh->zerobyte =_mm_read_UBYTE(modreader); + mh->msglength =_mm_read_I_UWORD(modreader); + mh->msgoffset =_mm_read_I_ULONG(modreader); + _mm_read_UBYTES(mh->blank02,4,modreader); + _mm_read_UBYTES(mh->pantable,64,modreader); + _mm_read_UBYTES(mh->voltable,64,modreader); + + if(_mm_eof(modreader)) { + _mm_errno=MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + of.songname = DupStr(mh->songname,26,0); /* 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; + of.flags |= UF_BGSLIDES | UF_ARPMEM; + if (!(mh->flags & 1)) + of.flags |= UF_PANNING; + of.bpmlimit=32; + + if(mh->songname[25]) { + of.numvoices=1+mh->songname[25]; +#ifdef MIKMOD_DEBUG + fprintf(stderr,"Embedded IT limitation to %d voices\n",of.numvoices); +#endif + } + + /* set the module type */ + /* 2.17 : IT 2.14p4 */ + /* 2.16 : IT 2.14p3 with resonant filters */ + /* 2.15 : IT 2.14p3 (improved compression) */ + if((mh->cwt<=0x219)&&(mh->cwt>=0x217)) + of.modtype=MikMod_strdup(IT_Version[mh->cmwt<0x214?4:5]); + else if (mh->cwt>=0x215) + of.modtype=MikMod_strdup(IT_Version[mh->cmwt<0x214?2:3]); + else { + of.modtype = MikMod_strdup(IT_Version[mh->cmwt<0x214?0:1]); + of.modtype[mh->cmwt<0x214?15:26] = (mh->cwt>>8)+'0'; + of.modtype[mh->cmwt<0x214?17:28] = ((mh->cwt>>4)&0xf)+'0'; + of.modtype[mh->cmwt<0x214?18:29] = ((mh->cwt)&0xf)+'0'; + } + + if(mh->flags&8) + of.flags |= UF_XMPERIODS | UF_LINEAR; + + if((mh->cwt>=0x106)&&(mh->flags&16)) + old_effect=S3MIT_OLDSTYLE; + else + old_effect=0; + + /* set panning positions */ + if (mh->flags & 1) + for(t=0;t<64;t++) { + mh->pantable[t]&=0x7f; + 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; + else if(mh->pantable[t]==127) + of.panning[t]=PAN_CENTER; + else { + _mm_errno=MMERR_LOADING_HEADER; + return 0; + } + } + else + for(t=0;t<64;t++) + of.panning[t]=PAN_CENTER; + + /* set channel volumes */ + memcpy(of.chanvol,mh->voltable,64); + + /* read the order data */ + if(!AllocPositions(mh->ordnum)) return 0; + if(!(origpositions=(UWORD*)MikMod_calloc(mh->ordnum,sizeof(UWORD)))) return 0; + + for(t=0;tordnum;t++) { + origpositions[t]=_mm_read_UBYTE(modreader); + if((origpositions[t]>mh->patnum)&&(origpositions[t]<254)) + origpositions[t]=255; + } + + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + poslookupcnt=mh->ordnum; + S3MIT_CreateOrders(curious); + + if(!(paraptr=(ULONG*)MikMod_malloc((mh->insnum+mh->smpnum+of.numpat)* + sizeof(ULONG)))) return 0; + + /* read the instrument, sample, and pattern parapointers */ + _mm_read_I_ULONGS(paraptr,mh->insnum+mh->smpnum+of.numpat,modreader); + + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* Check for and load midi information for resonant filters */ + if(mh->cmwt>=0x216) { + if(mh->special&8) { + IT_LoadMidiConfiguration(modreader); + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + } else + IT_LoadMidiConfiguration(NULL); + filters=1; + } + + /* Check for and load song comment */ + if((mh->special&1)&&(mh->cwt>=0x104)&&(mh->msglength)) { + _mm_fseek(modreader,(long)(mh->msgoffset),SEEK_SET); + if(!ReadComment(mh->msglength)) return 0; + } + + if(!(mh->flags&4)) of.numins=of.numsmp; + if(!AllocSamples()) return 0; + + if(!AllocLinear()) return 0; + + /* Load all samples */ + q = of.samples; + for(t=0;tsmpnum;t++) { + ITSAMPLE s; + + /* seek to sample position */ + _mm_fseek(modreader,(long)(paraptr[mh->insnum+t]+4),SEEK_SET); + + /* load sample info */ + _mm_read_string(s.filename,12,modreader); + s.zerobyte = _mm_read_UBYTE(modreader); + s.globvol = _mm_read_UBYTE(modreader); + s.flag = _mm_read_UBYTE(modreader); + s.volume = _mm_read_UBYTE(modreader); + _mm_read_string(s.sampname,26,modreader); + s.convert = _mm_read_UBYTE(modreader); + s.panning = _mm_read_UBYTE(modreader); + s.length = _mm_read_I_ULONG(modreader); + s.loopbeg = _mm_read_I_ULONG(modreader); + s.loopend = _mm_read_I_ULONG(modreader); + s.c5spd = _mm_read_I_ULONG(modreader); + s.susbegin = _mm_read_I_ULONG(modreader); + s.susend = _mm_read_I_ULONG(modreader); + s.sampoffset = _mm_read_I_ULONG(modreader); + s.vibspeed = _mm_read_UBYTE(modreader); + s.vibdepth = _mm_read_UBYTE(modreader); + s.vibrate = _mm_read_UBYTE(modreader); + s.vibwave = _mm_read_UBYTE(modreader); + + /* Generate an error if c5spd is > 512k, or samplelength > 256 megs + (nothing would EVER be that high) */ + + if(_mm_eof(modreader)||(s.c5spd>0x7ffffL)||(s.length>0xfffffffUL)) { + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + /* Reality check for sample loop information */ + if((s.flag&16)&& + ((s.loopbeg>0xfffffffUL)||(s.loopend>0xfffffffUL))) { + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + q->samplename = DupStr(s.sampname,26,0); + 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=speed_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&8)&&(mh->cwt>=0x214)) { + q->flags|=SF_ITPACKED; + /*compressed=1;*/ + } + 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;tinsnum;t++) { + ITINSTHEADER ih; + + /* seek to instrument position */ + _mm_fseek(modreader,paraptr[t]+4,SEEK_SET); + + /* load instrument info */ + _mm_read_string(ih.filename,12,modreader); + ih.zerobyte = _mm_read_UBYTE(modreader); + if(mh->cwt<0x200) { + /* load IT 1.xx inst header */ + ih.volflg = _mm_read_UBYTE(modreader); + ih.volbeg = _mm_read_UBYTE(modreader); + ih.volend = _mm_read_UBYTE(modreader); + ih.volsusbeg = _mm_read_UBYTE(modreader); + ih.volsusend = _mm_read_UBYTE(modreader); + _mm_read_I_UWORD(modreader); + ih.fadeout = _mm_read_I_UWORD(modreader); + ih.nna = _mm_read_UBYTE(modreader); + ih.dnc = _mm_read_UBYTE(modreader); + } else { + /* Read IT200+ header */ + ih.nna = _mm_read_UBYTE(modreader); + ih.dct = _mm_read_UBYTE(modreader); + ih.dca = _mm_read_UBYTE(modreader); + ih.fadeout = _mm_read_I_UWORD(modreader); + ih.ppsep = _mm_read_UBYTE(modreader); + ih.ppcenter = _mm_read_UBYTE(modreader); + ih.globvol = _mm_read_UBYTE(modreader); + ih.chanpan = _mm_read_UBYTE(modreader); + ih.rvolvar = _mm_read_UBYTE(modreader); + ih.rpanvar = _mm_read_UBYTE(modreader); + } + + ih.trkvers = _mm_read_I_UWORD(modreader); + ih.numsmp = _mm_read_UBYTE(modreader); + _mm_skip_BYTE(modreader); + _mm_read_string(ih.name,26,modreader); + _mm_read_UBYTES(ih.blank01,6,modreader); + _mm_read_I_UWORDS(ih.samptable,ITNOTECNT,modreader); + if(mh->cwt<0x200) { + /* load IT 1xx volume envelope */ + _mm_read_UBYTES(ih.volenv,200,modreader); + for(lp=0;lp ITENVCNT) \ + ih. name##pts = ITENVCNT; \ + ih. name##beg =_mm_read_UBYTE(modreader); \ + ih. name##end =_mm_read_UBYTE(modreader); \ + ih. name##susbeg=_mm_read_UBYTE(modreader); \ + ih. name##susend=_mm_read_UBYTE(modreader); \ + for(lp=0;lp ITENVCNT) \ + ih. name/**/pts = ITENVCNT; \ + ih. name/**/beg =_mm_read_UBYTE(modreader); \ + ih. name/**/end =_mm_read_UBYTE(modreader); \ + ih. name/**/susbeg=_mm_read_UBYTE(modreader); \ + ih. name/**/susend=_mm_read_UBYTE(modreader); \ + for(lp=0;lpvolflg|=EF_VOLENV; + d->insname = DupStr(ih.name,26,0); + d->nnatype = ih.nna & NNA_MASK; + + 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;uvolpts]!=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 defined __STDC__ || defined _MSC_VER || defined MPW_C +#define IT_ProcessEnvelope(name) \ + if(ih. name##flg&1) d-> name##flg|=EF_ON; \ + if(ih. name##flg&2) d-> name##flg|=EF_LOOP; \ + if(ih. name##flg&4) d-> name##flg|=EF_SUSTAIN; \ + d-> name##pts=ih. name##pts; \ + d-> name##beg=ih. name##beg; \ + d-> name##end=ih. name##end; \ + d-> name##susbeg=ih. name##susbeg; \ + d-> name##susend=ih. name##susend; \ + \ + for(u=0;u name##env[u].pos=ih. name##tick[u]; \ + \ + if((d-> name##flg&EF_ON)&&(d-> name##pts<2)) \ + d-> name##flg&=~EF_ON +#else +#define IT_ProcessEnvelope(name) \ + if(ih. name/**/flg&1) d-> name/**/flg|=EF_ON; \ + if(ih. name/**/flg&2) d-> name/**/flg|=EF_LOOP; \ + if(ih. name/**/flg&4) d-> name/**/flg|=EF_SUSTAIN; \ + d-> name/**/pts=ih. name/**/pts; \ + d-> name/**/beg=ih. name/**/beg; \ + d-> name/**/end=ih. name/**/end; \ + d-> name/**/susbeg=ih. name/**/susbeg; \ + d-> name/**/susend=ih. name/**/susend; \ + \ + for(u=0;u name/**/env[u].pos=ih. name/**/tick[u]; \ + \ + if((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \ + d-> name/**/flg&=~EF_ON +#endif + + IT_ProcessEnvelope(vol); + + for(u=0;uvolenv[u].val=(ih.volnode[u]<<2); + + IT_ProcessEnvelope(pan); + for(u=0;upanenv[u].val= + ih.pannode[u]==32?255:(ih.pannode[u]+32)<<2; + + IT_ProcessEnvelope(pit); + for(u=0;upitenv[u].val=ih.pitnode[u]+32; +#undef IT_ProcessEnvelope + + if(ih.pitflg&0x80) { + /* filter envelopes not supported yet */ + d->pitflg&=~EF_ON; + ih.pitpts=ih.pitbeg=ih.pitend=0; +#ifdef MIKMOD_DEBUG + { + static int warn=0; + + if(!warn) + fprintf(stderr, "\rFilter envelopes not supported yet\n"); + warn=1; + } +#endif + } + } + + for(u=0;usamplenote[u]=(ih.samptable[u]&255); + d->samplenumber[u]= + (ih.samptable[u]>>8)?((ih.samptable[u]>>8)-1):0xffff; + if(d->samplenumber[u]>=of.numsmp) + d->samplenote[u]=255; + else if (of.flags&UF_LINEAR) { + int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]]; + d->samplenote[u]=(note<0)?0:(note>255?255:note); + } + } + + d++; + } + } else if(of.flags & UF_LINEAR) { + if(!AllocInstruments()) return 0; + d=of.instruments; + of.flags|=UF_INST; + + for(t=0;tsmpnum;t++,d++) + for(u=0;usamplenumber[u]>=of.numsmp) + d->samplenote[u]=255; + else { + int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]]; + d->samplenote[u]=(note<0)?0:(note>255?255:note); + } + } + } + + /* Figure out how many channels this song actually uses */ + of.numchn=0; + memset(remap,-1,UF_MAXCHAN*sizeof(UBYTE)); + for(t=0;tinsnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */ + _mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET); + _mm_read_I_UWORD(modreader); + /* read pattern length (# of rows) + Impulse Tracker never creates patterns with less than 32 rows, + but some other trackers do, so we only check for more than 256 + rows */ + packlen=_mm_read_I_UWORD(modreader); + if(packlen>256) { + _mm_errno=MMERR_LOADING_PATTERN; + return 0; + } + _mm_read_I_ULONG(modreader); + if(!IT_GetNumChannels(packlen)) return 0; + } + } + + /* give each of them a different number */ + for(t=0;tinsnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */ + of.pattrows[t]=64; + for(u=0;uinsnum+mh->smpnum+t]),SEEK_SET); + packlen=_mm_read_I_UWORD(modreader); + (void)packlen; /* unused */ + of.pattrows[t]=_mm_read_I_UWORD(modreader); + _mm_read_I_ULONG(modreader); + if(!IT_ReadPattern(of.pattrows[t])) return 0; + } + } + + return 1; +} + +static CHAR *IT_LoadTitle(void) +{ + CHAR s[26]; + + _mm_fseek(modreader,4,SEEK_SET); + if(!_mm_read_UBYTES(s,26,modreader)) return NULL; + + return(DupStr(s,26,0)); +} + +/*========== Loader information */ + +MIKMODAPI MLOADER load_it={ + NULL, + "IT", + "IT (Impulse Tracker)", + IT_Init, + IT_Test, + IT_Load, + IT_Cleanup, + IT_LoadTitle +}; + +/* ex:set ts=4: */