OSDN Git Service

Concerning compilaton with vcc or bcc in Msys or cygwin environment.
[timidity41/timidity41.git] / libunimod / load_dsm.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   DSIK internal format (DSM) 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 #define DSM_MAXCHAN (16)
40 #define DSM_MAXORDERS (128)
41
42 typedef struct DSMSONG
43   {
44     CHAR songname[28];
45     UWORD version;
46     UWORD flags;
47     ULONG reserved2;
48     UWORD numord;
49     UWORD numsmp;
50     UWORD numpat;
51     UWORD numtrk;
52     UBYTE globalvol;
53     UBYTE mastervol;
54     UBYTE speed;
55     UBYTE bpm;
56     UBYTE panpos[DSM_MAXCHAN];
57     UBYTE orders[DSM_MAXORDERS];
58   }
59 DSMSONG;
60
61 typedef struct DSMINST
62   {
63     CHAR filename[13];
64     UWORD flags;
65     UBYTE volume;
66     ULONG length;
67     ULONG loopstart;
68     ULONG loopend;
69     ULONG reserved1;
70     UWORD c2spd;
71     UWORD period;
72     CHAR samplename[28];
73   }
74 DSMINST;
75
76 typedef struct DSMNOTE
77   {
78     UBYTE note, ins, vol, cmd, inf;
79   }
80 DSMNOTE;
81
82 #define DSM_SURROUND (0xa4)
83
84 /*========== Loader variables */
85
86 static CHAR *SONGID = "SONG";
87 static CHAR *INSTID = "INST";
88 static CHAR *PATTID = "PATT";
89
90 static UBYTE blockid[4];
91 static ULONG blockln;
92 static ULONG blocklp;
93 static DSMSONG *mh = NULL;
94 static DSMNOTE *dsmbuf = NULL;
95
96 static CHAR DSM_Version[] = "DSIK DSM-format";
97
98 static unsigned char DSMSIG[4 + 4] =
99 {'R', 'I', 'F', 'F', 'D', 'S', 'M', 'F'};
100
101 /*========== Loader code */
102
103 BOOL 
104 DSM_Test (void)
105 {
106   UBYTE id[12];
107
108   if (!_mm_read_UBYTES (id, 12, modreader))
109     return 0;
110   if (!memcmp (id, DSMSIG, 4) && !memcmp (id + 8, DSMSIG + 4, 4))
111     return 1;
112
113   return 0;
114 }
115
116 BOOL 
117 DSM_Init (void)
118 {
119   if (!(dsmbuf = (DSMNOTE *) _mm_malloc (DSM_MAXCHAN * 64 * sizeof (DSMNOTE))))
120     return 0;
121   if (!(mh = (DSMSONG *) _mm_calloc (1, sizeof (DSMSONG))))
122     return 0;
123   return 1;
124 }
125
126 void 
127 DSM_Cleanup (void)
128 {
129   _mm_free (dsmbuf);
130   _mm_free (mh);
131 }
132
133 static BOOL 
134 GetBlockHeader (void)
135 {
136   /* make sure we're at the right position for reading the
137      next riff block, no matter how many bytes read */
138   _mm_fseek (modreader, blocklp + blockln, SEEK_SET);
139
140   while (1)
141     {
142       _mm_read_UBYTES (blockid, 4, modreader);
143       blockln = _mm_read_I_ULONG (modreader);
144       if (_mm_eof (modreader))
145         {
146           _mm_errno = MMERR_LOADING_HEADER;
147           return 0;
148         }
149
150       if (memcmp (blockid, SONGID, 4) && memcmp (blockid, INSTID, 4) &&
151           memcmp (blockid, PATTID, 4))
152         {
153 #ifdef MIKMOD_DEBUG
154           fprintf (stderr, "\rDSM: Skipping unknown block type %4.4s\n", blockid);
155 #endif
156           _mm_fseek (modreader, blockln, SEEK_CUR);
157         }
158       else
159         break;
160     }
161
162   blocklp = _mm_ftell (modreader);
163
164   return 1;
165 }
166
167 static BOOL 
168 DSM_ReadPattern (void)
169 {
170   int flag, row = 0;
171   SWORD length;
172   DSMNOTE *n;
173
174   /* clear pattern data */
175   memset (dsmbuf, 255, DSM_MAXCHAN * 64 * sizeof (DSMNOTE));
176   length = _mm_read_I_SWORD (modreader);
177
178   while (row < 64)
179     {
180       flag = _mm_read_UBYTE (modreader);
181       if ((_mm_eof (modreader)) || (--length < 0))
182         {
183           _mm_errno = MMERR_LOADING_PATTERN;
184           return 0;
185         }
186
187       if (flag)
188         {
189           n = &dsmbuf[((flag & 0xf) * 64) + row];
190           if (flag & 0x80)
191             n->note = _mm_read_UBYTE (modreader);
192           if (flag & 0x40)
193             n->ins = _mm_read_UBYTE (modreader);
194           if (flag & 0x20)
195             n->vol = _mm_read_UBYTE (modreader);
196           if (flag & 0x10)
197             {
198               n->cmd = _mm_read_UBYTE (modreader);
199               n->inf = _mm_read_UBYTE (modreader);
200             }
201         }
202       else
203         row++;
204     }
205
206   return 1;
207 }
208
209 static UBYTE *
210 DSM_ConvertTrack (DSMNOTE * tr)
211 {
212   int t;
213   UBYTE note, ins, vol, cmd, inf;
214
215   UniReset ();
216   for (t = 0; t < 64; t++)
217     {
218       note = tr[t].note;
219       ins = tr[t].ins;
220       vol = tr[t].vol;
221       cmd = tr[t].cmd;
222       inf = tr[t].inf;
223
224       if (ins != 0 && ins != 255)
225         UniInstrument (ins - 1);
226       if (note != 255)
227         UniNote (note - 1);     /* normal note */
228       if (vol < 65)
229         UniPTEffect (0xc, vol);
230
231       if (cmd != 255)
232         {
233           if (cmd == 0x8)
234             {
235               if (inf == DSM_SURROUND)
236                 UniEffect (UNI_ITEFFECTS0, 0x91);
237               else if (inf <= 0x80)
238                 {
239                   inf = (inf < 0x80) ? inf << 1 : 255;
240                   UniPTEffect (cmd, inf);
241                 }
242             }
243           else if (cmd == 0xb)
244             {
245               if (inf <= 0x7f)
246                 UniPTEffect (cmd, inf);
247             }
248           else
249             {
250               /* Convert pattern jump from Dec to Hex */
251               if (cmd == 0xd)
252                 inf = (((inf & 0xf0) >> 4) * 10) + (inf & 0xf);
253               UniPTEffect (cmd, inf);
254             }
255         }
256       UniNewline ();
257     }
258   return UniDup ();
259 }
260
261 BOOL 
262 DSM_Load (BOOL curious)
263 {
264   int t;
265   DSMINST s;
266   SAMPLE *q;
267   int cursmp = 0, curpat = 0, track = 0;
268
269   blocklp = 0;
270   blockln = 12;
271
272   if (!GetBlockHeader ())
273     return 0;
274   if (memcmp (blockid, SONGID, 4))
275     {
276       _mm_errno = MMERR_LOADING_HEADER;
277       return 0;
278     }
279
280   _mm_read_UBYTES (mh->songname, 28, modreader);
281   mh->version = _mm_read_I_UWORD (modreader);
282   mh->flags = _mm_read_I_UWORD (modreader);
283   mh->reserved2 = _mm_read_I_ULONG (modreader);
284   mh->numord = _mm_read_I_UWORD (modreader);
285   mh->numsmp = _mm_read_I_UWORD (modreader);
286   mh->numpat = _mm_read_I_UWORD (modreader);
287   mh->numtrk = _mm_read_I_UWORD (modreader);
288   mh->globalvol = _mm_read_UBYTE (modreader);
289   mh->mastervol = _mm_read_UBYTE (modreader);
290   mh->speed = _mm_read_UBYTE (modreader);
291   mh->bpm = _mm_read_UBYTE (modreader);
292   _mm_read_UBYTES (mh->panpos, DSM_MAXCHAN, modreader);
293   _mm_read_UBYTES (mh->orders, DSM_MAXORDERS, modreader);
294
295   /* set module variables */
296   of.initspeed = mh->speed;
297   of.inittempo = mh->bpm;
298   of.modtype = strdup (DSM_Version);
299   of.numchn = mh->numtrk;
300   of.numpat = mh->numpat;
301   of.numtrk = of.numchn * of.numpat;
302   of.songname = DupStr (mh->songname, 28, 1);   /* make a cstr of songname */
303   of.reppos = 0;
304
305   for (t = 0; t < DSM_MAXCHAN; t++)
306     of.panning[t] = mh->panpos[t] == DSM_SURROUND ? PAN_SURROUND :
307       mh->panpos[t] < 0x80 ? (mh->panpos[t] << 1) : 255;
308
309   if (!AllocPositions (mh->numord))
310     return 0;
311   of.numpos = 0;
312   for (t = 0; t < mh->numord; t++)
313     {
314       of.positions[of.numpos] = mh->orders[t];
315       if (mh->orders[t] < 254)
316         of.numpos++;
317     }
318
319   of.numins = of.numsmp = mh->numsmp;
320
321   if (!AllocSamples ())
322     return 0;
323   if (!AllocTracks ())
324     return 0;
325   if (!AllocPatterns ())
326     return 0;
327
328   while (cursmp < of.numins || curpat < of.numpat)
329     {
330       if (!GetBlockHeader ())
331         return 0;
332       if (!memcmp (blockid, INSTID, 4) && cursmp < of.numins)
333         {
334           q = &of.samples[cursmp];
335
336           /* try to read sample info */
337           _mm_read_UBYTES (s.filename, 13, modreader);
338           s.flags = _mm_read_I_UWORD (modreader);
339           s.volume = _mm_read_UBYTE (modreader);
340           s.length = _mm_read_I_ULONG (modreader);
341           s.loopstart = _mm_read_I_ULONG (modreader);
342           s.loopend = _mm_read_I_ULONG (modreader);
343           s.reserved1 = _mm_read_I_ULONG (modreader);
344           s.c2spd = _mm_read_I_UWORD (modreader);
345           s.period = _mm_read_I_UWORD (modreader);
346           _mm_read_UBYTES (s.samplename, 28, modreader);
347
348           q->samplename = DupStr (s.samplename, 28, 1);
349           q->seekpos = _mm_ftell (modreader);
350           q->speed = s.c2spd;
351           q->length = s.length;
352           q->loopstart = s.loopstart;
353           q->loopend = s.loopend;
354           q->volume = s.volume;
355
356           if (s.flags & 1)
357             q->flags |= SF_LOOP;
358           if (s.flags & 2)
359             q->flags |= SF_SIGNED;
360           /* (s.flags&4) means packed sample,
361              but did they really exist in dsm ? */
362           cursmp++;
363         }
364       else if (!memcmp (blockid, PATTID, 4) && curpat < of.numpat)
365         {
366           DSM_ReadPattern ();
367           for (t = 0; t < of.numchn; t++)
368             if (!(of.tracks[track++] = DSM_ConvertTrack (&dsmbuf[t * 64])))
369               return 0;
370           curpat++;
371         }
372     }
373
374   return 1;
375 }
376
377 CHAR *
378 DSM_LoadTitle (void)
379 {
380   CHAR s[28];
381
382   _mm_fseek (modreader, 12, SEEK_SET);
383   if (!_mm_read_UBYTES (s, 28, modreader))
384     return NULL;
385
386   return (DupStr (s, 28, 1));
387 }
388
389 /*========== Loader information */
390
391 MLOADER load_dsm =
392 {
393   NULL,
394   "DSM",
395   "DSM (DSIK internal format)",
396   DSM_Init,
397   DSM_Test,
398   DSM_Load,
399   DSM_Cleanup,
400   DSM_LoadTitle
401 };
402
403
404 /* ex:set ts=4: */