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 2 (STM) 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 /* sample information */
40 typedef struct STMSAMPLE
41 {
42 CHAR filename[12];
43 UBYTE unused; /* 0x00 */
44 UBYTE instdisk; /* Instrument disk */
45 UWORD reserved;
46 UWORD length; /* Sample length */
47 UWORD loopbeg; /* Loop start point */
48 UWORD loopend; /* Loop end point */
49 UBYTE volume; /* Volume */
50 UBYTE reserved2;
51 UWORD c2spd; /* Good old c2spd */
52 ULONG reserved3;
53 UWORD isa;
54 }
55 STMSAMPLE;
56
57 /* header */
58 typedef struct STMHEADER
59 {
60 CHAR songname[20];
61 CHAR trackername[8]; /* !Scream! for ST 2.xx */
62 UBYTE unused; /* 0x1A */
63 UBYTE filetype; /* 1=song, 2=module */
64 UBYTE ver_major;
65 UBYTE ver_minor;
66 UBYTE inittempo; /* initspeed= stm inittempo>>4 */
67 UBYTE numpat; /* number of patterns */
68 UBYTE globalvol;
69 UBYTE reserved[13];
70 STMSAMPLE sample[31]; /* STM sample data */
71 UBYTE patorder[128]; /* Docs say 64 - actually 128 */
72 }
73 STMHEADER;
74
75 typedef struct STMNOTE
76 {
77 UBYTE note, insvol, volcmd, cmdinf;
78 }
79 STMNOTE;
80
81 /*========== Loader variables */
82
83 static STMNOTE *stmbuf = NULL;
84 static STMHEADER *mh = NULL;
85
86 /*========== Loader code */
87
88 static BOOL
STM_Test(void)89 STM_Test (void)
90 {
91 UBYTE str[44];
92 int t;
93
94 _mm_fseek (modreader, 20, SEEK_SET);
95 _mm_read_UBYTES (str, 44, modreader);
96 if (str[9] != 2)
97 return 0; /* STM Module = filetype 2 */
98
99 if(!memcmp (str + 40, "SCRM", 4))
100 return 0;
101
102 for (t=0;t<STM_NTRACKERS;t++)
103 if(!memcmp (str, STM_Signatures[t], 8))
104 return 1;
105
106 return 0;
107 }
108
109 static BOOL
STM_Init(void)110 STM_Init (void)
111 {
112 if (!(mh = (STMHEADER *) _mm_malloc (sizeof (STMHEADER))))
113 return 0;
114 if (!(stmbuf = (STMNOTE *) _mm_calloc (64U * 4, sizeof (STMNOTE))))
115 return 0;
116
117 return 1;
118 }
119
120 static void
STM_Cleanup(void)121 STM_Cleanup (void)
122 {
123 _mm_free (mh);
124 _mm_free (stmbuf);
125 }
126
127 static void
STM_ConvertNote(STMNOTE * n)128 STM_ConvertNote (STMNOTE * n)
129 {
130 UBYTE note, ins, vol, cmd, inf;
131
132 /* extract the various information from the 4 bytes that make up a note */
133 note = n->note;
134 ins = n->insvol >> 3;
135 vol = (n->insvol & 7) + ((n->volcmd & 0x70) >> 1);
136 cmd = n->volcmd & 15;
137 inf = n->cmdinf;
138
139 if ((ins) && (ins < 32))
140 UniInstrument (ins - 1);
141
142 /* special values of [SBYTE0] are handled here
143 we have no idea if these strange values will ever be encountered.
144 but it appears as those stms sound correct. */
145 if ((note == 254) || (note == 252))
146 {
147 UniPTEffect (0xc, 0); /* note cut */
148 n->volcmd |= 0x80;
149 }
150 else
151 /* if note < 251, then all three bytes are stored in the file */
152 if (note < 251)
153 UniNote ((((note >> 4) + 2) * OCTAVE) + (note & 0xf));
154
155 if ((!(n->volcmd & 0x80)) && (vol < 65))
156 UniPTEffect (0xc, vol);
157 if (cmd != 255)
158 switch (cmd)
159 {
160 case 1: /* Axx set speed to xx */
161 UniPTEffect (0xf, inf >> 4);
162 break;
163 case 2: /* Bxx position jump */
164 UniPTEffect (0xb, inf);
165 break;
166 case 3: /* Cxx patternbreak to row xx */
167 UniPTEffect (0xd, (((inf & 0xf0) >> 4) * 10) + (inf & 0xf));
168 break;
169 case 4: /* Dxy volumeslide */
170 UniEffect (UNI_S3MEFFECTD, inf);
171 break;
172 case 5: /* Exy toneslide down */
173 UniEffect (UNI_S3MEFFECTE, inf);
174 break;
175 case 6: /* Fxy toneslide up */
176 UniEffect (UNI_S3MEFFECTF, inf);
177 break;
178 case 7: /* Gxx Tone portamento,speed xx */
179 UniPTEffect (0x3, inf);
180 break;
181 case 8: /* Hxy vibrato */
182 UniPTEffect (0x4, inf);
183 break;
184 case 9: /* Ixy tremor, ontime x, offtime y */
185 UniEffect (UNI_S3MEFFECTI, inf);
186 break;
187 case 0: /* protracker arpeggio */
188 if (!inf)
189 break;
190 /* fall through */
191 case 0xa: /* Jxy arpeggio */
192 UniPTEffect (0x0, inf);
193 break;
194 case 0xb: /* Kxy Dual command H00 & Dxy */
195 UniPTEffect (0x4, 0);
196 UniEffect (UNI_S3MEFFECTD, inf);
197 break;
198 case 0xc: /* Lxy Dual command G00 & Dxy */
199 UniPTEffect (0x3, 0);
200 UniEffect (UNI_S3MEFFECTD, inf);
201 break;
202 /* Support all these above, since ST2 can LOAD these values but can
203 actually only play up to J - and J is only half-way implemented
204 in ST2 */
205 case 0x18: /* Xxx amiga panning command 8xx */
206 UniPTEffect (0x8, inf);
207 break;
208 }
209 }
210
211 static UBYTE *
STM_ConvertTrack(STMNOTE * n)212 STM_ConvertTrack (STMNOTE * n)
213 {
214 int t;
215
216 UniReset ();
217 for (t = 0; t < 64; t++)
218 {
219 STM_ConvertNote (n);
220 UniNewline ();
221 n += of.numchn;
222 }
223 return UniDup ();
224 }
225
226 static BOOL
STM_LoadPatterns(void)227 STM_LoadPatterns (void)
228 {
229 int t, s, tracks = 0;
230
231 if (!AllocPatterns ())
232 return 0;
233 if (!AllocTracks ())
234 return 0;
235
236 /* Allocate temporary buffer for loading and converting the patterns */
237 for (t = 0; t < of.numpat; t++)
238 {
239 for (s = 0; s < (64U * of.numchn); s++)
240 {
241 stmbuf[s].note = _mm_read_UBYTE (modreader);
242 stmbuf[s].insvol = _mm_read_UBYTE (modreader);
243 stmbuf[s].volcmd = _mm_read_UBYTE (modreader);
244 stmbuf[s].cmdinf = _mm_read_UBYTE (modreader);
245 }
246
247 if (_mm_eof (modreader))
248 {
249 _mm_errno = MMERR_LOADING_PATTERN;
250 return 0;
251 }
252
253 for (s = 0; s < of.numchn; s++)
254 if (!(of.tracks[tracks++] = STM_ConvertTrack (stmbuf + s)))
255 return 0;
256 }
257 return 1;
258 }
259
260 static BOOL
STM_Load(BOOL curious)261 STM_Load (BOOL curious)
262 {
263 int t;
264 ULONG ourISA; /* We must generate our own ISA, it's not stored in stm */
265 SAMPLE *q;
266
267 /* try to read stm header */
268 _mm_read_string (mh->songname, 20, modreader);
269 _mm_read_string (mh->trackername, 8, modreader);
270 mh->unused = _mm_read_UBYTE (modreader);
271 mh->filetype = _mm_read_UBYTE (modreader);
272 mh->ver_major = _mm_read_UBYTE (modreader);
273 mh->ver_minor = _mm_read_UBYTE (modreader);
274 mh->inittempo = _mm_read_UBYTE (modreader);
275 if (!mh->inittempo)
276 {
277 _mm_errno = MMERR_NOT_A_MODULE;
278 return 0;
279 }
280 mh->numpat = _mm_read_UBYTE (modreader);
281 mh->globalvol = _mm_read_UBYTE (modreader);
282 _mm_read_UBYTES (mh->reserved, 13, modreader);
283
284 for (t = 0; t < 31; t++)
285 {
286 STMSAMPLE *s = &mh->sample[t]; /* STM sample data */
287
288 _mm_read_string (s->filename, 12, modreader);
289 s->unused = _mm_read_UBYTE (modreader);
290 s->instdisk = _mm_read_UBYTE (modreader);
291 s->reserved = _mm_read_I_UWORD (modreader);
292 s->length = _mm_read_I_UWORD (modreader);
293 s->loopbeg = _mm_read_I_UWORD (modreader);
294 s->loopend = _mm_read_I_UWORD (modreader);
295 s->volume = _mm_read_UBYTE (modreader);
296 s->reserved2 = _mm_read_UBYTE (modreader);
297 s->c2spd = _mm_read_I_UWORD (modreader);
298 s->reserved3 = _mm_read_I_ULONG (modreader);
299 s->isa = _mm_read_I_UWORD (modreader);
300 }
301 _mm_read_UBYTES (mh->patorder, 128, modreader);
302
303 if (_mm_eof (modreader))
304 {
305 _mm_errno = MMERR_LOADING_HEADER;
306 return 0;
307 }
308
309 /* set module variables */
310 for (t = 0; t < STM_NTRACKERS; t++)
311 if (!memcmp (mh->trackername, STM_Signatures[t], 8))
312 break;
313 of.modtype = strdup (STM_Version[t]);
314 of.songname = DupStr (mh->songname, 20, 1); /* make a cstr of songname */
315 of.numpat = mh->numpat;
316 of.inittempo = 125; /* mh->inittempo+0x1c; */
317 of.initspeed = mh->inittempo >> 4;
318 of.numchn = 4; /* get number of channels */
319 of.reppos = 0;
320 of.flags |= UF_S3MSLIDES;
321
322 t = 0;
323 if (!AllocPositions (0x80))
324 return 0;
325 /* 99 terminates the patorder list */
326 while ((mh->patorder[t] != 99) && (mh->patorder[t] < mh->numpat))
327 {
328 of.positions[t] = mh->patorder[t];
329 t++;
330 }
331 if (mh->patorder[t] != 99)
332 t++;
333 of.numpos = t;
334 of.numtrk = of.numpat * of.numchn;
335 of.numins = of.numsmp = 31;
336
337 if (!AllocSamples ())
338 return 0;
339 if (!STM_LoadPatterns ())
340 return 0;
341 ourISA = _mm_ftell (modreader);
342 ourISA = (ourISA + 15) & 0xfffffff0; /* normalize */
343
344 for (q = of.samples, t = 0; t < of.numsmp; t++, q++)
345 {
346 /* load sample info */
347 q->samplename = DupStr (mh->sample[t].filename, 12, 1);
348 q->speed = (mh->sample[t].c2spd * 8363L) / 8448;
349 q->volume = mh->sample[t].volume;
350 q->length = mh->sample[t].length;
351 if ( /*(!mh->sample[t].volume)|| */ (q->length == 1))
352 q->length = 0;
353 q->loopstart = mh->sample[t].loopbeg;
354 q->loopend = mh->sample[t].loopend;
355 q->seekpos = ourISA;
356
357 ourISA += q->length;
358 ourISA = (ourISA + 15) & 0xfffffff0; /* normalize */
359
360 /* contrary to the STM specs, sample data is signed */
361 q->flags = SF_SIGNED;
362
363 /* fix for bad STMs */
364 if (q->loopstart >= q->length)
365 q->loopstart = q->loopend = 0;
366
367 if ((q->loopend > 0) && (q->loopend != 0xffff) && (q->loopend!=q->loopstart))
368 q->flags |= SF_LOOP;
369 /* fix replen if repend>length */
370 if (q->loopend > q->length)
371 q->loopend = q->length;
372 }
373 return 1;
374 }
375
376 static CHAR *
STM_LoadTitle(void)377 STM_LoadTitle (void)
378 {
379 CHAR s[20];
380
381 _mm_fseek (modreader, 0, SEEK_SET);
382 if (!_mm_read_UBYTES (s, 20, modreader))
383 return NULL;
384
385 return (DupStr (s, 20, 1));
386 }
387
388 /*========== Loader information */
389
390 MLOADER load_stm =
391 {
392 NULL,
393 "STM",
394 "STM (Scream Tracker)",
395 STM_Init,
396 STM_Test,
397 STM_Load,
398 STM_Cleanup,
399 STM_LoadTitle
400 };
401
402
403 /* ex:set ts=4: */
404