OSDN Git Service

autoreconf
[timidity41/timidity41.git] / libunimod / load_stx.c
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 
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 
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 
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 
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 *
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 
292 STX_Load (BOOL curious)
293 {
294   int t, u, track = 0;
295   int version = 0;
296   SAMPLE *q;
297   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 *
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: */