7 Screamtracker (S3M) module loader
\r
10 All systems - all compilers (hopefully)
\r
19 /**************************************************************************
\r
20 **************************************************************************/
\r
22 typedef struct S3MNOTE{
\r
23 UBYTE note,ins,vol,cmd,inf;
\r
26 typedef S3MNOTE S3MTRACK[64];
\r
29 /* Raw S3M header struct: */
\r
31 typedef struct S3MHEADER{
\r
55 /* Raw S3M sampleinfo struct: */
\r
57 typedef struct S3MSAMPLE{
\r
76 /**************************************************************************
\r
77 **************************************************************************/
\r
81 S3MNOTE *s3mbuf; /* pointer to a complete S3M pattern */
\r
82 UWORD *paraptr; /* parapointer array (see S3M docs) */
\r
83 static S3MHEADER *mh;
\r
87 char S3M_Version[]="Screamtracker 3.xx";
\r
94 _mm_fseek(modfp,0x2c,SEEK_SET);
\r
95 if(!fread(id,4,1,modfp)) return 0;
\r
96 if(!memcmp(id,"SCRM",4)) return 1;
\r
100 BOOL S3M_Init(void)
\r
105 if(!(s3mbuf=(S3MNOTE *)MyMalloc(16*64*sizeof(S3MNOTE)))) return 0;
\r
106 if(!(mh=(S3MHEADER *)MyCalloc(1,sizeof(S3MHEADER)))) return 0;
\r
111 void S3M_Cleanup(void)
\r
113 if(s3mbuf!=NULL) free(s3mbuf);
\r
114 if(paraptr!=NULL) free(paraptr);
\r
115 if(mh!=NULL) free(mh);
\r
121 BOOL S3M_ReadPattern(void)
\r
127 /* clear pattern data */
\r
129 memset(s3mbuf,255,16*64*sizeof(S3MNOTE));
\r
136 myerr="Error loading pattern";
\r
144 if(mh->channels[ch]<16){
\r
145 n=&s3mbuf[(64U*remap[ch])+row];
\r
152 n->note=fgetc(modfp);
\r
153 n->ins=fgetc(modfp);
\r
157 n->vol=fgetc(modfp);
\r
161 n->cmd=fgetc(modfp);
\r
162 n->inf=fgetc(modfp);
\r
172 UBYTE *S3M_ConvertTrack(S3MNOTE *tr)
\r
176 UBYTE note,ins,vol,cmd,inf,lo,hi;
\r
190 if(ins!=0 && ins!=255){
\r
191 UniInstrument(ins-1);
\r
195 if(note==254) UniPTEffect(0xc,0); /* <- note off command */
\r
196 else UniNote(((note>>4)*12)+(note&0xf)); /* <- normal note */
\r
200 UniPTEffect(0xc,vol);
\r
201 /* UniWrite(UNI_S3MVOLUME); */
\r
202 /* UniWrite(vol); */
\r
208 case 1: /* Axx set speed to xx */
\r
209 UniWrite(UNI_S3MEFFECTA);
\r
213 case 2: /* Bxx position jump */
\r
214 UniPTEffect(0xb,inf);
\r
217 case 3: /* Cxx patternbreak to row xx */
\r
218 UniPTEffect(0xd,inf);
\r
221 case 4: /* Dxy volumeslide */
\r
222 UniWrite(UNI_S3MEFFECTD);
\r
226 case 5: /* Exy toneslide down */
\r
227 UniWrite(UNI_S3MEFFECTE);
\r
231 case 6: /* Fxy toneslide up */
\r
232 UniWrite(UNI_S3MEFFECTF);
\r
236 case 7: /* Gxx Tone portamento,speed xx */
\r
237 UniPTEffect(0x3,inf);
\r
240 case 8: /* Hxy vibrato */
\r
241 UniPTEffect(0x4,inf);
\r
244 case 9: /* Ixy tremor, ontime x, offtime y */
\r
245 UniWrite(UNI_S3MEFFECTI);
\r
249 case 0xa: /* Jxy arpeggio */
\r
250 UniPTEffect(0x0,inf);
\r
253 case 0xb: /* Kxy Dual command H00 & Dxy */
\r
254 UniPTEffect(0x4,0);
\r
255 UniWrite(UNI_S3MEFFECTD);
\r
259 case 0xc: /* Lxy Dual command G00 & Dxy */
\r
260 UniPTEffect(0x3,0);
\r
261 UniWrite(UNI_S3MEFFECTD);
\r
265 case 0xf: /* Oxx set sampleoffset xx00h */
\r
266 UniPTEffect(0x9,inf);
\r
269 case 0x11: /* Qxy Retrig (+volumeslide) */
\r
270 UniWrite(UNI_S3MEFFECTQ);
\r
274 case 0x12: /* Rxy tremolo speed x, depth y */
\r
275 UniPTEffect(0x6,inf);
\r
278 case 0x13: /* Sxx special commands */
\r
281 case 0: /* S0x set filter */
\r
282 UniPTEffect(0xe,0x00|lo);
\r
285 case 1: /* S1x set glissando control */
\r
286 UniPTEffect(0xe,0x30|lo);
\r
289 case 2: /* S2x set finetune */
\r
290 UniPTEffect(0xe,0x50|lo);
\r
293 case 3: /* S3x set vibrato waveform */
\r
294 UniPTEffect(0xe,0x40|lo);
\r
297 case 4: /* S4x set tremolo waveform */
\r
298 UniPTEffect(0xe,0x70|lo);
\r
301 case 8: /* S8x set panning position */
\r
302 UniPTEffect(0xe,0x80|lo);
\r
305 case 0xb: /* SBx pattern loop */
\r
306 UniPTEffect(0xe,0x60|lo);
\r
309 case 0xc: /* SCx notecut */
\r
310 UniPTEffect(0xe,0xC0|lo);
\r
313 case 0xd: /* SDx notedelay */
\r
314 UniPTEffect(0xe,0xD0|lo);
\r
317 case 0xe: /* SDx patterndelay */
\r
318 UniPTEffect(0xe,0xE0|lo);
\r
323 case 0x14: /* Txx tempo */
\r
325 UniWrite(UNI_S3MEFFECTT);
\r
330 case 0x18: /* Xxx amiga command 8xx */
\r
331 UniPTEffect(0x8,inf);
\r
344 BOOL S3M_Load(void)
\r
352 /* try to read module header */
\r
354 _mm_read_str(mh->songname,28,modfp);
\r
355 mh->t1a =_mm_read_UBYTE(modfp);
\r
356 mh->type =_mm_read_UBYTE(modfp);
\r
357 _mm_read_UBYTES(mh->unused1,2,modfp);
\r
358 mh->ordnum =_mm_read_I_UWORD(modfp);
\r
359 mh->insnum =_mm_read_I_UWORD(modfp);
\r
360 mh->patnum =_mm_read_I_UWORD(modfp);
\r
361 mh->flags =_mm_read_I_UWORD(modfp);
\r
362 mh->tracker =_mm_read_I_UWORD(modfp);
\r
363 mh->fileformat =_mm_read_I_UWORD(modfp);
\r
364 _mm_read_str(mh->scrm,4,modfp);
\r
366 mh->mastervol =_mm_read_UBYTE(modfp);
\r
367 mh->initspeed =_mm_read_UBYTE(modfp);
\r
368 mh->inittempo =_mm_read_UBYTE(modfp);
\r
369 mh->mastermult =_mm_read_UBYTE(modfp);
\r
370 mh->ultraclick =_mm_read_UBYTE(modfp);
\r
371 mh->pantable =_mm_read_UBYTE(modfp);
\r
372 _mm_read_UBYTES(mh->unused2,8,modfp);
\r
373 mh->special =_mm_read_I_UWORD(modfp);
\r
374 _mm_read_UBYTES(mh->channels,32,modfp);
\r
377 myerr="Error loading header";
\r
381 /* set module variables */
\r
383 of.modtype=strdup(S3M_Version);
\r
384 of.songname=DupStr(mh->songname,28); /* make a cstr of songname */
\r
385 of.numpat=mh->patnum;
\r
386 of.numins=mh->insnum;
\r
387 of.initspeed=mh->initspeed;
\r
388 of.inittempo=mh->inittempo;
\r
390 /* count the number of channels used */
\r
394 /* for(t=0;t<32;t++) printf("%2.2x ",mh->channels[t]);
\r
396 for(t=0;t<32;t++) remap[t]=0;
\r
397 for(t=0;t<16;t++) isused[t]=0;
\r
399 /* set a flag for each channel (1 out of of 16) thats being used: */
\r
402 if(mh->channels[t]<16){
\r
403 isused[mh->channels[t]]=1;
\r
407 /* give each of them a different number */
\r
411 isused[t]=of.numchn;
\r
416 /* build the remap array */
\r
419 if(mh->channels[t]<16){
\r
420 remap[t]=isused[mh->channels[t]];
\r
424 /* set panning positions */
\r
427 if(mh->channels[t]<16){
\r
428 if(mh->channels[t]<8){
\r
429 of.panning[remap[t]]=0x30;
\r
432 of.panning[remap[t]]=0xc0;
\r
437 of.numtrk=of.numpat*of.numchn;
\r
439 /* printf("Uses %d channels\n",of.numchn);
\r
441 /* read the order data */
\r
443 _mm_read_UBYTES(of.positions,mh->ordnum,modfp);
\r
446 for(t=0;t<mh->ordnum;t++){
\r
447 of.positions[of.numpos]=of.positions[t];
\r
448 if(of.positions[t]<254) of.numpos++;
\r
451 if((paraptr=(UWORD *)MyMalloc((of.numins+of.numpat)*sizeof(UWORD)))==NULL) return 0;
\r
453 /* read the instrument+pattern parapointers */
\r
455 _mm_read_I_UWORDS(paraptr,of.numins+of.numpat,modfp);
\r
457 /* printf("pantab %d\n",mh->pantable);
\r
459 if(mh->pantable==252){
\r
461 /* read the panning table */
\r
463 _mm_read_UBYTES(pan,32,modfp);
\r
465 /* set panning positions according to panning table (new for st3.2) */
\r
468 if((pan[t]&0x20) && mh->channels[t]<16){
\r
469 of.panning[remap[t]]=(pan[t]&0xf)<<4;
\r
474 /* now is a good time to check if the header was too short :) */
\r
477 myerr="Error loading header";
\r
481 if(!AllocInstruments()) return 0;
\r
485 for(t=0;t<of.numins;t++){
\r
489 if(!AllocSamples(d)) return 0;
\r
492 /* seek to instrument position */
\r
494 _mm_fseek(modfp,((long)paraptr[t])<<4,SEEK_SET);
\r
496 /* and load sample info */
\r
498 s.type =_mm_read_UBYTE(modfp);
\r
499 _mm_read_str(s.filename,12,modfp);
\r
500 s.memsegh =_mm_read_UBYTE(modfp);
\r
501 s.memsegl =_mm_read_I_UWORD(modfp);
\r
502 s.length =_mm_read_I_ULONG(modfp);
\r
503 s.loopbeg =_mm_read_I_ULONG(modfp);
\r
504 s.loopend =_mm_read_I_ULONG(modfp);
\r
505 s.volume =_mm_read_UBYTE(modfp);
\r
506 s.dsk =_mm_read_UBYTE(modfp);
\r
507 s.pack =_mm_read_UBYTE(modfp);
\r
508 s.flags =_mm_read_UBYTE(modfp);
\r
509 s.c2spd =_mm_read_I_ULONG(modfp);
\r
510 _mm_read_UBYTES(s.unused,12,modfp);
\r
511 _mm_read_str(s.sampname,28,modfp);
\r
512 _mm_read_str(s.scrs,4,modfp);
\r
515 myerr=ERROR_LOADING_HEADER;
\r
519 d->insname=DupStr(s.sampname,28);
\r
521 q->length=s.length;
\r
522 q->loopstart=s.loopbeg;
\r
523 q->loopend=s.loopend;
\r
524 q->volume=s.volume;
\r
525 q->seekpos=(((long)s.memsegh)<<16|s.memsegl)<<4;
\r
529 if(s.flags&1) q->flags|=SF_LOOP;
\r
530 if(s.flags&4) q->flags|=SF_16BITS;
\r
531 if(mh->fileformat==1) q->flags|=SF_SIGNED;
\r
533 /* DON'T load sample if it doesn't have the SCRS tag */
\r
535 if(memcmp(s.scrs,"SCRS",4)!=0) q->length=0;
\r
537 /* printf("%s\n",d->insname);
\r
542 if(!AllocTracks()) return 0;
\r
543 if(!AllocPatterns()) return 0;
\r
545 for(t=0;t<of.numpat;t++){
\r
547 /* seek to pattern position ( + 2 skip pattern length ) */
\r
549 _mm_fseek(modfp,(((long)paraptr[of.numins+t])<<4)+2,SEEK_SET);
\r
551 if(!S3M_ReadPattern()) return 0;
\r
553 for(u=0;u<of.numchn;u++){
\r
554 if(!(of.tracks[track++]=S3M_ConvertTrack(&s3mbuf[u*64]))) return 0;
\r
565 "Portable S3M loader v0.2",
\r