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