1 /* MikMod sound library
2 (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
3 AUTHORS for complete list.
5 This library is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of
8 the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 /*==============================================================================
25 Screamtracker (S3M) module loader
27 ==============================================================================*/
43 #include "mikmod_internals.h"
46 extern int fprintf(FILE *, const char *, ...);
49 /*========== Module structure */
52 typedef struct S3MHEADER {
75 /* sample information */
76 typedef struct S3MSAMPLE {
94 typedef struct S3MNOTE {
95 UBYTE note,ins,vol,cmd,inf;
98 /*========== Loader variables */
100 static S3MNOTE *s3mbuf = NULL; /* pointer to a complete S3M pattern */
101 static S3MHEADER *mh = NULL;
102 static UWORD *paraptr = NULL; /* parapointer array (see S3M docs) */
103 static unsigned int tracker; /* tracker id */
105 /* tracker identifiers */
106 #define NUMTRACKERS 4
107 static const CHAR * S3M_Version[] = {
108 "Screamtracker x.xx",
109 "Imago Orpheus x.xx (S3M format)",
110 "Impulse Tracker x.xx (S3M format)",
111 "Unknown tracker x.xx (S3M format)",
112 "Impulse Tracker 2.14p3 (S3M format)",
113 "Impulse Tracker 2.14p4 (S3M format)"
115 /* version number position in above array */
116 static const int numeric[NUMTRACKERS]={14,14,16,16};
118 /*========== Loader code */
120 static BOOL S3M_Test(void)
124 _mm_fseek(modreader,0x2c,SEEK_SET);
125 if(!_mm_read_UBYTES(id,4,modreader)) return 0;
126 if(!memcmp(id,"SCRM",4)) return 1;
130 static BOOL S3M_Init(void)
132 if(!(s3mbuf=(S3MNOTE*)MikMod_malloc(32*64*sizeof(S3MNOTE)))) return 0;
133 if(!(mh=(S3MHEADER*)MikMod_malloc(sizeof(S3MHEADER)))) return 0;
134 if(!(poslookup=(UBYTE*)MikMod_malloc(sizeof(UBYTE)*256))) return 0;
135 memset(poslookup,-1,256);
140 static void S3M_Cleanup(void)
143 MikMod_free(paraptr);
144 MikMod_free(poslookup);
146 MikMod_free(origpositions);
154 /* Because so many s3m files have 16 channels as the set number used, but really
155 only use far less (usually 8 to 12 still), I had to make this function, which
156 determines the number of channels that are actually USED by a pattern.
158 For every channel that's used, it sets the appropriate array entry of the
159 global variable 'remap'
161 NOTE: You must first seek to the file location of the pattern before calling
164 Returns 0 on fail. */
165 static BOOL S3M_GetNumChannels(void)
170 flag=_mm_read_UBYTE(modreader);
172 if(_mm_eof(modreader)) {
173 _mm_errno = MMERR_LOADING_PATTERN;
179 if(mh->channels[ch]<32) remap[ch] = 0;
180 if(flag&32) {_mm_skip_BYTE(modreader);_mm_skip_BYTE(modreader);}
181 if(flag&64) _mm_skip_BYTE(modreader);
182 if(flag&128){_mm_skip_BYTE(modreader);_mm_skip_BYTE(modreader);}
188 static BOOL S3M_ReadPattern(void)
193 /* clear pattern data */
194 memset(s3mbuf,255,32*64*sizeof(S3MNOTE));
197 flag=_mm_read_UBYTE(modreader);
199 if(_mm_eof(modreader)) {
200 _mm_errno = MMERR_LOADING_PATTERN;
208 n=&s3mbuf[(64U*ch)+row];
213 n->note=_mm_read_UBYTE(modreader);
214 n->ins=_mm_read_UBYTE(modreader);
217 n->vol=_mm_read_UBYTE(modreader);
218 if (n->vol>64) n->vol=64;
221 n->cmd=_mm_read_UBYTE(modreader);
222 n->inf=_mm_read_UBYTE(modreader);
229 static UBYTE* S3M_ConvertTrack(S3MNOTE* tr)
241 if((ins)&&(ins!=255)) UniInstrument(ins-1);
244 UniPTEffect(0xc,0); /* note cut command */
247 UniNote(((note>>4)*OCTAVE)+(note&0xf)); /* normal note */
249 if(vol<255) UniPTEffect(0xc,vol);
251 S3MIT_ProcessCmd(tr[t].cmd,tr[t].inf,
252 tracker == 1 ? S3MIT_OLDSTYLE | S3MIT_SCREAM : S3MIT_OLDSTYLE);
258 static BOOL S3M_Load(BOOL curious)
264 /* try to read module header */
265 _mm_read_string(mh->songname,28,modreader);
266 mh->t1a =_mm_read_UBYTE(modreader);
267 mh->type =_mm_read_UBYTE(modreader);
268 _mm_read_UBYTES(mh->unused1,2,modreader);
269 mh->ordnum =_mm_read_I_UWORD(modreader);
270 mh->insnum =_mm_read_I_UWORD(modreader);
271 mh->patnum =_mm_read_I_UWORD(modreader);
272 mh->flags =_mm_read_I_UWORD(modreader);
273 mh->tracker =_mm_read_I_UWORD(modreader);
274 mh->fileformat =_mm_read_I_UWORD(modreader);
275 _mm_read_string(mh->scrm,4,modreader);
276 mh->mastervol =_mm_read_UBYTE(modreader);
277 mh->initspeed =_mm_read_UBYTE(modreader);
278 mh->inittempo =_mm_read_UBYTE(modreader);
279 mh->mastermult =_mm_read_UBYTE(modreader);
280 mh->ultraclick =_mm_read_UBYTE(modreader);
281 mh->pantable =_mm_read_UBYTE(modreader);
282 _mm_read_UBYTES(mh->unused2,8,modreader);
283 mh->special =_mm_read_I_UWORD(modreader);
284 _mm_read_UBYTES(mh->channels,32,modreader);
286 if(_mm_eof(modreader)) {
287 _mm_errno = MMERR_LOADING_HEADER;
291 /* then we can decide the module type */
292 tracker=mh->tracker>>12;
293 if((!tracker)||(tracker>=NUMTRACKERS))
294 tracker=NUMTRACKERS-1; /* unknown tracker */
296 if(mh->tracker>=0x3217)
297 tracker=NUMTRACKERS+1; /* IT 2.14p4 */
298 else if(mh->tracker>=0x3216)
299 tracker=NUMTRACKERS; /* IT 2.14p3 */
302 of.modtype = MikMod_strdup(S3M_Version[tracker]);
303 if(tracker<NUMTRACKERS) {
304 of.modtype[numeric[tracker]] = ((mh->tracker>>8) &0xf)+'0';
305 of.modtype[numeric[tracker]+2] = ((mh->tracker>>4)&0xf)+'0';
306 of.modtype[numeric[tracker]+3] = ((mh->tracker)&0xf)+'0';
308 /* set module variables */
309 of.songname = DupStr(mh->songname,28,0);
310 of.numpat = mh->patnum;
312 of.numins = of.numsmp = mh->insnum;
313 of.initspeed = mh->initspeed;
314 of.inittempo = mh->inittempo;
315 of.initvolume = mh->mastervol<<1;
316 of.flags |= UF_ARPMEM | UF_PANNING;
317 if((mh->tracker==0x1300)||(mh->flags&64))
318 of.flags|=UF_S3MSLIDES;
321 /* read the order data */
322 if(!AllocPositions(mh->ordnum)) return 0;
323 if(!(origpositions=(UWORD*)MikMod_calloc(mh->ordnum,sizeof(UWORD)))) return 0;
325 for(t=0;t<mh->ordnum;t++) {
326 origpositions[t]=_mm_read_UBYTE(modreader);
327 if((origpositions[t]>=mh->patnum)&&(origpositions[t]<254))
328 origpositions[t]=255/*mh->patnum-1*/;
331 if(_mm_eof(modreader)) {
332 _mm_errno = MMERR_LOADING_HEADER;
336 poslookupcnt=mh->ordnum;
337 S3MIT_CreateOrders(curious);
339 if(!(paraptr=(UWORD*)MikMod_malloc((of.numins+of.numpat)*sizeof(UWORD))))
342 /* read the instrument+pattern parapointers */
343 _mm_read_I_UWORDS(paraptr,of.numins+of.numpat,modreader);
345 if(mh->pantable==252) {
346 /* read the panning table (ST 3.2 addition. See below for further
347 portions of channel panning [past reampper]). */
348 _mm_read_UBYTES(pan,32,modreader);
351 if(_mm_eof(modreader)) {
352 _mm_errno = MMERR_LOADING_HEADER;
357 if(!AllocSamples()) return 0;
359 for(t=0;t<of.numins;t++) {
362 /* seek to instrument position */
363 _mm_fseek(modreader,((long)paraptr[t])<<4,SEEK_SET);
364 /* and load sample info */
365 s.type =_mm_read_UBYTE(modreader);
366 _mm_read_string(s.filename,12,modreader);
367 s.memsegh =_mm_read_UBYTE(modreader);
368 s.memsegl =_mm_read_I_UWORD(modreader);
369 s.length =_mm_read_I_ULONG(modreader);
370 s.loopbeg =_mm_read_I_ULONG(modreader);
371 s.loopend =_mm_read_I_ULONG(modreader);
372 s.volume =_mm_read_UBYTE(modreader);
373 s.dsk =_mm_read_UBYTE(modreader);
374 s.pack =_mm_read_UBYTE(modreader);
375 s.flags =_mm_read_UBYTE(modreader);
376 s.c2spd =_mm_read_I_ULONG(modreader);
377 _mm_read_UBYTES(s.unused,12,modreader);
378 _mm_read_string(s.sampname,28,modreader);
379 _mm_read_string(s.scrs,4,modreader);
381 /* ScreamTracker imposes a 64000 bytes (not 64k !) limit */
382 /* enforce it, if we'll use S3MIT_SCREAM in S3M_ConvertTrack() */
383 if (s.length > 64000 && tracker == 1)
386 if(_mm_eof(modreader)) {
387 _mm_errno = MMERR_LOADING_SAMPLEINFO;
391 q->samplename = DupStr(s.sampname,28,0);
393 q->length = s.length;
394 q->loopstart = s.loopbeg;
395 q->loopend = s.loopend;
396 q->volume = s.volume;
397 q->seekpos = (((ULONG)s.memsegh)<<16|s.memsegl)<<4;
399 if(s.flags&1) q->flags |= SF_LOOP;
400 if(s.flags&4) q->flags |= SF_16BITS;
401 if(mh->fileformat==1) q->flags |= SF_SIGNED;
403 /* don't load sample if it doesn't have the SCRS tag */
404 if(memcmp(s.scrs,"SCRS",4)) q->length = 0;
409 /* determine the number of channels actually used. */
411 memset(remap,-1,32*sizeof(UBYTE));
412 for(t=0;t<of.numpat;t++) {
413 /* seek to pattern position (+2 skip pattern length) */
414 _mm_fseek(modreader,(long)((paraptr[of.numins+t])<<4)+2,SEEK_SET);
415 if(!S3M_GetNumChannels()) return 0;
418 /* build the remap array */
421 remap[t]=of.numchn++;
423 /* set panning positions after building remap chart! */
425 if((mh->channels[t]<32)&&(remap[t]!=-1)) {
426 if(mh->channels[t]<8)
427 of.panning[remap[t]]=0x30;
429 of.panning[remap[t]]=0xc0;
431 if(mh->pantable==252)
432 /* set panning positions according to panning table (new for st3.2) */
434 if((pan[t]&0x20)&&(mh->channels[t]<32)&&(remap[t]!=-1))
435 of.panning[remap[t]]=(pan[t]&0xf)<<4;
437 /* load pattern info */
438 of.numtrk=of.numpat*of.numchn;
439 if(!AllocTracks()) return 0;
440 if(!AllocPatterns()) return 0;
442 for(t=0;t<of.numpat;t++) {
443 /* seek to pattern position (+2 skip pattern length) */
444 _mm_fseek(modreader,(((long)paraptr[of.numins+t])<<4)+2,SEEK_SET);
445 if(!S3M_ReadPattern()) return 0;
446 for(u=0;u<of.numchn;u++)
447 if(!(of.tracks[track++]=S3M_ConvertTrack(&s3mbuf[u*64]))) return 0;
453 static CHAR *S3M_LoadTitle(void)
457 _mm_fseek(modreader,0,SEEK_SET);
458 if(!_mm_read_UBYTES(s,28,modreader)) return NULL;
460 return(DupStr(s,28,0));
463 /*========== Loader information */
465 MIKMODAPI MLOADER load_s3m={
468 "S3M (Scream Tracker 3)",