1 /*      MikMod sound library
2    (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
3    complete list.
4 
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.
9 
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.
14 
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
18    02111-1307, USA.
19  */
20 
21 /*==============================================================================
22 
23   $Id$
24 
25   Screamtracker (S3M) module loader
26 
27 ==============================================================================*/
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <string.h>
34 
35 #include "unimod_priv.h"
36 
37 /*========== Module structure */
38 
39 /* header */
40 typedef struct S3MHEADER
41   {
42     CHAR songname[28];
43     UBYTE t1a;
44     UBYTE type;
45     UBYTE unused1[2];
46     UWORD ordnum;
47     UWORD insnum;
48     UWORD patnum;
49     UWORD flags;
50     UWORD tracker;
51     UWORD fileformat;
52     CHAR scrm[4];
53     UBYTE mastervol;
54     UBYTE initspeed;
55     UBYTE inittempo;
56     UBYTE mastermult;
57     UBYTE ultraclick;
58     UBYTE pantable;
59     UBYTE unused2[8];
60     UWORD special;
61     UBYTE channels[32];
62   }
63 S3MHEADER;
64 
65 /* sample information */
66 typedef struct S3MSAMPLE
67   {
68     UBYTE type;
69     CHAR filename[12];
70     UBYTE memsegh;
71     UWORD memsegl;
72     ULONG length;
73     ULONG loopbeg;
74     ULONG loopend;
75     UBYTE volume;
76     UBYTE dsk;
77     UBYTE pack;
78     UBYTE flags;
79     ULONG c2spd;
80     UBYTE unused[12];
81     CHAR sampname[28];
82     CHAR scrs[4];
83   }
84 S3MSAMPLE;
85 
86 typedef struct S3MNOTE
87   {
88     UBYTE note, ins, vol, cmd, inf;
89   }
90 S3MNOTE;
91 
92 /*========== Loader variables */
93 
94 static S3MNOTE *s3mbuf = NULL;	/* pointer to a complete S3M pattern */
95 static S3MHEADER *mh = NULL;
96 static UWORD *paraptr = NULL;	/* parapointer array (see S3M docs) */
97 
98 /* tracker identifiers */
99 #define NUMTRACKERS 4
100 static const CHAR *S3M_Version[] =
101 {
102   "Screamtracker x.xx",
103   "Imago Orpheus x.xx (S3M format)",
104   "Impulse Tracker x.xx (S3M format)",
105   "Unknown tracker x.xx (S3M format)",
106   "Impulse Tracker 2.14p3 (S3M format)",
107   "Impulse Tracker 2.14p4 (S3M format)"
108 };
109 /* version number position in above array */
110 static int numeric[NUMTRACKERS] =
111 {14, 14, 16, 16};
112 
113 /*========== Loader code */
114 
115 static BOOL
S3M_Test(void)116 S3M_Test (void)
117 {
118   UBYTE id[4];
119 
120   _mm_fseek (modreader, 0x2c, SEEK_SET);
121   if (!_mm_read_UBYTES (id, 4, modreader))
122     return 0;
123   if (!memcmp (id, "SCRM", 4))
124     return 1;
125   return 0;
126 }
127 
128 static BOOL
S3M_Init(void)129 S3M_Init (void)
130 {
131   if (!(s3mbuf = (S3MNOTE *) _mm_malloc (32 * 64 * sizeof (S3MNOTE))))
132     return 0;
133   if (!(mh = (S3MHEADER *) _mm_malloc (sizeof (S3MHEADER))))
134     return 0;
135   if (!(poslookup = (UBYTE *) _mm_malloc (sizeof (UBYTE) * 256)))
136     return 0;
137   memset (poslookup, -1, 256);
138 
139   return 1;
140 }
141 
142 static void
S3M_Cleanup(void)143 S3M_Cleanup (void)
144 {
145   _mm_free (s3mbuf);
146   _mm_free (paraptr);
147   _mm_free (poslookup);
148   _mm_free (mh);
149   _mm_free (origpositions);
150 }
151 
152 /* Because so many s3m files have 16 channels as the set number used, but really
153    only use far less (usually 8 to 12 still), I had to make this function, which
154    determines the number of channels that are actually USED by a pattern.
155 
156    For every channel that's used, it sets the appropriate array entry of the
157    global variable 'remap'
158 
159    NOTE: You must first seek to the file location of the pattern before calling
160    this procedure.
161 
162    Returns 1 on fail.                                                         */
163 static BOOL
S3M_GetNumChannels(void)164 S3M_GetNumChannels (void)
165 {
166   int row = 0, flag, ch;
167 
168   while (row < 64)
169     {
170       flag = _mm_read_UBYTE (modreader);
171 
172       if (_mm_eof (modreader))
173 	{
174 	  _mm_errno = MMERR_LOADING_PATTERN;
175 	  return 1;
176 	}
177 
178       if (flag)
179 	{
180 	  ch = flag & 31;
181 	  if (mh->channels[ch] < 32)
182 	    remap[ch] = 0;
183 	  if (flag & 32)
184 	    {
185 	      _mm_read_UBYTE (modreader);
186 	      _mm_read_UBYTE (modreader);
187 	    }
188 	  if (flag & 64)
189 	    _mm_read_UBYTE (modreader);
190 	  if (flag & 128)
191 	    {
192 	      _mm_read_UBYTE (modreader);
193 	      _mm_read_UBYTE (modreader);
194 	    }
195 	}
196       else
197 	row++;
198     }
199   return 0;
200 }
201 
202 static BOOL
S3M_ReadPattern(void)203 S3M_ReadPattern (void)
204 {
205   int row = 0, flag, ch;
206   S3MNOTE *n, dummy;
207 
208   /* clear pattern data */
209   memset (s3mbuf, 255, 32 * 64 * sizeof (S3MNOTE));
210 
211   while (row < 64)
212     {
213       flag = _mm_read_UBYTE (modreader);
214 
215       if (_mm_eof (modreader))
216 	{
217 	  _mm_errno = MMERR_LOADING_PATTERN;
218 	  return 0;
219 	}
220 
221       if (flag)
222 	{
223 	  ch = remap[flag & 31];
224 
225 	  if (ch != -1)
226 	    n = &s3mbuf[(64U * ch) + row];
227 	  else
228 	    n = &dummy;
229 
230 	  if (flag & 32)
231 	    {
232 	      n->note = _mm_read_UBYTE (modreader);
233 	      n->ins = _mm_read_UBYTE (modreader);
234 	    }
235 	  if (flag & 64)
236 	    n->vol = _mm_read_UBYTE (modreader);
237 	  if (flag & 128)
238 	    {
239 	      n->cmd = _mm_read_UBYTE (modreader);
240 	      n->inf = _mm_read_UBYTE (modreader);
241 	    }
242 	}
243       else
244 	row++;
245     }
246   return 1;
247 }
248 
249 static UBYTE *
S3M_ConvertTrack(S3MNOTE * tr)250 S3M_ConvertTrack (S3MNOTE * tr)
251 {
252   int t;
253 
254   UniReset ();
255   for (t = 0; t < 64; t++)
256     {
257       UBYTE note, ins, vol;
258 
259       note = tr[t].note;
260       ins = tr[t].ins;
261       vol = tr[t].vol;
262 
263       if ((ins) && (ins != 255))
264 	UniInstrument (ins - 1);
265       if (note != 255)
266 	{
267 	  if (note == 254)
268 	    {
269 	      UniPTEffect (0xc, 0);	/* note cut command */
270 	      vol = 255;
271 	    }
272 	  else
273 	    UniNote (((note >> 4) * OCTAVE) + (note & 0xf));	/* normal note */
274 	}
275       if (vol < 255)
276 	UniPTEffect (0xc, vol);
277 
278       S3MIT_ProcessCmd (tr[t].cmd, tr[t].inf, 1);
279       UniNewline ();
280     }
281   return UniDup ();
282 }
283 
284 static BOOL
S3M_Load(BOOL curious)285 S3M_Load (BOOL curious)
286 {
287   int t, u, track = 0;
288   SAMPLE *q;
289   UBYTE pan[32];
290 
291   /* try to read module header */
292   _mm_read_string (mh->songname, 28, modreader);
293   mh->t1a = _mm_read_UBYTE (modreader);
294   mh->type = _mm_read_UBYTE (modreader);
295   _mm_read_UBYTES (mh->unused1, 2, modreader);
296   mh->ordnum = _mm_read_I_UWORD (modreader);
297   mh->insnum = _mm_read_I_UWORD (modreader);
298   mh->patnum = _mm_read_I_UWORD (modreader);
299   mh->flags = _mm_read_I_UWORD (modreader);
300   mh->tracker = _mm_read_I_UWORD (modreader);
301   mh->fileformat = _mm_read_I_UWORD (modreader);
302   _mm_read_string (mh->scrm, 4, modreader);
303   mh->mastervol = _mm_read_UBYTE (modreader);
304   mh->initspeed = _mm_read_UBYTE (modreader);
305   mh->inittempo = _mm_read_UBYTE (modreader);
306   mh->mastermult = _mm_read_UBYTE (modreader);
307   mh->ultraclick = _mm_read_UBYTE (modreader);
308   mh->pantable = _mm_read_UBYTE (modreader);
309   _mm_read_UBYTES (mh->unused2, 8, modreader);
310   mh->special = _mm_read_I_UWORD (modreader);
311   _mm_read_UBYTES (mh->channels, 32, modreader);
312 
313   if (_mm_eof (modreader))
314     {
315       _mm_errno = MMERR_LOADING_HEADER;
316       return 0;
317     }
318 
319   /* set module variables */
320   of.songname = DupStr (mh->songname, 28, 0);
321   of.numpat = mh->patnum;
322   of.reppos = 0;
323   of.numins = of.numsmp = mh->insnum;
324   of.initspeed = mh->initspeed;
325   of.inittempo = mh->inittempo;
326   of.initvolume = mh->mastervol << 1;
327   of.flags |= UF_ARPMEM;
328   if ((mh->tracker == 0x1300) || (mh->flags & 64))
329     of.flags |= UF_S3MSLIDES;
330 
331   /* read the order data */
332   if (!AllocPositions (mh->ordnum))
333     return 0;
334   if (!(origpositions = _mm_calloc (mh->ordnum, sizeof (UWORD))))
335     return 0;
336 
337   for (t = 0; t < mh->ordnum; t++)
338     {
339       origpositions[t] = _mm_read_UBYTE (modreader);
340       if ((origpositions[t] >= mh->patnum) && (origpositions[t] < 254))
341 	origpositions[t] = 255 /*mh->patnum-1 */ ;
342     }
343 
344   if (_mm_eof (modreader))
345     {
346       _mm_errno = MMERR_LOADING_HEADER;
347       return 0;
348     }
349 
350   poslookupcnt = mh->ordnum;
351   S3MIT_CreateOrders (curious);
352 
353   if (!(paraptr = (UWORD *) _mm_malloc ((of.numins + of.numpat) * sizeof (UWORD))))
354     return 0;
355 
356   /* read the instrument+pattern parapointers */
357   _mm_read_I_UWORDS (paraptr, of.numins + of.numpat, modreader);
358 
359   if (mh->pantable == 252)
360     {
361       /* read the panning table (ST 3.2 addition.  See below for further
362          portions of channel panning [past reampper]). */
363       _mm_read_UBYTES (pan, 32, modreader);
364     }
365 
366   if (_mm_eof (modreader))
367     {
368       _mm_errno = MMERR_LOADING_HEADER;
369       return 0;
370     }
371 
372   /* load samples */
373   if (!AllocSamples ())
374     return 0;
375   q = of.samples;
376   for (t = 0; t < of.numins; t++)
377     {
378       S3MSAMPLE s;
379 
380       /* seek to instrument position */
381       _mm_fseek (modreader, ((long) paraptr[t]) << 4, SEEK_SET);
382       /* and load sample info */
383       s.type = _mm_read_UBYTE (modreader);
384       _mm_read_string (s.filename, 12, modreader);
385       s.memsegh = _mm_read_UBYTE (modreader);
386       s.memsegl = _mm_read_I_UWORD (modreader);
387       s.length = _mm_read_I_ULONG (modreader);
388       s.loopbeg = _mm_read_I_ULONG (modreader);
389       s.loopend = _mm_read_I_ULONG (modreader);
390       s.volume = _mm_read_UBYTE (modreader);
391       s.dsk = _mm_read_UBYTE (modreader);
392       s.pack = _mm_read_UBYTE (modreader);
393       s.flags = _mm_read_UBYTE (modreader);
394       s.c2spd = _mm_read_I_ULONG (modreader);
395       _mm_read_UBYTES (s.unused, 12, modreader);
396       _mm_read_string (s.sampname, 28, modreader);
397       _mm_read_string (s.scrs, 4, modreader);
398 
399       /* ScreamTracker imposes a 64000 bytes (not 64k !) limit */
400       if (s.length > 64000)
401         s.length = 64000;
402 
403       if (_mm_eof (modreader))
404 	{
405 	  _mm_errno = MMERR_LOADING_SAMPLEINFO;
406 	  return 0;
407 	}
408 
409       q->samplename = DupStr (s.sampname, 28, 0);
410       q->speed = s.c2spd;
411       q->length = s.length;
412       q->loopstart = s.loopbeg > s.length ? s.length : s.loopbeg;
413       q->loopend = s.loopend > s.length ? s.length : s.loopend;
414       q->volume = s.volume;
415       q->seekpos = (((long) s.memsegh) << 16 | s.memsegl) << 4;
416 
417       if (s.flags & 1)
418 	q->flags |= SF_LOOP;
419       if (s.flags & 4)
420 	q->flags |= SF_16BITS;
421       if (mh->fileformat == 1)
422 	q->flags |= SF_SIGNED;
423 
424       /* don't load sample if it doesn't have the SCRS tag */
425       if (memcmp (s.scrs, "SCRS", 4))
426 	q->length = 0;
427 
428       q++;
429     }
430 
431   /* determine the number of channels actually used. */
432   of.numchn = 0;
433   memset (remap, -1, 32 * sizeof (UBYTE));
434   for (t = 0; t < of.numpat; t++)
435     {
436       /* seek to pattern position (+2 skip pattern length) */
437       _mm_fseek (modreader, (long) ((paraptr[of.numins + t]) << 4) + 2, SEEK_SET);
438       if (S3M_GetNumChannels ())
439 	return 0;
440     }
441   /* then we can decide the module type */
442   t = mh->tracker >> 12;
443   if ((!t) || (t > 3))
444     t = NUMTRACKERS - 1;	/* unknown tracker */
445   else
446     {
447       if (mh->tracker >= 0x3217)
448 	t = NUMTRACKERS + 1;	/* IT 2.14p4 */
449       else if (mh->tracker >= 0x3216)
450 	t = NUMTRACKERS;	/* IT 2.14p3 */
451       else
452 	t--;
453     }
454   of.modtype = strdup (S3M_Version[t]);
455   if (t < NUMTRACKERS)
456     {
457       of.modtype[numeric[t]] = ((mh->tracker >> 8) & 0xf) + '0';
458       of.modtype[numeric[t] + 2] = ((mh->tracker >> 4) & 0xf) + '0';
459       of.modtype[numeric[t] + 3] = ((mh->tracker) & 0xf) + '0';
460     }
461 
462   /* build the remap array  */
463   for (t = 0; t < 32; t++)
464     if (!remap[t])
465       remap[t] = of.numchn++;
466 
467   /* set panning positions after building remap chart! */
468   for (t = 0; t < 32; t++)
469     if ((mh->channels[t] < 32) && (remap[t] != -1))
470       {
471 	if (mh->channels[t] < 8)
472 	  of.panning[remap[t]] = 0x20;	/* 0x30 = std s3m val */
473 	else
474 	  of.panning[remap[t]] = 0xd0;	/* 0xc0 = std s3m val */
475       }
476   if (mh->pantable == 252)
477     /* set panning positions according to panning table (new for st3.2) */
478     for (t = 0; t < 32; t++)
479       if ((pan[t] & 0x20) && (mh->channels[t] < 32) && (remap[t] != -1))
480 	of.panning[remap[t]] = (pan[t] & 0xf) << 4;
481 
482   /* load pattern info */
483   of.numtrk = of.numpat * of.numchn;
484   if (!AllocTracks ())
485     return 0;
486   if (!AllocPatterns ())
487     return 0;
488 
489   for (t = 0; t < of.numpat; t++)
490     {
491       /* seek to pattern position (+2 skip pattern length) */
492       _mm_fseek (modreader, (((long) paraptr[of.numins + t]) << 4) + 2, SEEK_SET);
493       if (!S3M_ReadPattern ())
494 	return 0;
495       for (u = 0; u < of.numchn; u++)
496 	if (!(of.tracks[track++] = S3M_ConvertTrack (&s3mbuf[u * 64])))
497 	  return 0;
498     }
499 
500   return 1;
501 }
502 
503 static CHAR *
S3M_LoadTitle(void)504 S3M_LoadTitle (void)
505 {
506   CHAR s[28];
507 
508   _mm_fseek (modreader, 0, SEEK_SET);
509   if (!_mm_read_UBYTES (s, 28, modreader))
510     return NULL;
511 
512   return (DupStr (s, 28, 0));
513 }
514 
515 /*========== Loader information */
516 
517 MLOADER load_s3m =
518 {
519   NULL,
520   "S3M",
521   "S3M (Scream Tracker 3)",
522   S3M_Init,
523   S3M_Test,
524   S3M_Load,
525   S3M_Cleanup,
526   S3M_LoadTitle
527 };
528 
529 /* ex:set ts=4: */
530