Logo Search packages:      
Sourcecode: ia32-libs-sdl version File versions  Download package

load_it.c

/*    MikMod sound library
      (c) 1998, 1999, 2000 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.6 2001/09/11 18:49:18 slouken Exp $

  Impulse tracker (IT) module loader

==============================================================================*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <ctype.h>
#include <string.h>

#include "mikmod_internals.h"

/*========== 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 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 */

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;
}

BOOL IT_Init(void)
{
      if(!(mh=(ITHEADER*)_mm_malloc(sizeof(ITHEADER)))) return 0;
      if(!(poslookup=(UBYTE*)_mm_malloc(256*sizeof(UBYTE)))) return 0;
      if(!(itpat=(ITNOTE*)_mm_malloc(200*64*sizeof(ITNOTE)))) return 0;
      if(!(mask=(UBYTE*)_mm_malloc(64*sizeof(UBYTE)))) return 0;
      if(!(last=(ITNOTE*)_mm_malloc(64*sizeof(ITNOTE)))) return 0;

      return 1;
}

void IT_Cleanup(void)
{
      FreeLinear();

      _mm_free(mh);
      _mm_free(poslookup);
      _mm_free(itpat);
      _mm_free(mask);
      _mm_free(last);
      _mm_free(paraptr);
      _mm_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 BOOL 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)   _mm_read_UBYTE(modreader);
                  if(mask[ch]&2)   _mm_read_UBYTE(modreader);
                  if(mask[ch]&4)   _mm_read_UBYTE(modreader);
                  if(mask[ch]&8) { _mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader); }
            }
      } while(row<patrows);

      return 0;
}

static 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)
                        UniWriteByte(UNI_KEYOFF);
                  else if(note==254) {
                        UniPTEffect(0xc,-1);    /* note cut command */
                        volpan=255;
                  } else
                        UniNote(note);
            }

            if((ins)&&(ins<100))
                  UniInstrument(ins-1);
            else if(ins==253)
                  UniWriteByte(UNI_KEYOFF);
            else if(ins!=255) { /* crap */
                  _mm_errno=MMERR_LOADING_PATTERN;
                  return NULL;
            }

            /* process volume / panning column
               volume / panning effects do NOT all share the same memory address
               yet. */
            if(volpan<=64)
                  UniVolEffect(VOL_VOLUME,volpan);
            else if(volpan<=74)     /* fine volume slide up (65-74) */
                  UniVolEffect(VOL_VOLSLIDE,0x0f+((volpan-65)<<4));
            else if(volpan<=84)     /* fine volume slide down (75-84) */
                  UniVolEffect(VOL_VOLSLIDE,0xf0+(volpan-75));
            else if(volpan<=94)     /* volume slide up (85-94) */
                  UniVolEffect(VOL_VOLSLIDE,((volpan-85)<<4));
            else if(volpan<=104)/* volume slide down (95-104) */
                  UniVolEffect(VOL_VOLSLIDE,(volpan-95));
            else if(volpan<=114)/* pitch slide down (105-114) */
                  UniVolEffect(VOL_PITCHSLIDEDN,(volpan-105));
            else if(volpan<=124)/* pitch slide up (115-124) */
                  UniVolEffect(VOL_PITCHSLIDEUP,(volpan-115));
            else if(volpan<=127) { /* crap */
                  _mm_errno=MMERR_LOADING_PATTERN;
                  return NULL;
            } else if(volpan<=192)
                  UniVolEffect(VOL_PANNING,((volpan-128)==64)?255:((volpan-128)<<2));
            else if(volpan<=202)/* portamento to note */
                  UniVolEffect(VOL_PORTAMENTO,portatable[volpan-193]);
            else if(volpan<=212)/* vibrato */
                  UniVolEffect(VOL_VIBRATO,(volpan-203));
            else if((volpan!=239)&&(volpan!=255)) { /* crap */
                  _mm_errno=MMERR_LOADING_PATTERN;
                  return NULL;
            }

            S3MIT_ProcessCmd(tr[t*of.numchn].cmd,tr[t*of.numchn].inf,old_effect|2);

            UniNewline();
      }
      return UniDup();
}

