Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / loaders / load_it.c
diff --git a/apps/plugins/mikmod/loaders/load_it.c b/apps/plugins/mikmod/loaders/load_it.c
new file mode 100644 (file)
index 0000000..d115af5
--- /dev/null
@@ -0,0 +1,1008 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_it.c,v 1.2 2004/02/06 19:29:03 raph Exp $\r
+\r
+  Impulse tracker (IT) module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+//#include <ctype.h>\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+extern int toupper(int);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+/* header */\r
+typedef struct ITHEADER {\r
+       CHAR    songname[26];\r
+       UBYTE   blank01[2];\r
+       UWORD   ordnum;\r
+       UWORD   insnum;\r
+       UWORD   smpnum;\r
+       UWORD   patnum;\r
+       UWORD   cwt;            /* Created with tracker (y.xx = 0x0yxx) */\r
+       UWORD   cmwt;           /* Compatible with tracker ver > than val. */\r
+       UWORD   flags;\r
+       UWORD   special;        /* bit 0 set = song message attached */\r
+       UBYTE   globvol;\r
+       UBYTE   mixvol;         /* mixing volume [ignored] */\r
+       UBYTE   initspeed;\r
+       UBYTE   inittempo;\r
+       UBYTE   pansep;         /* panning separation between channels */\r
+       UBYTE   zerobyte;       \r
+       UWORD   msglength;\r
+       ULONG   msgoffset;\r
+       UBYTE   blank02[4];\r
+       UBYTE   pantable[64];\r
+       UBYTE   voltable[64];\r
+} ITHEADER;\r
+\r
+/* sample information */\r
+typedef struct ITSAMPLE {\r
+       CHAR    filename[12];\r
+       UBYTE   zerobyte;\r
+       UBYTE   globvol;\r
+       UBYTE   flag;\r
+       UBYTE   volume;\r
+       UBYTE   panning;\r
+       CHAR    sampname[28];\r
+       UWORD   convert;        /* sample conversion flag */\r
+       ULONG   length;\r
+       ULONG   loopbeg;\r
+       ULONG   loopend;\r
+       ULONG   c5spd;\r
+       ULONG   susbegin;\r
+       ULONG   susend;\r
+       ULONG   sampoffset;\r
+       UBYTE   vibspeed;\r
+       UBYTE   vibdepth;\r
+       UBYTE   vibrate;\r
+       UBYTE   vibwave;        /* 0=sine, 1=rampdown, 2=square, 3=random (speed ignored) */\r
+} ITSAMPLE;\r
+\r
+/* instrument information */\r
+\r
+#define ITENVCNT 25\r
+#define ITNOTECNT 120\r
+typedef struct ITINSTHEADER {\r
+       ULONG   size;                   /* (dword) Instrument size */\r
+       CHAR    filename[12];   /* (char) Instrument filename */\r
+       UBYTE   zerobyte;               /* (byte) Instrument type (always 0) */\r
+       UBYTE   volflg;\r
+       UBYTE   volpts;   \r
+       UBYTE   volbeg;                 /* (byte) Volume loop start (node) */\r
+       UBYTE   volend;                 /* (byte) Volume loop end (node) */\r
+       UBYTE   volsusbeg;              /* (byte) Volume sustain begin (node) */\r
+       UBYTE   volsusend;              /* (byte) Volume Sustain end (node) */\r
+       UBYTE   panflg;\r
+       UBYTE   panpts;  \r
+       UBYTE   panbeg;                 /* (byte) channel loop start (node) */\r
+       UBYTE   panend;                 /* (byte) channel loop end (node) */\r
+       UBYTE   pansusbeg;              /* (byte) channel sustain begin (node) */\r
+       UBYTE   pansusend;              /* (byte) channel Sustain end (node) */\r
+       UBYTE   pitflg;\r
+       UBYTE   pitpts;   \r
+       UBYTE   pitbeg;                 /* (byte) pitch loop start (node) */\r
+       UBYTE   pitend;                 /* (byte) pitch loop end (node) */\r
+       UBYTE   pitsusbeg;              /* (byte) pitch sustain begin (node) */\r
+       UBYTE   pitsusend;              /* (byte) pitch Sustain end (node) */\r
+       UWORD   blank;\r
+       UBYTE   globvol;\r
+       UBYTE   chanpan;\r
+       UWORD   fadeout;                /* Envelope end / NNA volume fadeout */\r
+       UBYTE   dnc;                    /* Duplicate note check */\r
+       UBYTE   dca;                    /* Duplicate check action */\r
+       UBYTE   dct;                    /* Duplicate check type */\r
+       UBYTE   nna;                    /* New Note Action [0,1,2,3] */\r
+       UWORD   trkvers;                /* tracker version used to save [files only] */\r
+       UBYTE   ppsep;                  /* Pitch-pan Separation */\r
+       UBYTE   ppcenter;               /* Pitch-pan Center */\r
+       UBYTE   rvolvar;                /* random volume varations */\r
+       UBYTE   rpanvar;                /* random panning varations */\r
+       UWORD   numsmp;                 /* Number of samples in instrument [files only] */\r
+       CHAR    name[26];               /* Instrument name */\r
+       UBYTE   blank01[6];\r
+       UWORD   samptable[ITNOTECNT];/* sample for each note [note / samp pairs] */\r
+       UBYTE   volenv[200];         /* volume envelope (IT 1.x stuff) */\r
+       UBYTE   oldvoltick[ITENVCNT];/* volume tick position (IT 1.x stuff) */\r
+       UBYTE   volnode[ITENVCNT];   /* amplitude of volume nodes */\r
+       UWORD   voltick[ITENVCNT];   /* tick value of volume nodes */\r
+       SBYTE   pannode[ITENVCNT];   /* panenv - node points */\r
+       UWORD   pantick[ITENVCNT];   /* tick value of panning nodes */\r
+       SBYTE   pitnode[ITENVCNT];   /* pitchenv - node points */\r
+       UWORD   pittick[ITENVCNT];   /* tick value of pitch nodes */\r
+} ITINSTHEADER;                       \r
+\r
+/* unpacked note */\r
+\r
+typedef struct ITNOTE {\r
+       UBYTE note,ins,volpan,cmd,inf;\r
+} ITNOTE;\r
+\r
+/*========== Loader data */\r
+\r
+static ULONG *paraptr=NULL;    /* parapointer array (see IT docs) */\r
+static ITHEADER *mh=NULL;\r
+static ITNOTE *itpat=NULL;     /* allocate to space for one full pattern */\r
+static UBYTE *mask=NULL;       /* arrays allocated to 64 elements and used for */\r
+static ITNOTE *last=NULL;      /* uncompressing IT's pattern information */\r
+static int numtrk=0;\r
+static unsigned int old_effect;                /* if set, use S3M old-effects stuffs */\r
+   \r
+static CHAR* IT_Version[]={\r
+       "ImpulseTracker  .  ",\r
+       "Compressed ImpulseTracker  .  ",\r
+       "ImpulseTracker 2.14p3",\r
+       "Compressed ImpulseTracker 2.14p3",\r
+       "ImpulseTracker 2.14p4",\r
+       "Compressed ImpulseTracker 2.14p4",\r
+};\r
+\r
+/* table for porta-to-note command within volume/panning column */\r
+static UBYTE portatable[10]= {0,1,4,8,16,32,64,96,128,255};\r
+\r
+/*========== Loader code */\r
+\r
+BOOL IT_Test(void)\r
+{\r
+       UBYTE id[4];\r
+\r
+       if(!_mm_read_UBYTES(id,4,modreader)) return 0;\r
+       if(!memcmp(id,"IMPM",4)) return 1;\r
+       return 0;\r
+}\r
+\r
+BOOL IT_Init(void)\r
+{\r
+       if(!(mh=(ITHEADER*)_mm_malloc(sizeof(ITHEADER)))) return 0;\r
+       if(!(poslookup=(UBYTE*)_mm_malloc(256*sizeof(UBYTE)))) return 0;\r
+       if(!(itpat=(ITNOTE*)_mm_malloc(200*64*sizeof(ITNOTE)))) return 0;\r
+       if(!(mask=(UBYTE*)_mm_malloc(64*sizeof(UBYTE)))) return 0;\r
+       if(!(last=(ITNOTE*)_mm_malloc(64*sizeof(ITNOTE)))) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+void IT_Cleanup(void)\r
+{\r
+       FreeLinear();\r
+\r
+       _mm_free(mh);\r
+       _mm_free(poslookup);\r
+       _mm_free(itpat);\r
+       _mm_free(mask);\r
+       _mm_free(last);\r
+       _mm_free(paraptr);\r
+       _mm_free(origpositions);\r
+}\r
+\r
+/* Because so many IT files have 64 channels as the set number used, but really\r
+   only use far less (usually from 8 to 24 still), I had to make this function,\r
+   which determines the number of channels that are actually USED by a pattern.\r
\r
+   NOTE: You must first seek to the file location of the pattern before calling\r
+         this procedure.\r
+\r
+   Returns 1 on error\r
+*/\r
+static BOOL IT_GetNumChannels(UWORD patrows)\r
+{\r
+       int row=0,flag,ch;\r
+\r
+       do {\r
+               if((flag=_mm_read_UBYTE(modreader))==EOF) {\r
+                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                       return 1;\r
+               }\r
+               if(!flag)\r
+                       row++;\r
+               else {\r
+                       ch=(flag-1)&63;\r
+                       remap[ch]=0;\r
+                       if(flag & 128) mask[ch]=_mm_read_UBYTE(modreader);\r
+                       if(mask[ch]&1)   _mm_read_UBYTE(modreader);\r
+                       if(mask[ch]&2)   _mm_read_UBYTE(modreader);\r
+                       if(mask[ch]&4)   _mm_read_UBYTE(modreader);\r
+                       if(mask[ch]&8) { _mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader); }\r
+               }\r
+       } while(row<patrows);\r
+\r
+       return 0;\r
+}\r
+\r
+static UBYTE* IT_ConvertTrack(ITNOTE* tr,UWORD numrows)\r
+{\r
+       int t;\r
+       UBYTE note,ins,volpan;\r
+\r
+       UniReset();\r
+\r
+       for(t=0;t<numrows;t++) {\r
+               note=tr[t*of.numchn].note;\r
+               ins=tr[t*of.numchn].ins;\r
+               volpan=tr[t*of.numchn].volpan;\r
+\r
+               if(note!=255) {\r
+                       if(note==253)\r
+                               UniWriteByte(UNI_KEYOFF);\r
+                       else if(note==254) {\r
+                               UniPTEffect(0xc,-1);    /* note cut command */\r
+                               volpan=255;\r
+                       } else\r
+                               UniNote(note);\r
+               }\r
+\r
+               if((ins)&&(ins<100))\r
+                       UniInstrument(ins-1);\r
+               else if(ins==253)\r
+                       UniWriteByte(UNI_KEYOFF);\r
+               else if(ins!=255) { /* crap */\r
+                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                       return NULL;\r
+               }\r
+\r
+               /* process volume / panning column\r
+                  volume / panning effects do NOT all share the same memory address\r
+                  yet. */\r
+               if(volpan<=64) \r
+                       UniVolEffect(VOL_VOLUME,volpan);\r
+               else if(volpan==65) /* fine volume slide up (65-74) - A0 case */\r
+                       UniVolEffect(VOL_VOLSLIDE,0);\r
+               else if(volpan<=74)     { /* fine volume slide up (65-74) - general case */\r
+                       UniVolEffect(VOL_VOLSLIDE,0x0f+((volpan-65)<<4));\r
+               } else if(volpan==75)   /* fine volume slide down (75-84) - B0 case */\r
+                       UniVolEffect(VOL_VOLSLIDE,0);\r
+               else if(volpan<=84) {   /* fine volume slide down (75-84) - general case*/\r
+                       UniVolEffect(VOL_VOLSLIDE,0xf0+(volpan-75));\r
+               } else if(volpan<=94)   /* volume slide up (85-94) */\r
+                       UniVolEffect(VOL_VOLSLIDE,((volpan-85)<<4));\r
+               else if(volpan<=104)/* volume slide down (95-104) */\r
+                       UniVolEffect(VOL_VOLSLIDE,(volpan-95));\r
+               else if(volpan<=114)/* pitch slide down (105-114) */\r
+                       UniVolEffect(VOL_PITCHSLIDEDN,(volpan-105));\r
+               else if(volpan<=124)/* pitch slide up (115-124) */\r
+                       UniVolEffect(VOL_PITCHSLIDEUP,(volpan-115));\r
+               else if(volpan<=127) { /* crap */\r
+                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                       return NULL;\r
+               } else if(volpan<=192)\r
+                       UniVolEffect(VOL_PANNING,((volpan-128)==64)?255:((volpan-128)<<2));\r
+               else if(volpan<=202)/* portamento to note */\r
+                       UniVolEffect(VOL_PORTAMENTO,portatable[volpan-193]);\r
+               else if(volpan<=212)/* vibrato */\r
+                       UniVolEffect(VOL_VIBRATO,(volpan-203));\r
+               else if((volpan!=239)&&(volpan!=255)) { /* crap */\r
+                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                       return NULL;\r
+               }\r
+\r
+               S3MIT_ProcessCmd(tr[t*of.numchn].cmd,tr[t*of.numchn].inf,\r
+                   old_effect|S3MIT_IT);\r
+\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+static BOOL IT_ReadPattern(UWORD patrows)\r
+{\r
+       int row=0,flag,ch,blah;\r
+       ITNOTE *itt=itpat,dummy,*n,*l;\r
+\r
+       memset(itt,255,200*64*sizeof(ITNOTE));\r
+\r
+       do {\r
+               if((flag=_mm_read_UBYTE(modreader))==EOF) {\r
+                       _mm_errno = MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+               if(!flag) {\r
+                       itt=&itt[of.numchn];\r
+                       row++;\r
+               } else {\r
+                       ch=remap[(flag-1)&63];\r
+                       if(ch!=-1) {\r
+                               n=&itt[ch];\r
+                               l=&last[ch];\r
+                       } else \r
+                               n=l=&dummy;\r
+\r
+                       if(flag&128) mask[ch]=_mm_read_UBYTE(modreader);\r
+                       if(mask[ch]&1)\r
+                               /* convert IT note off to internal note off */\r
+                               if((l->note=n->note=_mm_read_UBYTE(modreader))==255) \r
+                                       l->note=n->note=253;\r
+                       if(mask[ch]&2)\r
+                               l->ins=n->ins=_mm_read_UBYTE(modreader);\r
+                       if(mask[ch]&4)\r
+                               l->volpan=n->volpan=_mm_read_UBYTE(modreader);\r
+                       if(mask[ch]&8) {\r
+                               l->cmd=n->cmd=_mm_read_UBYTE(modreader);\r
+                               l->inf=n->inf=_mm_read_UBYTE(modreader);\r
+                       }\r
+                       if(mask[ch]&16)\r
+                               n->note=l->note;\r
+                       if(mask[ch]&32)\r
+                               n->ins=l->ins;\r
+                       if(mask[ch]&64)\r
+                               n->volpan=l->volpan;\r
+                       if(mask[ch]&128) {\r
+                               n->cmd=l->cmd;\r
+                               n->inf=l->inf;\r
+                       }\r
+               }\r
+       } while(row<patrows);\r
+\r
+       for(blah=0;blah<of.numchn;blah++) {\r
+               if(!(of.tracks[numtrk++]=IT_ConvertTrack(&itpat[blah],patrows)))\r
+                       return 0;\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+static void LoadMidiString(MREADER* modreader,CHAR* dest)\r
+{\r
+       CHAR *cur,*last;\r
+\r
+       _mm_read_UBYTES(dest,32,modreader);\r
+       cur=last=dest;\r
+       /* remove blanks and uppercase all */\r
+       while(*last) {\r
+               if(isalnum((int)*last)) *(cur++)=toupper((int)*last);\r
+               last++;\r
+       }\r
+       *cur=0;\r
+}\r
+\r
+/* Load embedded midi information for resonant filters */\r
+static void IT_LoadMidiConfiguration(MREADER* modreader)\r
+{\r
+       int i;\r
+\r
+       memset(filtermacros,0,sizeof(filtermacros));\r
+       memset(filtersettings,0,sizeof(filtersettings));\r
+\r
+       if (modreader) { /* information is embedded in file */\r
+               UWORD dat;\r
+               CHAR midiline[33];\r
+\r
+               dat=_mm_read_I_UWORD(modreader);\r
+               _mm_fseek(modreader,8*dat+0x120,SEEK_CUR);\r
+\r
+               /* read midi macros */\r
+               for(i=0;i<UF_MAXMACRO;i++) {\r
+                       LoadMidiString(modreader,midiline);\r
+                       if((!strncmp(midiline,"F0F00",5))&&\r
+                          ((midiline[5]=='0')||(midiline[5]=='1')))\r
+                                       filtermacros[i]=(midiline[5]-'0')|0x80;\r
+               }\r
+\r
+               /* read standalone filters */\r
+               for(i=0x80;i<0x100;i++) {\r
+                       LoadMidiString(modreader,midiline);\r
+                       if((!strncmp(midiline,"F0F00",5))&&\r
+                          ((midiline[5]=='0')||(midiline[5]=='1'))) {\r
+                               filtersettings[i].filter=(midiline[5]-'0')|0x80;\r
+                               dat=(midiline[6])?(midiline[6]-'0'):0;\r
+                               if(midiline[7])dat=(dat<<4)|(midiline[7]-'0');\r
+                               filtersettings[i].inf=dat;\r
+                       }\r
+               }\r
+       } else { /* use default information */\r
+               filtermacros[0]=FILT_CUT;\r
+               for(i=0x80;i<0x90;i++) {\r
+                       filtersettings[i].filter=FILT_RESONANT;\r
+                       filtersettings[i].inf=(i&0x7f)<<3;\r
+               }\r
+       }\r
+       activemacro=0;\r
+       for(i=0;i<0x80;i++) {\r
+               filtersettings[i].filter=filtermacros[0];\r
+               filtersettings[i].inf=i;\r
+       }\r
+}\r
+\r
+BOOL IT_Load(BOOL curious)\r
+{\r
+       int t,u,lp;\r
+       INSTRUMENT *d;\r
+       SAMPLE *q;\r
+       BOOL compressed=0;\r
+\r
+       numtrk=0;\r
+       filters=0;\r
+\r
+       /* try to read module header */\r
+       _mm_read_I_ULONG(modreader);    /* kill the 4 byte header */\r
+       _mm_read_string(mh->songname,26,modreader);\r
+       _mm_read_UBYTES(mh->blank01,2,modreader);\r
+       mh->ordnum      =_mm_read_I_UWORD(modreader);\r
+       mh->insnum      =_mm_read_I_UWORD(modreader);\r
+       mh->smpnum      =_mm_read_I_UWORD(modreader);\r
+       mh->patnum      =_mm_read_I_UWORD(modreader);\r
+       mh->cwt         =_mm_read_I_UWORD(modreader);\r
+       mh->cmwt        =_mm_read_I_UWORD(modreader);\r
+       mh->flags       =_mm_read_I_UWORD(modreader);\r
+       mh->special     =_mm_read_I_UWORD(modreader);\r
+       mh->globvol     =_mm_read_UBYTE(modreader);\r
+       mh->mixvol      =_mm_read_UBYTE(modreader);\r
+       mh->initspeed   =_mm_read_UBYTE(modreader);\r
+       mh->inittempo   =_mm_read_UBYTE(modreader);\r
+       mh->pansep      =_mm_read_UBYTE(modreader);\r
+       mh->zerobyte    =_mm_read_UBYTE(modreader);\r
+       mh->msglength   =_mm_read_I_UWORD(modreader);\r
+       mh->msgoffset   =_mm_read_I_ULONG(modreader);\r
+       _mm_read_UBYTES(mh->blank02,4,modreader);\r
+       _mm_read_UBYTES(mh->pantable,64,modreader);\r
+       _mm_read_UBYTES(mh->voltable,64,modreader);\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno=MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* set module variables */\r
+       of.songname    = DupStr(mh->songname,26,0); /* make a cstr of songname  */\r
+       of.reppos      = 0;\r
+       of.numpat      = mh->patnum;\r
+       of.numins      = mh->insnum;\r
+       of.numsmp      = mh->smpnum;\r
+       of.initspeed   = mh->initspeed;\r
+       of.inittempo   = mh->inittempo;\r
+       of.initvolume  = mh->globvol;\r
+       of.flags      |= UF_BGSLIDES | UF_ARPMEM;\r
+       if (!(mh->flags & 1))\r
+                       of.flags |= UF_PANNING;\r
+       of.bpmlimit=32;\r
+\r
+       if(mh->songname[25]) {\r
+               of.numvoices=1+mh->songname[25];\r
+#ifdef MIKMOD_DEBUG\r
+               fprintf(stderr,"Embedded IT limitation to %d voices\n",of.numvoices);\r
+#endif\r
+       }\r
+\r
+       /* set the module type */\r
+       /* 2.17 : IT 2.14p4 */\r
+       /* 2.16 : IT 2.14p3 with resonant filters */\r
+       /* 2.15 : IT 2.14p3 (improved compression) */\r
+       if((mh->cwt<=0x219)&&(mh->cwt>=0x217))\r
+               of.modtype=strdup(IT_Version[mh->cmwt<0x214?4:5]);\r
+       else if (mh->cwt>=0x215)\r
+               of.modtype=strdup(IT_Version[mh->cmwt<0x214?2:3]);\r
+       else {\r
+               of.modtype     = strdup(IT_Version[mh->cmwt<0x214?0:1]);\r
+               of.modtype[mh->cmwt<0x214?15:26] = (mh->cwt>>8)+'0';\r
+               of.modtype[mh->cmwt<0x214?17:28] = ((mh->cwt>>4)&0xf)+'0';\r
+               of.modtype[mh->cmwt<0x214?18:29] = ((mh->cwt)&0xf)+'0';\r
+       }\r
+\r
+       if(mh->flags&8)\r
+               of.flags |= UF_XMPERIODS | UF_LINEAR;\r
+\r
+       if((mh->cwt>=0x106)&&(mh->flags&16))\r
+               old_effect=S3MIT_OLDSTYLE;\r
+       else\r
+               old_effect=0;\r
+\r
+       /* set panning positions */\r
+       if (mh->flags & 1)\r
+               for(t=0;t<64;t++) {\r
+                       mh->pantable[t]&=0x7f;\r
+                       if(mh->pantable[t]<64)\r
+                               of.panning[t]=mh->pantable[t]<<2;\r
+                       else if(mh->pantable[t]==64)\r
+                               of.panning[t]=255;\r
+                       else if(mh->pantable[t]==100)\r
+                               of.panning[t]=PAN_SURROUND;\r
+                       else if(mh->pantable[t]==127)\r
+                               of.panning[t]=PAN_CENTER;\r
+                       else {\r
+                               _mm_errno=MMERR_LOADING_HEADER;\r
+                               return 0;\r
+                       }\r
+               }\r
+       else\r
+               for(t=0;t<64;t++)\r
+                       of.panning[t]=PAN_CENTER;\r
+\r
+       /* set channel volumes */\r
+       memcpy(of.chanvol,mh->voltable,64);\r
+\r
+       /* read the order data */\r
+       if(!AllocPositions(mh->ordnum)) return 0;\r
+       if(!(origpositions=_mm_calloc(mh->ordnum,sizeof(UWORD)))) return 0;\r
+\r
+       for(t=0;t<mh->ordnum;t++) {\r
+               origpositions[t]=_mm_read_UBYTE(modreader);\r
+               if((origpositions[t]>mh->patnum)&&(origpositions[t]<254))\r
+                       origpositions[t]=255;\r
+       }\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       poslookupcnt=mh->ordnum;\r
+       S3MIT_CreateOrders(curious);\r
+\r
+       if(!(paraptr=(ULONG*)_mm_malloc((mh->insnum+mh->smpnum+of.numpat)*\r
+                                      sizeof(ULONG)))) return 0;\r
+\r
+       /* read the instrument, sample, and pattern parapointers */\r
+       _mm_read_I_ULONGS(paraptr,mh->insnum+mh->smpnum+of.numpat,modreader);\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* Check for and load midi information for resonant filters */\r
+       if(mh->cmwt>=0x216) {\r
+               if(mh->special&8) {\r
+                       IT_LoadMidiConfiguration(modreader);\r
+                       if(_mm_eof(modreader)) {\r
+                               _mm_errno = MMERR_LOADING_HEADER;\r
+                               return 0;\r
+                       }\r
+               } else\r
+                       IT_LoadMidiConfiguration(NULL);\r
+               filters=1;\r
+       }\r
+\r
+       /* Check for and load song comment */\r
+       if((mh->special&1)&&(mh->cwt>=0x104)&&(mh->msglength)) {\r
+               _mm_fseek(modreader,(long)(mh->msgoffset),SEEK_SET);\r
+               if(!ReadComment(mh->msglength)) return 0;\r
+       }\r
+\r
+       if(!(mh->flags&4)) of.numins=of.numsmp;\r
+       if(!AllocSamples()) return 0;\r
+\r
+       if(!AllocLinear()) return 0;\r
+\r
+       /* Load all samples */\r
+       q = of.samples;\r
+       for(t=0;t<mh->smpnum;t++) {\r
+               ITSAMPLE s;\r
+\r
+               /* seek to sample position */\r
+               _mm_fseek(modreader,(long)(paraptr[mh->insnum+t]+4),SEEK_SET);\r
+\r
+               /* load sample info */\r
+               _mm_read_string(s.filename,12,modreader);\r
+               s.zerobyte    = _mm_read_UBYTE(modreader);\r
+               s.globvol     = _mm_read_UBYTE(modreader);\r
+               s.flag        = _mm_read_UBYTE(modreader);\r
+               s.volume      = _mm_read_UBYTE(modreader);\r
+               _mm_read_string(s.sampname,26,modreader);\r
+               s.convert     = _mm_read_UBYTE(modreader);\r
+               s.panning     = _mm_read_UBYTE(modreader);\r
+               s.length      = _mm_read_I_ULONG(modreader);\r
+               s.loopbeg     = _mm_read_I_ULONG(modreader);\r
+               s.loopend     = _mm_read_I_ULONG(modreader);\r
+               s.c5spd       = _mm_read_I_ULONG(modreader);\r
+               s.susbegin    = _mm_read_I_ULONG(modreader);\r
+               s.susend      = _mm_read_I_ULONG(modreader);\r
+               s.sampoffset  = _mm_read_I_ULONG(modreader);\r
+               s.vibspeed    = _mm_read_UBYTE(modreader);\r
+               s.vibdepth    = _mm_read_UBYTE(modreader);\r
+               s.vibrate     = _mm_read_UBYTE(modreader);\r
+               s.vibwave     = _mm_read_UBYTE(modreader);\r
+\r
+               /* Generate an error if c5spd is > 512k, or samplelength > 256 megs\r
+                  (nothing would EVER be that high) */\r
+\r
+               if(_mm_eof(modreader)||(s.c5spd>0x7ffffL)||(s.length>0xfffffffUL)) {\r
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                       return 0;\r
+               }\r
+\r
+               /* Reality check for sample loop information */\r
+               if((s.flag&16)&&\r
+                  ((s.loopbeg>0xfffffffUL)||(s.loopend>0xfffffffUL))) {\r
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                       return 0;\r
+               }\r
+\r
+               q->samplename = DupStr(s.sampname,26,0);\r
+               q->speed      = s.c5spd / 2;\r
+               q->panning    = ((s.panning&127)==64)?255:(s.panning&127)<<2;\r
+               q->length     = s.length;\r
+               q->loopstart  = s.loopbeg;\r
+               q->loopend    = s.loopend;\r
+               q->volume     = s.volume;\r
+               q->globvol    = s.globvol;\r
+               q->seekpos    = s.sampoffset;\r
+\r
+               /* Convert speed to XM linear finetune */\r
+               if(of.flags&UF_LINEAR)\r
+                       q->speed=speed_to_finetune(s.c5spd,t);\r
+\r
+               if(s.panning&128) q->flags|=SF_OWNPAN;\r
+\r
+               if(s.vibrate) {\r
+                       q->vibflags |= AV_IT;\r
+                       q->vibtype   = s.vibwave;\r
+                       q->vibsweep  = s.vibrate * 2;\r
+                       q->vibdepth  = s.vibdepth;\r
+                       q->vibrate   = s.vibspeed;\r
+               }\r
+\r
+               if(s.flag&2) q->flags|=SF_16BITS;\r
+               if((s.flag&8)&&(mh->cwt>=0x214)) {\r
+                       q->flags|=SF_ITPACKED;\r
+                       compressed=1;\r
+               }\r
+               if(s.flag&16) q->flags|=SF_LOOP;\r
+               if(s.flag&64) q->flags|=SF_BIDI;\r
+\r
+               if(mh->cwt>=0x200) {\r
+                       if(s.convert&1) q->flags|=SF_SIGNED;\r
+                       if(s.convert&4) q->flags|=SF_DELTA;   \r
+               }\r
+               q++;\r
+       }\r
+\r
+       /* Load instruments if instrument mode flag enabled */\r
+       if(mh->flags&4) {\r
+               if(!AllocInstruments()) return 0;\r
+               d=of.instruments;\r
+               of.flags|=UF_NNA|UF_INST;\r
+\r
+               for(t=0;t<mh->insnum;t++) {\r
+                       ITINSTHEADER ih;\r
+\r
+                       /* seek to instrument position */\r
+                       _mm_fseek(modreader,paraptr[t]+4,SEEK_SET);\r
+\r
+                       /* load instrument info */\r
+                       _mm_read_string(ih.filename,12,modreader);\r
+                       ih.zerobyte  = _mm_read_UBYTE(modreader);\r
+                       if(mh->cwt<0x200) {\r
+                               /* load IT 1.xx inst header */\r
+                               ih.volflg    = _mm_read_UBYTE(modreader);\r
+                               ih.volbeg    = _mm_read_UBYTE(modreader);\r
+                               ih.volend    = _mm_read_UBYTE(modreader);\r
+                               ih.volsusbeg = _mm_read_UBYTE(modreader);\r
+                               ih.volsusend = _mm_read_UBYTE(modreader);\r
+                               _mm_read_I_UWORD(modreader);\r
+                               ih.fadeout   = _mm_read_I_UWORD(modreader);\r
+                               ih.nna       = _mm_read_UBYTE(modreader);\r
+                               ih.dnc       = _mm_read_UBYTE(modreader);\r
+                       } else {\r
+                               /* Read IT200+ header */\r
+                               ih.nna       = _mm_read_UBYTE(modreader);\r
+                               ih.dct       = _mm_read_UBYTE(modreader);\r
+                               ih.dca       = _mm_read_UBYTE(modreader);\r
+                               ih.fadeout   = _mm_read_I_UWORD(modreader);\r
+                               ih.ppsep     = _mm_read_UBYTE(modreader);\r
+                               ih.ppcenter  = _mm_read_UBYTE(modreader);\r
+                               ih.globvol   = _mm_read_UBYTE(modreader);\r
+                               ih.chanpan   = _mm_read_UBYTE(modreader);\r
+                               ih.rvolvar   = _mm_read_UBYTE(modreader);\r
+                               ih.rpanvar   = _mm_read_UBYTE(modreader);\r
+                       }\r
+\r
+                       ih.trkvers   = _mm_read_I_UWORD(modreader);\r
+                       ih.numsmp    = _mm_read_UBYTE(modreader);\r
+                       _mm_read_UBYTE(modreader);\r
+                       _mm_read_string(ih.name,26,modreader);\r
+                       _mm_read_UBYTES(ih.blank01,6,modreader);\r
+                       _mm_read_I_UWORDS(ih.samptable,ITNOTECNT,modreader);\r
+                       if(mh->cwt<0x200) {\r
+                               /* load IT 1xx volume envelope */\r
+                               _mm_read_UBYTES(ih.volenv,200,modreader);\r
+                               for(lp=0;lp<ITENVCNT;lp++) {\r
+                                       ih.oldvoltick[lp] = _mm_read_UBYTE(modreader);\r
+                                       ih.volnode[lp]    = _mm_read_UBYTE(modreader);\r
+                               } \r
+                       } else {\r
+                               /* load IT 2xx volume, pan and pitch envelopes */\r
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
+#define IT_LoadEnvelope(name,type)                                                                             \\r
+                               ih. name##flg   =_mm_read_UBYTE(modreader);                             \\r
+                               ih. name##pts   =_mm_read_UBYTE(modreader);                             \\r
+                               ih. name##beg   =_mm_read_UBYTE(modreader);                             \\r
+                               ih. name##end   =_mm_read_UBYTE(modreader);                             \\r
+                               ih. name##susbeg=_mm_read_UBYTE(modreader);                             \\r
+                               ih. name##susend=_mm_read_UBYTE(modreader);                             \\r
+                               for(lp=0;lp<ITENVCNT;lp++) {                                                    \\r
+                                       ih. name##node[lp]=_mm_read_##type (modreader);         \\r
+                                       ih. name##tick[lp]=_mm_read_I_UWORD(modreader);         \\r
+                               }                                                                                                               \\r
+                               _mm_read_UBYTE(modreader)\r
+#else\r
+#define IT_LoadEnvelope(name,type)                                                                             \\r
+                               ih. name/**/flg   =_mm_read_UBYTE(modreader);                   \\r
+                               ih. name/**/pts   =_mm_read_UBYTE(modreader);                   \\r
+                               ih. name/**/beg   =_mm_read_UBYTE(modreader);                   \\r
+                               ih. name/**/end   =_mm_read_UBYTE(modreader);                   \\r
+                               ih. name/**/susbeg=_mm_read_UBYTE(modreader);                   \\r
+                               ih. name/**/susend=_mm_read_UBYTE(modreader);                   \\r
+                               for(lp=0;lp<ITENVCNT;lp++) {                                                    \\r
+                                       ih. name/**/node[lp]=_mm_read_/**/type (modreader);     \\r
+                                       ih. name/**/tick[lp]=_mm_read_I_UWORD(modreader);       \\r
+                               }                                                                                                               \\r
+                               _mm_read_UBYTE(modreader)\r
+#endif\r
+\r
+                               IT_LoadEnvelope(vol,UBYTE);\r
+                               IT_LoadEnvelope(pan,SBYTE);\r
+                               IT_LoadEnvelope(pit,SBYTE);\r
+#undef IT_LoadEnvelope\r
+                       }\r
\r
+                       if(_mm_eof(modreader)) {\r
+                               _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                               return 0;\r
+                       }\r
+\r
+                       d->volflg|=EF_VOLENV;\r
+                       d->insname = DupStr(ih.name,26,0);\r
+                       d->nnatype = ih.nna & NNA_MASK;\r
+\r
+                       if(mh->cwt<0x200) {\r
+                               d->volfade=ih.fadeout<< 6;\r
+                               if(ih.dnc) {\r
+                                       d->dct=DCT_NOTE;\r
+                                       d->dca=DCA_CUT;\r
+                               }\r
+\r
+                               if(ih.volflg&1) d->volflg|=EF_ON;\r
+                               if(ih.volflg&2) d->volflg|=EF_LOOP;\r
+                               if(ih.volflg&4) d->volflg|=EF_SUSTAIN;      \r
+\r
+                               /* XM conversion of IT envelope Array */\r
+                               d->volbeg    = ih.volbeg;   \r
+                               d->volend    = ih.volend;\r
+                               d->volsusbeg = ih.volsusbeg;\r
+                               d->volsusend = ih.volsusend;\r
+\r
+                               if(ih.volflg&1) {\r
+                                       for(u=0;u<ITENVCNT;u++)\r
+                                               if(ih.oldvoltick[d->volpts]!=0xff) {\r
+                                                       d->volenv[d->volpts].val=(ih.volnode[d->volpts]<<2);\r
+                                                       d->volenv[d->volpts].pos=ih.oldvoltick[d->volpts];\r
+                                                       d->volpts++;\r
+                                               } else\r
+                                                       break;\r
+                               }  \r
+                       } else {\r
+                               d->panning=((ih.chanpan&127)==64)?255:(ih.chanpan&127)<<2;\r
+                               if(!(ih.chanpan&128)) d->flags|=IF_OWNPAN;\r
+\r
+                               if(!(ih.ppsep & 128)) {\r
+                                       d->pitpansep=ih.ppsep<<2;\r
+                                       d->pitpancenter=ih.ppcenter;\r
+                                       d->flags|=IF_PITCHPAN;\r
+                               }\r
+                               d->globvol=ih.globvol>>1;\r
+                               d->volfade=ih.fadeout<<5;\r
+                               d->dct    =ih.dct;\r
+                               d->dca    =ih.dca;\r
+\r
+                               if(mh->cwt>=0x204) {\r
+                                       d->rvolvar = ih.rvolvar;\r
+                                       d->rpanvar = ih.rpanvar;\r
+                               }\r
+\r
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
+#define IT_ProcessEnvelope(name)                                                                               \\r
+                               if(ih. name##flg&1) d-> name##flg|=EF_ON;                               \\r
+                               if(ih. name##flg&2) d-> name##flg|=EF_LOOP;                             \\r
+                               if(ih. name##flg&4) d-> name##flg|=EF_SUSTAIN;                  \\r
+                               d-> name##pts=ih. name##pts;                                                    \\r
+                               d-> name##beg=ih. name##beg;                                                    \\r
+                               d-> name##end=ih. name##end;                                                    \\r
+                               d-> name##susbeg=ih. name##susbeg;                                              \\r
+                               d-> name##susend=ih. name##susend;                                              \\r
+                                                                                                                                               \\r
+                               for(u=0;u<ih. name##pts;u++)                                                    \\r
+                                       d-> name##env[u].pos=ih. name##tick[u];                         \\r
+                                                                                                                                               \\r
+                               if((d-> name##flg&EF_ON)&&(d-> name##pts<2))                    \\r
+                                       d-> name##flg&=~EF_ON\r
+#else\r
+#define IT_ProcessEnvelope(name)                                                                       \\r
+                               if(ih. name/**/flg&1) d-> name/**/flg|=EF_ON;           \\r
+                               if(ih. name/**/flg&2) d-> name/**/flg|=EF_LOOP;         \\r
+                               if(ih. name/**/flg&4) d-> name/**/flg|=EF_SUSTAIN;      \\r
+                               d-> name/**/pts=ih. name/**/pts;                                        \\r
+                               d-> name/**/beg=ih. name/**/beg;                                        \\r
+                               d-> name/**/end=ih. name/**/end;                                        \\r
+                               d-> name/**/susbeg=ih. name/**/susbeg;                          \\r
+                               d-> name/**/susend=ih. name/**/susend;                          \\r
+                                                                                                                                       \\r
+                               for(u=0;u<ih. name/**/pts;u++)                                          \\r
+                                       d-> name/**/env[u].pos=ih. name/**/tick[u];             \\r
+                                                                                                                                       \\r
+                               if((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2))        \\r
+                                       d-> name/**/flg&=~EF_ON\r
+#endif\r
+\r
+                               IT_ProcessEnvelope(vol);\r
+                               for(u=0;u<ih.volpts;u++)\r
+                                       d->volenv[u].val=(ih.volnode[u]<<2);\r
+\r
+                               IT_ProcessEnvelope(pan);\r
+                               for(u=0;u<ih.panpts;u++)\r
+                                       d->panenv[u].val=\r
+                                         ih.pannode[u]==32?255:(ih.pannode[u]+32)<<2;\r
+\r
+                               IT_ProcessEnvelope(pit);\r
+                               for(u=0;u<ih.pitpts;u++)\r
+                                       d->pitenv[u].val=ih.pitnode[u]+32;\r
+#undef IT_ProcessEnvelope\r
+\r
+                               if(ih.pitflg&0x80) {\r
+                                       /* filter envelopes not supported yet */\r
+                                       d->pitflg&=~EF_ON;\r
+                                       ih.pitpts=ih.pitbeg=ih.pitend=0;\r
+#ifdef MIKMOD_DEBUG\r
+                                       {\r
+                                               static int warn=0;\r
+                                               \r
+                                               if(!warn)\r
+                                                       fprintf(stderr, "\rFilter envelopes not supported yet\n");\r
+                                               warn=1;\r
+                                       }\r
+#endif\r
+                               }\r
+                       }\r
+\r
+                       for(u=0;u<ITNOTECNT;u++) {\r
+                               d->samplenote[u]=(ih.samptable[u]&255);\r
+                               d->samplenumber[u]=\r
+                                 (ih.samptable[u]>>8)?((ih.samptable[u]>>8)-1):0xffff;\r
+                               if(d->samplenumber[u]>=of.numsmp)\r
+                                       d->samplenote[u]=255;\r
+                               else if (of.flags&UF_LINEAR) {\r
+                                       int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]];\r
+                                       d->samplenote[u]=(note<0)?0:(note>255?255:note);\r
+                               }\r
+                       }\r
+\r
+                       d++;                  \r
+               }\r
+       } else if(of.flags & UF_LINEAR) {\r
+               if(!AllocInstruments()) return 0;\r
+               d=of.instruments;\r
+               of.flags|=UF_INST;\r
+\r
+               for(t=0;t<mh->smpnum;t++,d++)\r
+                       for(u=0;u<ITNOTECNT;u++) {\r
+                               if(d->samplenumber[u]>=of.numsmp)\r
+                                       d->samplenote[u]=255;\r
+                               else {\r
+                                       int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]];\r
+                                       d->samplenote[u]=(note<0)?0:(note>255?255:note);\r
+                               }\r
+                       }\r
+       }\r
+\r
+       /* Figure out how many channels this song actually uses */\r
+       of.numchn=0;\r
+       memset(remap,-1,UF_MAXCHAN*sizeof(UBYTE));\r
+       for(t=0;t<of.numpat;t++) {\r
+               UWORD packlen;\r
+\r
+               /* seek to pattern position */\r
+               if(paraptr[mh->insnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */\r
+                       _mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET);\r
+                       _mm_read_I_UWORD(modreader);\r
+                       /* read pattern length (# of rows)\r
+                          Impulse Tracker never creates patterns with less than 32 rows,\r
+                          but some other trackers do, so we only check for more than 256\r
+                          rows */\r
+                       packlen=_mm_read_I_UWORD(modreader);\r
+                       if(packlen>256) {\r
+                               _mm_errno=MMERR_LOADING_PATTERN;\r
+                               return 0;\r
+                       }\r
+                       _mm_read_I_ULONG(modreader);\r
+                       if(IT_GetNumChannels(packlen)) return 0;\r
+               }\r
+       }\r
+\r
+       /* give each of them a different number */\r
+       for(t=0;t<UF_MAXCHAN;t++) \r
+               if(!remap[t])\r
+                       remap[t]=of.numchn++;\r
+\r
+       of.numtrk = of.numpat*of.numchn;\r
+       if(of.numvoices)\r
+               if (of.numvoices<of.numchn) of.numvoices=of.numchn;\r
+\r
+       if(!AllocPatterns()) return 0;\r
+       if(!AllocTracks()) return 0;\r
+\r
+       for(t=0;t<of.numpat;t++) {\r
+               UWORD packlen;\r
+\r
+               /* seek to pattern position */\r
+               if(!paraptr[mh->insnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */\r
+                       of.pattrows[t]=64;\r
+                       for(u=0;u<of.numchn;u++) {\r
+                               int k;\r
+\r
+                               UniReset();\r
+                               for(k=0;k<64;k++) UniNewline();\r
+                               of.tracks[numtrk++]=UniDup();\r
+                       }\r
+               } else {\r
+                       _mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET);\r
+                       packlen=_mm_read_I_UWORD(modreader);\r
+                       of.pattrows[t]=_mm_read_I_UWORD(modreader);\r
+                       _mm_read_I_ULONG(modreader);\r
+                       if(!IT_ReadPattern(of.pattrows[t])) return 0;\r
+               }\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+CHAR *IT_LoadTitle(void)\r
+{\r
+       CHAR s[26];\r
+\r
+       _mm_fseek(modreader,4,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,26,modreader)) return NULL;\r
+   \r
+       return(DupStr(s,26,0));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_it={\r
+       NULL,\r
+       "IT",\r
+       "IT (Impulse Tracker)",\r
+       IT_Init,\r
+       IT_Test,\r
+       IT_Load,\r
+       IT_Cleanup,\r
+       IT_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r