/* 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: load_it.c,v 1.4 2010/01/12 03:30:32 realtech Exp $ Impulse tracker (IT) module loader ==============================================================================*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_UNISTD_H #include #endif #include #include #ifdef HAVE_MEMORY_H #include #endif #include #include "mikmod_internals.h" #ifdef SUNOS extern int fprintf(FILE *, const char *, ...); extern int toupper(int); #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 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 UBYTE portatable[10]= {0,1,4,8,16,32,64,96,128,255}; /*========== Loader code */ int IT_Test(void) { UBYTE id[4]; if(!_mm_read_UBYTES(id,4,modreader)) return 0; if(!memcmp(id,"IMPM",4)) return 1; return 0; } int 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; } 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); } /* 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 1 on error */ static int IT_GetNumChannels(UWORD patrows) { int row=0,flag,ch; do { if((flag=_mm_read_UBYTE(modreader))==EOF) { _mm_errno=MMERR_LOADING_PATTERN; return 1; } if(!flag) row++; else { ch=(flag-1)&63; remap[ch]=0; if(flag & 128) mask[ch]=_mm_read_UBYTE(modreader); if(mask[ch]&1) (void)_mm_read_UBYTE(modreader); if(mask[ch]&2) (void)_mm_read_UBYTE(modreader); if(mask[ch]&4) (void)_mm_read_UBYTE(modreader); if(mask[ch]&8) { (void)_mm_read_UBYTE(modreader);(void)_mm_read_UBYTE(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=StrDup(IT_Version[mh->cmwt<0x214?4:5]); else if (mh->cwt>=0x215) of.modtype=StrDup(IT_Version[mh->cmwt<0x214?2:3]); else { of.modtype = 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=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); (void)_mm_read_UBYTE(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;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); // Secunia SA37775 if (ih.volpts>= ENVPOINTS) ih.volpts = ENVPOINTS-1; 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); (void)_mm_read_I_UWORD(modreader); of.pattrows[t]=_mm_read_I_UWORD(modreader); _mm_read_I_ULONG(modreader); if(!IT_ReadPattern(of.pattrows[t])) return 0; } } return 1; } 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: */