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   STMIK 0.2 (STX) module loader
26 
27 ==============================================================================*/
28 
29 /*
30 
31    Written by Claudio Matsuoka <claudio@helllabs.org>
32 
33  */
34 
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 
39 #include <string.h>
40 
41 #include "unimod_priv.h"
42 
43 /*========== Module structure */
44 
45 /* header */
46 typedef struct STXHEADER
47   {
48     CHAR songname[20];
49     CHAR trackername[8];
50     UWORD patsize;
51     UWORD unknown1;
52     UWORD patptr;
53     UWORD insptr;
54     UWORD chnptr;		/* not sure */
55     UWORD unknown2;
56     UWORD unknown3;
57     UBYTE mastermult;
58     UBYTE initspeed;
59     UWORD unknown4;
60     UWORD unknown5;
61     UWORD patnum;
62     UWORD insnum;
63     UWORD ordnum;
64     UWORD unknown6;
65     UWORD unknown7;
66     UWORD unknown8;
67     CHAR scrm[4];
68   }
69 STXHEADER;
70 
71 /* sample information */
72 typedef struct STXSAMPLE
73   {
74     UBYTE type;
75     CHAR filename[12];
76     UBYTE memsegh;
77     UWORD memsegl;
78     ULONG length;
79     ULONG loopbeg;
80     ULONG loopend;
81     UBYTE volume;
82     UBYTE dsk;
83     UBYTE pack;
84     UBYTE flags;
85     ULONG c2spd;
86     UBYTE unused[12];
87     CHAR sampname[28];
88     CHAR scrs[4];
89   }
90 STXSAMPLE;
91 
92 typedef struct STXNOTE
93   {
94     UBYTE note, ins, vol, cmd, inf;
95   }
96 STXNOTE;
97 
98 /*========== Loader variables */
99 
100 static STXNOTE *stxbuf = NULL;	/* pointer to a complete STX pattern */
101 static STXHEADER *mh = NULL;
102 static UWORD *paraptr = NULL;	/* parapointer array (see STX docs) */
103 
104 /*========== Loader code */
105 
106 static BOOL
STX_Test(void)107 STX_Test (void)
108 {
109   UBYTE id[8];
110   int t;
111 
112   _mm_fseek(modreader,0x14,SEEK_SET);
113   if(!_mm_read_UBYTES(id, 8, modreader))
114     return 0;
115 
116   for(t=0;t<STM_NTRACKERS;t++)
117     if(!memcmp(id,STM_Signatures[t],8)) return 1;
118 
119   _mm_fseek (modreader, 0x3C, SEEK_SET);
120   if (!_mm_read_UBYTES (id, 4, modreader))
121     return 0;
122   if (memcmp (id, "SCRM", 4))
123     return 0;
124 
125   return 1;
126 }
127 
128 static BOOL
STX_Init(void)129 STX_Init (void)
130 {
131   if (!(stxbuf = (STXNOTE *) _mm_malloc (4 * 64 * sizeof (STXNOTE))))
132     return 0;
133   if (!(mh = (STXHEADER *) _mm_malloc (sizeof (STXHEADER))))
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
STX_Cleanup(void)143 STX_Cleanup (void)
144 {
145   _mm_free (stxbuf);
146   _mm_free (paraptr);
147   _mm_free (poslookup);
148   _mm_free (mh);
149 }
150 
151 static BOOL
STX_ReadPattern(void)152 STX_ReadPattern (void)
153 {
154   int row = 0, flag, ch;
155   STXNOTE *n, dummy;
156 
157   /* clear pattern data */
158   memset (stxbuf, 255, 4 * 64 * sizeof (STXNOTE));
159 
160   while (row < 64)
161     {
162       flag = _mm_read_UBYTE (modreader);
163 
164       if (_mm_eof (modreader))
165 	{
166 	  _mm_errno = MMERR_LOADING_PATTERN;
167 	  return 0;
168 	}
169 
170       if (flag)
171 	{
172 	  ch = flag & 31;
173 
174 	  if ((ch >= 0) && (ch < 4))
175 	    n = &stxbuf[(64U * ch) + row];
176 	  else
177 	    n = &dummy;
178 
179 	  if (flag & 32)
180 	    {
181 	      n->note = _mm_read_UBYTE (modreader);
182 	      n->ins = _mm_read_UBYTE (modreader);
183 	    }
184 	  if (flag & 64)
185 	    {
186 	      n->vol = _mm_read_UBYTE (modreader);
187 	      if (n->vol > 64)
188 	        n->vol = 64;
189 	    }
190 	  if (flag & 128)
191 	    {
192 	      n->cmd = _mm_read_UBYTE (modreader);
193 	      n->inf = _mm_read_UBYTE (modreader);
194 	    }
195 	}
196       else
197 	row++;
198     }
199   return 1;
200 }
201 
202 static UBYTE *
STX_ConvertTrack(STXNOTE * tr)203 STX_ConvertTrack (STXNOTE * tr)
204 {
205   int t;
206 
207   UniReset ();
208   for (t = 0; t < 64; t++)
209     {
210       UBYTE note, ins, vol, cmd, inf;
211 
212       note = tr[t].note;
213       ins = tr[t].ins;
214       vol = tr[t].vol;
215       cmd = tr[t].cmd;
216       inf = tr[t].inf;
217 
218       if ((ins) && (ins != 255))
219 	UniInstrument (ins - 1);
220       if ((note) && (note != 255))
221 	{
222 	  if (note == 254)
223 	    {
224 	      UniPTEffect (0xc, 0);	/* note cut command */
225 	      vol = 255;
226 	    }
227 	  else
228 	    UniNote (24 + ((note >> 4) * OCTAVE) + (note & 0xf));	/* normal note */
229 	}
230 
231       if (vol < 255)
232 	UniPTEffect (0xc, vol);
233 
234       if (cmd < 255)
235 	switch (cmd)
236 	  {
237 	  case 1:		/* Axx set speed to xx */
238 	    UniPTEffect (0xf, inf >> 4);
239 	    break;
240 	  case 2:		/* Bxx position jump */
241 	    UniPTEffect (0xb, inf);
242 	    break;
243 	  case 3:		/* Cxx patternbreak to row xx */
244 	    UniPTEffect (0xd, (((inf & 0xf0) >> 4) * 10) + (inf & 0xf));
245 	    break;
246 	  case 4:		/* Dxy volumeslide */
247 	    UniEffect (UNI_S3MEFFECTD, inf);
248 	    break;
249 	  case 5:		/* Exy toneslide down */
250 	    UniEffect (UNI_S3MEFFECTE, inf);
251 	    break;
252 	  case 6:		/* Fxy toneslide up */
253 	    UniEffect (UNI_S3MEFFECTF, inf);
254 	    break;
255 	  case 7:		/* Gxx Tone portamento,speed xx */
256 	    UniPTEffect (0x3, inf);
257 	    break;
258 	  case 8:		/* Hxy vibrato */
259 	    UniPTEffect (0x4, inf);
260 	    break;
261 	  case 9:		/* Ixy tremor, ontime x, offtime y */
262 	    UniEffect (UNI_S3MEFFECTI, inf);
263 	    break;
264 	  case 0:		/* protracker arpeggio */
265 	    if (!inf)
266 	      break;
267 	    /* fall through */
268 	  case 0xa:		/* Jxy arpeggio */
269 	    UniPTEffect (0x0, inf);
270 	    break;
271 	  case 0xb:		/* Kxy Dual command H00 & Dxy */
272 	    UniPTEffect (0x4, 0);
273 	    UniEffect (UNI_S3MEFFECTD, inf);
274 	    break;
275 	  case 0xc:		/* Lxy Dual command G00 & Dxy */
276 	    UniPTEffect (0x3, 0);
277 	    UniEffect (UNI_S3MEFFECTD, inf);
278 	    break;
279 	    /* Support all these above, since ST2 can LOAD these values but can
280 	       actually only play up to J - and J is only half-way implemented
281 	       in ST2 */
282 	  case 0x18:		/* Xxx amiga panning command 8xx */
283 	    UniPTEffect (0x8, inf);
284 	    break;
285 	  }
286       UniNewline ();
287     }
288   return UniDup ();
289 }
290 
291 static BOOL
STX_Load(BOOL curious)292 STX_Load (BOOL curious)
293 {
294   int t, u, track = 0;
295   int version = 0;
296   SAMPLE *q;
297   const char *tracker;
298 
299   /* try to read module header */
300   _mm_read_string (mh->songname, 20, modreader);
301   _mm_read_string (mh->trackername, 8, modreader);
302   mh->patsize = _mm_read_I_UWORD (modreader);
303   mh->unknown1 = _mm_read_I_UWORD (modreader);
304   mh->patptr = _mm_read_I_UWORD (modreader);
305   mh->insptr = _mm_read_I_UWORD (modreader);
306   mh->chnptr = _mm_read_I_UWORD (modreader);
307   mh->unknown2 = _mm_read_I_UWORD (modreader);
308   mh->unknown3 = _mm_read_I_UWORD (modreader);
309   mh->mastermult = _mm_read_UBYTE (modreader);
310   mh->initspeed = _mm_read_UBYTE (modreader) >> 4;
311   mh->unknown4 = _mm_read_I_UWORD (modreader);
312   mh->unknown5 = _mm_read_I_UWORD (modreader);
313   mh->patnum = _mm_read_I_UWORD (modreader);
314   mh->insnum = _mm_read_I_UWORD (modreader);
315   mh->ordnum = _mm_read_I_UWORD (modreader);
316   mh->unknown6 = _mm_read_I_UWORD (modreader);
317   mh->unknown7 = _mm_read_I_UWORD (modreader);
318   mh->unknown8 = _mm_read_I_UWORD (modreader);
319   _mm_read_string (mh->scrm, 4, modreader);
320 
321   if (_mm_eof (modreader))
322     {
323       _mm_errno = MMERR_LOADING_HEADER;
324       return 0;
325     }
326 
327   tracker = "unknown tracker";
328   for (t = 0; t < STM_NTRACKERS; t++)
329     if (!memcmp (mh->trackername, STM_Signatures[t], 8))
330       {
331 	tracker = STM_Version[t];
332 	break;
333       }
334 
335   of.modtype = _mm_malloc(
336     strlen(tracker) +
337     strlen("STM2STX 1.x ()") + 1);
338 
339   sprintf(of.modtype, "STM2STX 1.x (%s)", tracker);
340 
341   /* set module variables */
342   of.songname = DupStr (mh->songname, 20, 1);
343   of.numpat = mh->patnum;
344   of.reppos = 0;
345   of.numins = of.numsmp = mh->insnum;
346   of.initspeed = mh->initspeed;
347   of.inittempo = 125;
348   of.numchn = 4;
349   of.flags |= UF_S3MSLIDES;
350 
351   if (!(paraptr = (UWORD *) _mm_malloc ((of.numins + of.numpat) * sizeof (UWORD))))
352     return 0;
353 
354   /* read the instrument+pattern parapointers */
355   _mm_fseek (modreader, mh->insptr << 4, SEEK_SET);
356   _mm_read_I_UWORDS (paraptr, of.numins, modreader);
357   _mm_fseek (modreader, mh->patptr << 4, SEEK_SET);
358   _mm_read_I_UWORDS (paraptr + of.numins, of.numpat, modreader);
359 
360   /* check module version */
361   _mm_fseek (modreader, paraptr[of.numins] << 4, SEEK_SET);
362   version = _mm_read_I_UWORD (modreader);
363   if (version == mh->patsize)
364     {
365       version = 0x10;
366       of.modtype[10] = '0';
367     }
368   else
369     {
370       version = 0x11;
371       of.modtype[10] = '1';
372     }
373 
374   /* read the order data */
375   _mm_fseek (modreader, (mh->chnptr << 4) + 32, SEEK_SET);
376   if (!AllocPositions (mh->ordnum))
377     return 0;
378   for (t = 0; t < mh->ordnum; t++)
379     {
380       of.positions[t] = _mm_read_UBYTE (modreader);
381       _mm_fseek (modreader, 4, SEEK_CUR);
382     }
383 
384   of.numpos = 0;
385   poslookupcnt = mh->ordnum;
386   for (t = 0; t < mh->ordnum; t++)
387     {
388       of.positions[of.numpos] = of.positions[t];
389       poslookup[t] = of.numpos;	/* bug fix for freaky S3Ms */
390       if (of.positions[t] < 254)
391 	of.numpos++;
392       else
393 	/* special end of song pattern */
394       if ((of.positions[t] == 255) && (!curious))
395 	break;
396     }
397 
398   if (_mm_eof (modreader))
399     {
400       _mm_errno = MMERR_LOADING_HEADER;
401       return 0;
402     }
403 
404   /* load samples */
405   if (!AllocSamples ())
406     return 0;
407   for (q = of.samples, t = 0; t < of.numins; t++, q++)
408     {
409       STXSAMPLE s;
410 
411       /* seek to instrument position */
412       _mm_fseek (modreader, ((long) paraptr[t]) << 4, SEEK_SET);
413       /* and load sample info */
414       s.type = _mm_read_UBYTE (modreader);
415       _mm_read_string (s.filename, 12, modreader);
416       s.memsegh = _mm_read_UBYTE (modreader);
417       s.memsegl = _mm_read_I_UWORD (modreader);
418       s.length = _mm_read_I_ULONG (modreader);
419       s.loopbeg = _mm_read_I_ULONG (modreader);
420       s.loopend = _mm_read_I_ULONG (modreader);
421       s.volume = _mm_read_UBYTE (modreader);
422       s.dsk = _mm_read_UBYTE (modreader);
423       s.pack = _mm_read_UBYTE (modreader);
424       s.flags = _mm_read_UBYTE (modreader);
425       s.c2spd = _mm_read_I_ULONG (modreader);
426       _mm_read_UBYTES (s.unused, 12, modreader);
427       _mm_read_string (s.sampname, 28, modreader);
428       _mm_read_string (s.scrs, 4, modreader);
429 
430       if (_mm_eof (modreader))
431 	{
432 	  _mm_errno = MMERR_LOADING_SAMPLEINFO;
433 	  return 0;
434 	}
435 
436       q->samplename = DupStr (s.sampname, 28, 1);
437       q->speed = (s.c2spd * 8363) / 8448;
438       q->length = s.length;
439       q->loopstart = s.loopbeg;
440       q->loopend = s.loopend;
441       q->volume = s.volume;
442       q->seekpos = (((long) s.memsegh) << 16 | s.memsegl) << 4;
443       q->flags |= SF_SIGNED;
444 
445       /* fix for bad converted STMs */
446       if (q->loopstart >= q->length)
447 	q->loopstart = q->loopend = 0;
448 
449       /* some modules come with loopstart == loopend == 0, yet have the
450        * looping flag set */
451       if ((s.flags & 1) && (q->loopstart != q->loopend))
452 	{
453 	  q->flags |= SF_LOOP;
454 	  if (q->loopend > q->length)
455 	    q->loopend = q->length;
456 	}
457       if (s.flags & 4)
458 	q->flags |= SF_16BITS;
459     }
460 
461   /* load pattern info */
462   of.numtrk = of.numpat * of.numchn;
463   if (!AllocTracks ())
464     return 0;
465   if (!AllocPatterns ())
466     return 0;
467 
468   for (t = 0; t < of.numpat; t++)
469     {
470       /* seek to pattern position (+2 skip pattern length) */
471       _mm_fseek (modreader, (((long) paraptr[of.numins + t]) << 4) +
472 		 (version == 0x10 ? 2 : 0), SEEK_SET);
473       if (!STX_ReadPattern ())
474 	return 0;
475       for (u = 0; u < of.numchn; u++)
476 	if (!(of.tracks[track++] = STX_ConvertTrack (&stxbuf[u * 64])))
477 	  return 0;
478     }
479 
480   return 1;
481 }
482 
483 static CHAR *
STX_LoadTitle(void)484 STX_LoadTitle (void)
485 {
486   CHAR s[28];
487 
488   _mm_fseek (modreader, 0, SEEK_SET);
489   if (!_mm_read_UBYTES (s, 20, modreader))
490     return NULL;
491 
492   return (DupStr (s, 28, 1));
493 }
494 
495 /*========== Loader information */
496 
497 MLOADER load_stx =
498 {
499   NULL,
500   "STX",
501   "STX (Scream Tracker Music Interface Kit)",
502   STX_Init,
503   STX_Test,
504   STX_Load,
505   STX_Cleanup,
506   STX_LoadTitle
507 };
508 
509 /* ex:set ts=4: */
510