static BOOL IT_ReadPattern(UWORD patrows)
{
      int row=0,flag,ch,blah;
      ITNOTE *itt=itpat,dummy,*n,*l;

      memset(itt,255,200*64*sizeof(ITNOTE));

      do {
            if((flag=_mm_read_UBYTE(modreader))==EOF) {
                  _mm_errno = MMERR_LOADING_PATTERN;
                  return 0;
            }
            if(!flag) {
                  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(modreader);
                  if(mask[ch]&1)
                        /* convert IT note off to internal note off */
                        if((l->note=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(row<patrows);

      for(blah=0;blah<of.numchn;blah++) {
            if(!(of.tracks[numtrk++]=IT_ConvertTrack(&itpat[blah],patrows)))
                  return 0;
      }

      return 1;
}

static void LoadMidiString(MREADER* modreader,CHAR* dest)
{
      CHAR *cur,*last;

      _mm_read_UBYTES(dest,32,modreader);
      cur=last=dest;
      /* remove blanks and uppercase all */
      while(*last) {
            if(isalnum((int)*last)) *(cur++)=toupper((int)*last);
            last++;
      }
      *cur=0;
}

/* Load embedded midi information for resonant filters */
static void IT_LoadMidiConfiguration(MREADER* modreader)
{
      int i;

      memset(filtermacros,0,sizeof(filtermacros));
      memset(filtersettings,0,sizeof(filtersettings));

      if (modreader) { /* information is embedded in file */
            UWORD dat;
            CHAR midiline[33];

            dat=_mm_read_I_UWORD(modreader);
            _mm_fseek(modreader,8*dat+0x120,SEEK_CUR);

            /* read midi macros */
            for(i=0;i<16;i++) {
                  LoadMidiString(modreader,midiline);
                  if((!strncmp(midiline,"F0F00",5))&&
                     ((midiline[5]=='0')||(midiline[5]=='1')))
                              filtermacros[i]=(midiline[5]-'0')|0x80;
            }

            /* read standalone filters */
            for(i=0x80;i<0x100;i++) {
                  LoadMidiString(modreader,midiline);
                  if((!strncmp(midiline,"F0F00",5))&&
                     ((midiline[5]=='0')||(midiline[5]=='1'))) {
                        filtersettings[i].filter=(midiline[5]-'0')|0x80;
                        dat=(midiline[6])?(midiline[6]-'0'):0;
                        if(midiline[7])dat=(dat<<4)|(midiline[7]-'0');
                        filtersettings[i].inf=(UBYTE)dat;
                  }
            }
      } else { /* use default information */
            filtermacros[0]=FILT_CUT;
            for(i=0x80;i<0x90;i++) {
                  filtersettings[i].filter=FILT_RESONANT;
                  filtersettings[i].inf=(i&0x7f)<<3;
            }
      }
      activemacro=0;
      for(i=0;i<0x80;i++) {
            filtersettings[i].filter=filtermacros[0];
            filtersettings[i].inf=i;
      }
}

BOOL IT_Load(BOOL curious)
{
      int t,u,lp;
      INSTRUMENT *d;
      SAMPLE *q;
      BOOL compressed=0;

      numtrk=0;
      filters=0;

      /* try to read module header */
      _mm_read_I_ULONG(modreader);  /* kill the 4 byte header */
      _mm_read_string(mh->songname,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->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=1;
      else
            old_effect=0;

      /* set panning positions */
      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;
            }
      }

      /* set channel volumes */
      memcpy(of.chanvol,mh->voltable,64);

      /* read the order data */
      if(!AllocPositions(mh->ordnum)) return 0;
      if(!(origpositions=_mm_calloc(mh->ordnum,sizeof(UWORD)))) return 0;

      for(t=0;t<mh->ordnum;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=(UBYTE)mh->ordnum;
      S3MIT_CreateOrders(curious);

      if(!(paraptr=(ULONG*)_mm_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;t<mh->smpnum;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)||
               (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;t<mh->insnum;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_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;lp<ITENVCNT;lp++) {
                              ih.oldvoltick[lp] = _mm_read_UBYTE(modreader);
                              ih.volnode[lp]    = _mm_read_UBYTE(modreader);
                        }
                  } else {
                        /* load IT 2xx volume, pan and pitch envelopes */

 ih.volflg   =_mm_read_UBYTE(modreader);             
 ih.volpts   =_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);             
 for(lp=0;lp<ITENVCNT;lp++) {
 ih.volnode[lp]=_mm_read_UBYTE(modreader);
 ih.voltick[lp]=_mm_read_I_UWORD(modreader); 
 }                                                            
 _mm_read_UBYTE(modreader);
 ih.panflg   =_mm_read_UBYTE(modreader);             
 ih.panpts   =_mm_read_UBYTE(modreader);             
 ih.panbeg   =_mm_read_UBYTE(modreader);             
 ih.panend   =_mm_read_UBYTE(modreader);             
 ih.pansusbeg=_mm_read_UBYTE(modreader);             
 ih.pansusend=_mm_read_UBYTE(modreader);             
 for(lp=0;lp<ITENVCNT;lp++) {
 ih.pannode[lp]=_mm_read_SBYTE(modreader);
 ih.pantick[lp]=_mm_read_I_UWORD(modreader); 
 }                                                            
 _mm_read_UBYTE(modreader);
 ih.pitflg   =_mm_read_UBYTE(modreader);             
 ih.pitpts   =_mm_read_UBYTE(modreader);             
 ih.pitbeg   =_mm_read_UBYTE(modreader);             
 ih.pitend   =_mm_read_UBYTE(modreader);             
 ih.pitsusbeg=_mm_read_UBYTE(modreader);             
 ih.pitsusend=_mm_read_UBYTE(modreader);             
 for(lp=0;lp < ITENVCNT; lp++) {
 ih.pitnode[lp]=_mm_read_SBYTE(modreader);
 ih.pittick[lp]=_mm_read_I_UWORD(modreader); 
 }                                                            
 _mm_read_UBYTE(modreader);

                  }

                  if(_mm_eof(modreader)) {
                        _mm_errno = MMERR_LOADING_SAMPLEINFO;
                        return 0;
                  }

                  d->volflg|=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;u<ITENVCNT;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;
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].pos=ih.voltick[u];                               if((d->volflg&EF_ON)&&(d->volpts<2))                          
 d->volflg&=~EF_ON;
for(u=0;u<ih.volpts;u++)
 d->volenv[u].val=(ih.volnode[u]<<2);
                               
if(ih.panflg&1) d->panflg|=EF_ON;
if(ih.panflg&2) d->panflg|=EF_LOOP;
if(ih.panflg&4) d->panflg|=EF_SUSTAIN;
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].pos=ih.pantick[u];                               
if((d->panflg&EF_ON)&&(d->panpts<2))         
d->panflg&=~EF_ON;                 
 for(u=0;u<ih.panpts;u++)
  d->panenv[u].val=ih.pannode[u]==32?255:(ih.pannode[u]+32)<<2;

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->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].pos=ih.pittick[u];                               
if((d->pitflg&EF_ON)&&(d->pitpts<2))
d->pitflg&=~EF_ON;
 for(u=0;u<ih.pitpts;u++)
  d->pitenv[u].val=ih.pitnode[u]+32;

                        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)
                                          fputs("\rFilter envelopes not supported yet\n",stderr);
                                    warn=1;
                              }
#endif
                        }
                  }

                  for(u=0;u<ITNOTECNT;u++) {
                        d->samplenote[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;t<mh->smpnum;t++,d++)
                  for(u=0;u<ITNOTECNT;u++) {
                        if(d->samplenumber[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,64*sizeof(UBYTE));
      for(t=0;t<of.numpat;t++) {
            UWORD packlen;

            /* seek to pattern position */
            if(paraptr[mh->insnum+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;t<64;t++)
            if(!remap[t])
                  remap[t]=of.numchn++;

      of.numtrk = of.numpat*of.numchn;
      if(of.numvoices)
            if (of.numvoices<of.numchn) of.numvoices=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 -> empty 64 row pattern */
                  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(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET);
                  packlen=_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: */

Generated by  Doxygen 1.6.0   Back to index