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