added an old version of mikmod for dos
[dosdemo] / libs / oldmik / src / load_s3m.c
diff --git a/libs/oldmik/src/load_s3m.c b/libs/oldmik/src/load_s3m.c
new file mode 100644 (file)
index 0000000..07425ec
--- /dev/null
@@ -0,0 +1,570 @@
+/*\r
+\r
+Name:\r
+LOAD_S3M.C\r
+\r
+Description:\r
+Screamtracker (S3M) module loader\r
+\r
+Portability:\r
+All systems - all compilers (hopefully)\r
+\r
+*/\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include "mikmod.h"\r
+\r
+/**************************************************************************\r
+**************************************************************************/\r
+\r
+typedef struct S3MNOTE{\r
+       UBYTE note,ins,vol,cmd,inf;\r
+} S3MNOTE;\r
+\r
+typedef S3MNOTE S3MTRACK[64];\r
+\r
+\r
+/* Raw S3M header struct: */\r
+\r
+typedef struct S3MHEADER{\r
+       char  songname[28];\r
+       char  t1a;\r
+       char  type;\r
+        UBYTE unused1[2];\r
+       UWORD ordnum;\r
+       UWORD insnum;\r
+       UWORD patnum;\r
+       UWORD flags;\r
+       UWORD tracker;\r
+       UWORD fileformat;\r
+       char  scrm[4];\r
+       UBYTE mastervol;\r
+       UBYTE initspeed;\r
+       UBYTE inittempo;\r
+       UBYTE mastermult;\r
+       UBYTE ultraclick;\r
+       UBYTE pantable;\r
+        UBYTE unused2[8];\r
+       UWORD special;\r
+       UBYTE channels[32];\r
+} S3MHEADER;\r
+\r
+\r
+/* Raw S3M sampleinfo struct: */\r
+\r
+typedef struct S3MSAMPLE{\r
+       UBYTE type;\r
+       char  filename[12];\r
+       UBYTE memsegh;\r
+       UWORD memsegl;\r
+       ULONG length;\r
+       ULONG loopbeg;\r
+       ULONG loopend;\r
+       UBYTE volume;\r
+       UBYTE dsk;\r
+       UBYTE pack;\r
+       UBYTE flags;\r
+       ULONG c2spd;\r
+        UBYTE unused[12];\r
+       char  sampname[28];\r
+       char  scrs[4];\r
+} S3MSAMPLE;\r
+\r
+\r
+/**************************************************************************\r
+**************************************************************************/\r
+\r
+\r
+\r
+S3MNOTE *s3mbuf;        /* pointer to a complete S3M pattern */\r
+UWORD *paraptr;         /* parapointer array (see S3M docs) */\r
+static S3MHEADER *mh;\r
+UBYTE remap[32];\r
+\r
+\r
+char S3M_Version[]="Screamtracker 3.xx";\r
+\r
+\r
+\r
+BOOL S3M_Test(void)\r
+{\r
+       char id[4];\r
+       _mm_fseek(modfp,0x2c,SEEK_SET);\r
+       if(!fread(id,4,1,modfp)) return 0;\r
+       if(!memcmp(id,"SCRM",4)) return 1;\r
+       return 0;\r
+}\r
+\r
+BOOL S3M_Init(void)\r
+{\r
+       s3mbuf=NULL;\r
+       paraptr=NULL;\r
+\r
+       if(!(s3mbuf=(S3MNOTE *)MyMalloc(16*64*sizeof(S3MNOTE)))) return 0;\r
+       if(!(mh=(S3MHEADER *)MyCalloc(1,sizeof(S3MHEADER)))) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+void S3M_Cleanup(void)\r
+{\r
+       if(s3mbuf!=NULL) free(s3mbuf);\r
+       if(paraptr!=NULL) free(paraptr);\r
+       if(mh!=NULL) free(mh);\r
+}\r
+\r
+\r
+\r
+\r
+BOOL S3M_ReadPattern(void)\r
+{\r
+       int row=0,flag,ch;\r
+       S3MNOTE *n;\r
+       S3MNOTE dummy;\r
+\r
+       /* clear pattern data */\r
+\r
+       memset(s3mbuf,255,16*64*sizeof(S3MNOTE));\r
+\r
+       while(row<64){\r
+\r
+               flag=fgetc(modfp);\r
+\r
+               if(flag==EOF){\r
+                       myerr="Error loading pattern";\r
+                       return 0;\r
+               }\r
+\r
+               if(flag){\r
+\r
+                       ch=flag&31;\r
+\r
+                       if(mh->channels[ch]<16){\r
+                               n=&s3mbuf[(64U*remap[ch])+row];\r
+                       }\r
+                       else{\r
+                               n=&dummy;\r
+                       }\r
+\r
+                       if(flag&32){\r
+                               n->note=fgetc(modfp);\r
+                               n->ins=fgetc(modfp);\r
+                       }\r
+\r
+                       if(flag&64){\r
+                               n->vol=fgetc(modfp);\r
+                       }\r
+\r
+                       if(flag&128){\r
+                               n->cmd=fgetc(modfp);\r
+                               n->inf=fgetc(modfp);\r
+                       }\r
+               }\r
+               else row++;\r
+       }\r
+       return 1;\r
+}\r
+\r
+\r
+\r
+UBYTE *S3M_ConvertTrack(S3MNOTE *tr)\r
+{\r
+       int t;\r
+\r
+       UBYTE note,ins,vol,cmd,inf,lo,hi;\r
+\r
+       UniReset();\r
+       for(t=0;t<64;t++){\r
+\r
+               note=tr[t].note;\r
+               ins=tr[t].ins;\r
+               vol=tr[t].vol;\r
+               cmd=tr[t].cmd;\r
+               inf=tr[t].inf;\r
+               lo=inf&0xf;\r
+               hi=inf>>4;\r
+\r
+\r
+               if(ins!=0 && ins!=255){\r
+                       UniInstrument(ins-1);\r
+               }\r
+\r
+               if(note!=255){\r
+                       if(note==254) UniPTEffect(0xc,0);                       /* <- note off command */\r
+                       else UniNote(((note>>4)*12)+(note&0xf));        /* <- normal note */\r
+               }\r
+\r
+               if(vol<255){\r
+                       UniPTEffect(0xc,vol);\r
+/*                     UniWrite(UNI_S3MVOLUME); */\r
+/*                     UniWrite(vol); */\r
+               }\r
+\r
+               if(cmd!=255){\r
+                       switch(cmd){\r
+\r
+                               case 1:                 /* Axx set speed to xx */\r
+                                       UniWrite(UNI_S3MEFFECTA);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 2:                 /* Bxx position jump */\r
+                                       UniPTEffect(0xb,inf);\r
+                                       break;\r
+\r
+                               case 3:                 /* Cxx patternbreak to row xx */\r
+                                       UniPTEffect(0xd,inf);\r
+                                       break;\r
+\r
+                               case 4:                 /* Dxy volumeslide */\r
+                                       UniWrite(UNI_S3MEFFECTD);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 5:                 /* Exy toneslide down */\r
+                                       UniWrite(UNI_S3MEFFECTE);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 6:                 /* Fxy toneslide up */\r
+                                       UniWrite(UNI_S3MEFFECTF);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 7:                 /* Gxx Tone portamento,speed xx */\r
+                                       UniPTEffect(0x3,inf);\r
+                                       break;\r
+\r
+                               case 8:                 /* Hxy vibrato */\r
+                                       UniPTEffect(0x4,inf);\r
+                                       break;\r
+\r
+                               case 9:                 /* Ixy tremor, ontime x, offtime y */\r
+                                       UniWrite(UNI_S3MEFFECTI);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 0xa:               /* Jxy arpeggio */\r
+                                       UniPTEffect(0x0,inf);\r
+                                       break;\r
+\r
+                               case 0xb:               /* Kxy Dual command H00 & Dxy */\r
+                                       UniPTEffect(0x4,0);\r
+                                       UniWrite(UNI_S3MEFFECTD);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 0xc:               /* Lxy Dual command G00 & Dxy */\r
+                                       UniPTEffect(0x3,0);\r
+                                       UniWrite(UNI_S3MEFFECTD);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 0xf:               /* Oxx set sampleoffset xx00h */\r
+                                       UniPTEffect(0x9,inf);\r
+                                       break;\r
+\r
+                               case 0x11:              /* Qxy Retrig (+volumeslide) */\r
+                                       UniWrite(UNI_S3MEFFECTQ);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 0x12:              /* Rxy tremolo speed x, depth y */\r
+                                       UniPTEffect(0x6,inf);\r
+                                       break;\r
+\r
+                               case 0x13:              /* Sxx special commands */\r
+                                       switch(hi){\r
+\r
+                                               case 0: /* S0x set filter */\r
+                                                       UniPTEffect(0xe,0x00|lo);\r
+                                                       break;\r
+\r
+                                               case 1: /* S1x set glissando control */\r
+                                                       UniPTEffect(0xe,0x30|lo);\r
+                                                       break;\r
+\r
+                                               case 2: /* S2x set finetune */\r
+                                                       UniPTEffect(0xe,0x50|lo);\r
+                                                       break;\r
+\r
+                                               case 3: /* S3x set vibrato waveform */\r
+                                                       UniPTEffect(0xe,0x40|lo);\r
+                                                       break;\r
+\r
+                                               case 4: /* S4x set tremolo waveform */\r
+                                                       UniPTEffect(0xe,0x70|lo);\r
+                                                       break;\r
+\r
+                                               case 8: /* S8x set panning position */\r
+                                                       UniPTEffect(0xe,0x80|lo);\r
+                                                       break;\r
+\r
+                                               case 0xb:       /* SBx pattern loop */\r
+                                                       UniPTEffect(0xe,0x60|lo);\r
+                                                       break;\r
+\r
+                                               case 0xc:       /* SCx notecut */\r
+                                                       UniPTEffect(0xe,0xC0|lo);\r
+                                                       break;\r
+\r
+                                               case 0xd:       /* SDx notedelay */\r
+                                                       UniPTEffect(0xe,0xD0|lo);\r
+                                                       break;\r
+\r
+                                               case 0xe:       /* SDx patterndelay */\r
+                                                       UniPTEffect(0xe,0xE0|lo);\r
+                                                       break;\r
+                                       }\r
+                                       break;\r
+\r
+                               case 0x14:      /* Txx tempo */\r
+                                       if(inf>0x20){\r
+                                               UniWrite(UNI_S3MEFFECTT);\r
+                                               UniWrite(inf);\r
+                                       }\r
+                                       break;\r
+\r
+                               case 0x18:      /* Xxx amiga command 8xx */\r
+                                       UniPTEffect(0x8,inf);\r
+                                       break;\r
+                       }\r
+               }\r
+\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+\r
+\r
+\r
+BOOL S3M_Load(void)\r
+{\r
+       int t,u,track=0;\r
+       INSTRUMENT *d;\r
+       SAMPLE *q;\r
+       UBYTE isused[16];\r
+       UBYTE pan[32];\r
+\r
+       /* try to read module header */\r
+\r
+       _mm_read_str(mh->songname,28,modfp);\r
+       mh->t1a                 =_mm_read_UBYTE(modfp);\r
+       mh->type                =_mm_read_UBYTE(modfp);\r
+       _mm_read_UBYTES(mh->unused1,2,modfp);\r
+       mh->ordnum              =_mm_read_I_UWORD(modfp);\r
+       mh->insnum              =_mm_read_I_UWORD(modfp);\r
+       mh->patnum              =_mm_read_I_UWORD(modfp);\r
+       mh->flags               =_mm_read_I_UWORD(modfp);\r
+       mh->tracker             =_mm_read_I_UWORD(modfp);\r
+       mh->fileformat  =_mm_read_I_UWORD(modfp);\r
+       _mm_read_str(mh->scrm,4,modfp);\r
+\r
+       mh->mastervol   =_mm_read_UBYTE(modfp);\r
+       mh->initspeed   =_mm_read_UBYTE(modfp);\r
+       mh->inittempo   =_mm_read_UBYTE(modfp);\r
+       mh->mastermult  =_mm_read_UBYTE(modfp);\r
+       mh->ultraclick  =_mm_read_UBYTE(modfp);\r
+       mh->pantable    =_mm_read_UBYTE(modfp);\r
+       _mm_read_UBYTES(mh->unused2,8,modfp);\r
+       mh->special             =_mm_read_I_UWORD(modfp);\r
+       _mm_read_UBYTES(mh->channels,32,modfp);\r
+\r
+       if(feof(modfp)){\r
+               myerr="Error loading header";\r
+               return 0;\r
+       }\r
+\r
+       /* set module variables */\r
+\r
+       of.modtype=strdup(S3M_Version);\r
+       of.songname=DupStr(mh->songname,28);    /* make a cstr of songname */\r
+       of.numpat=mh->patnum;\r
+       of.numins=mh->insnum;\r
+       of.initspeed=mh->initspeed;\r
+       of.inittempo=mh->inittempo;\r
+\r
+       /* count the number of channels used */\r
+\r
+       of.numchn=0;\r
+\r
+/*      for(t=0;t<32;t++) printf("%2.2x ",mh->channels[t]);\r
+*/\r
+       for(t=0;t<32;t++) remap[t]=0;\r
+       for(t=0;t<16;t++) isused[t]=0;\r
+\r
+       /* set a flag for each channel (1 out of of 16) thats being used: */\r
+\r
+       for(t=0;t<32;t++){\r
+               if(mh->channels[t]<16){\r
+                       isused[mh->channels[t]]=1;\r
+               }\r
+       }\r
+\r
+       /* give each of them a different number */\r
+\r
+       for(t=0;t<16;t++){\r
+               if(isused[t]){\r
+                       isused[t]=of.numchn;\r
+                       of.numchn++;\r
+               }\r
+       }\r
+\r
+       /* build the remap array */\r
+\r
+       for(t=0;t<32;t++){\r
+               if(mh->channels[t]<16){\r
+                       remap[t]=isused[mh->channels[t]];\r
+               }\r
+       }\r
+\r
+       /* set panning positions */\r
+\r
+       for(t=0;t<32;t++){\r
+               if(mh->channels[t]<16){\r
+                       if(mh->channels[t]<8){\r
+                               of.panning[remap[t]]=0x30;\r
+                       }\r
+                       else{\r
+                               of.panning[remap[t]]=0xc0;\r
+                       }\r
+               }\r
+       }\r
+\r
+       of.numtrk=of.numpat*of.numchn;\r
+\r
+/*      printf("Uses %d channels\n",of.numchn);\r
+*/\r
+       /* read the order data */\r
+\r
+       _mm_read_UBYTES(of.positions,mh->ordnum,modfp);\r
+\r
+       of.numpos=0;\r
+       for(t=0;t<mh->ordnum;t++){\r
+               of.positions[of.numpos]=of.positions[t];\r
+               if(of.positions[t]<254) of.numpos++;\r
+       }\r
+\r
+       if((paraptr=(UWORD *)MyMalloc((of.numins+of.numpat)*sizeof(UWORD)))==NULL) return 0;\r
+\r
+       /* read the instrument+pattern parapointers */\r
+\r
+       _mm_read_I_UWORDS(paraptr,of.numins+of.numpat,modfp);\r
+\r
+/*      printf("pantab %d\n",mh->pantable);\r
+*/\r
+       if(mh->pantable==252){\r
+\r
+               /* read the panning table */\r
+\r
+               _mm_read_UBYTES(pan,32,modfp);\r
+\r
+               /* set panning positions according to panning table (new for st3.2) */\r
+\r
+               for(t=0;t<32;t++){\r
+                       if((pan[t]&0x20) && mh->channels[t]<16){\r
+                               of.panning[remap[t]]=(pan[t]&0xf)<<4;\r
+                       }\r
+               }\r
+       }\r
+\r
+       /* now is a good time to check if the header was too short :) */\r
+\r
+       if(feof(modfp)){\r
+               myerr="Error loading header";\r
+               return 0;\r
+       }\r
+\r
+       if(!AllocInstruments()) return 0;\r
+\r
+       d=of.instruments;\r
+\r
+       for(t=0;t<of.numins;t++){\r
+               S3MSAMPLE s;\r
+\r
+               d->numsmp=1;\r
+               if(!AllocSamples(d)) return 0;\r
+               q=d->samples;\r
+\r
+               /* seek to instrument position */\r
+\r
+               _mm_fseek(modfp,((long)paraptr[t])<<4,SEEK_SET);\r
+\r
+               /* and load sample info */\r
+\r
+               s.type          =_mm_read_UBYTE(modfp);\r
+               _mm_read_str(s.filename,12,modfp);\r
+               s.memsegh       =_mm_read_UBYTE(modfp);\r
+               s.memsegl       =_mm_read_I_UWORD(modfp);\r
+               s.length        =_mm_read_I_ULONG(modfp);\r
+               s.loopbeg       =_mm_read_I_ULONG(modfp);\r
+               s.loopend       =_mm_read_I_ULONG(modfp);\r
+               s.volume        =_mm_read_UBYTE(modfp);\r
+               s.dsk           =_mm_read_UBYTE(modfp);\r
+               s.pack          =_mm_read_UBYTE(modfp);\r
+               s.flags         =_mm_read_UBYTE(modfp);\r
+               s.c2spd         =_mm_read_I_ULONG(modfp);\r
+               _mm_read_UBYTES(s.unused,12,modfp);\r
+               _mm_read_str(s.sampname,28,modfp);\r
+               _mm_read_str(s.scrs,4,modfp);\r
+\r
+               if(feof(modfp)){\r
+                       myerr=ERROR_LOADING_HEADER;\r
+                       return 0;\r
+               }\r
+\r
+               d->insname=DupStr(s.sampname,28);\r
+               q->c2spd=s.c2spd;\r
+               q->length=s.length;\r
+               q->loopstart=s.loopbeg;\r
+               q->loopend=s.loopend;\r
+               q->volume=s.volume;\r
+               q->seekpos=(((long)s.memsegh)<<16|s.memsegl)<<4;\r
+\r
+               q->flags=0;\r
+\r
+               if(s.flags&1) q->flags|=SF_LOOP;\r
+               if(s.flags&4) q->flags|=SF_16BITS;\r
+               if(mh->fileformat==1) q->flags|=SF_SIGNED;\r
+\r
+               /* DON'T load sample if it doesn't have the SCRS tag */\r
+\r
+               if(memcmp(s.scrs,"SCRS",4)!=0) q->length=0;\r
+\r
+/*              printf("%s\n",d->insname);\r
+*/\r
+               d++;\r
+       }\r
+\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+\r
+       for(t=0;t<of.numpat;t++){\r
+\r
+               /* seek to pattern position ( + 2 skip pattern length ) */\r
+\r
+               _mm_fseek(modfp,(((long)paraptr[of.numins+t])<<4)+2,SEEK_SET);\r
+\r
+               if(!S3M_ReadPattern()) return 0;\r
+\r
+               for(u=0;u<of.numchn;u++){\r
+                       if(!(of.tracks[track++]=S3M_ConvertTrack(&s3mbuf[u*64]))) return 0;\r
+               }\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+LOADER load_s3m={\r
+       NULL,\r
+       "S3M",\r
+       "Portable S3M loader v0.2",\r
+       S3M_Init,\r
+       S3M_Test,\r
+       S3M_Load,\r
+       S3M_Cleanup\r
+};\r