OSDN Git Service

TiMidity++-2.11.0-pre2
[timidity41/timidity41.git] / libunimod / load_ult.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: load_ult.c,v 1.27 1999/10/25 16:31:41 miod Exp $
24
25   Ultratracker (ULT) 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 /* header */
40 typedef struct ULTHEADER
41   {
42     CHAR id[16];
43     CHAR songtitle[32];
44     UBYTE reserved;
45   }
46 ULTHEADER;
47
48 /* sample information */
49 typedef struct ULTSAMPLE
50   {
51     CHAR samplename[32];
52     CHAR dosname[12];
53     SLONG loopstart;
54     SLONG loopend;
55     SLONG sizestart;
56     SLONG sizeend;
57     UBYTE volume;
58     UBYTE flags;
59     UWORD speed;
60     SWORD finetune;
61   }
62 ULTSAMPLE;
63
64 typedef struct ULTEVENT
65   {
66     UBYTE note, sample, eff, dat1, dat2;
67   }
68 ULTEVENT;
69
70 /*========== Loader variables */
71
72 #define ULTS_16BITS     4
73 #define ULTS_LOOP       8
74 #define ULTS_REVERSE    16
75
76 #define ULT_VERSION_LEN 18
77 static CHAR ULT_Version[ULT_VERSION_LEN] = "Ultra Tracker v1.x";
78
79 static ULTEVENT ev;
80
81 /*========== Loader code */
82
83 BOOL 
84 ULT_Test (void)
85 {
86   CHAR id[16];
87
88   if (!_mm_read_string (id, 15, modreader))
89     return 0;
90   if (strncmp (id, "MAS_UTrack_V00", 14))
91     return 0;
92   if ((id[14] < '1') || (id[14] > '4'))
93     return 0;
94   return 1;
95 }
96
97 BOOL 
98 ULT_Init (void)
99 {
100   return 1;
101 }
102
103 void 
104 ULT_Cleanup (void)
105 {
106 }
107
108 static UBYTE 
109 ReadUltEvent (ULTEVENT * event)
110 {
111   UBYTE flag, rep = 1;
112
113   flag = _mm_read_UBYTE (modreader);
114   if (flag == 0xfc)
115     {
116       rep = _mm_read_UBYTE (modreader);
117       event->note = _mm_read_UBYTE (modreader);
118     }
119   else
120     event->note = flag;
121
122   event->sample = _mm_read_UBYTE (modreader);
123   event->eff = _mm_read_UBYTE (modreader);
124   event->dat1 = _mm_read_UBYTE (modreader);
125   event->dat2 = _mm_read_UBYTE (modreader);
126
127   return rep;
128 }
129
130 BOOL 
131 ULT_Load (BOOL curious)
132 {
133   int t, u, tracks = 0;
134   SAMPLE *q;
135   ULTSAMPLE s;
136   ULTHEADER mh;
137   UBYTE nos, noc, nop;
138
139   /* try to read module header */
140   _mm_read_string (mh.id, 15, modreader);
141   _mm_read_string (mh.songtitle, 32, modreader);
142   mh.reserved = _mm_read_UBYTE (modreader);
143
144   if (_mm_eof (modreader))
145     {
146       _mm_errno = MMERR_LOADING_HEADER;
147       return 0;
148     }
149
150   ULT_Version[ULT_VERSION_LEN - 1] = '3' + (mh.id[14] - '1');
151   of.modtype = DupStr (ULT_Version, ULT_VERSION_LEN, 1);
152   of.initspeed = 6;
153   of.inittempo = 125;
154   of.reppos = 0;
155
156   /* read songtext */
157   if ((mh.id[14] > '1') && (mh.reserved))
158     if (!ReadLinedComment (mh.reserved, 32))
159       return 0;
160
161   nos = _mm_read_UBYTE (modreader);
162   if (_mm_eof (modreader))
163     {
164       _mm_errno = MMERR_LOADING_HEADER;
165       return 0;
166     }
167
168   of.songname = DupStr (mh.songtitle, 32, 1);
169   of.numins = of.numsmp = nos;
170
171   if (!AllocSamples ())
172     return 0;
173   q = of.samples;
174   for (t = 0; t < nos; t++)
175     {
176       /* try to read sample info */
177       _mm_read_string (s.samplename, 32, modreader);
178       _mm_read_string (s.dosname, 12, modreader);
179       s.loopstart = _mm_read_I_ULONG (modreader);
180       s.loopend = _mm_read_I_ULONG (modreader);
181       s.sizestart = _mm_read_I_ULONG (modreader);
182       s.sizeend = _mm_read_I_ULONG (modreader);
183       s.volume = _mm_read_UBYTE (modreader);
184       s.flags = _mm_read_UBYTE (modreader);
185       s.speed = (mh.id[14] >= '4') ? _mm_read_I_UWORD (modreader) : 8363;
186       s.finetune = _mm_read_I_SWORD (modreader);
187
188       if (_mm_eof (modreader))
189         {
190           _mm_errno = MMERR_LOADING_SAMPLEINFO;
191           return 0;
192         }
193
194       q->samplename = DupStr (s.samplename, 32, 1);
195       /* The correct formula for the coefficient would be
196          pow(2,(double)s.finetume/OCTAVE/32768), but to avoid floating point
197          here, we'll use a first order approximation here.
198          1/567290 == Ln(2)/OCTAVE/32768 */
199       q->speed = s.speed + s.speed * (((SLONG) s.speed * (SLONG) s.finetune) / 567290);
200       q->length = s.sizeend - s.sizestart;
201       q->volume = s.volume >> 2;
202       q->loopstart = s.loopstart;
203       q->loopend = s.loopend;
204       q->flags = SF_SIGNED;
205       if (s.flags & ULTS_LOOP)
206         q->flags |= SF_LOOP;
207       if (s.flags & ULTS_16BITS)
208         {
209           s.sizeend += (s.sizeend - s.sizestart);
210           s.sizestart <<= 1;
211           q->flags |= SF_16BITS;
212           q->loopstart >>= 1;
213           q->loopend >>= 1;
214         }
215       q++;
216     }
217
218   if (!AllocPositions (256))
219     return 0;
220   for (t = 0; t < 256; t++)
221     of.positions[t] = _mm_read_UBYTE (modreader);
222   for (t = 0; t < 256; t++)
223     if (of.positions[t] == 255)
224       break;
225   of.numpos = t;
226
227   noc = _mm_read_UBYTE (modreader);
228   nop = _mm_read_UBYTE (modreader);
229
230   of.numchn = ++noc;
231   of.numpat = ++nop;
232   of.numtrk = of.numchn * of.numpat;
233   if (!AllocTracks ())
234     return 0;
235   if (!AllocPatterns ())
236     return 0;
237   for (u = 0; u < of.numchn; u++)
238     for (t = 0; t < of.numpat; t++)
239       of.patterns[(t * of.numchn) + u] = tracks++;
240
241   /* read pan position table for v1.5 and higher */
242   if (mh.id[14] >= '3')
243     for (t = 0; t < of.numchn; t++)
244       of.panning[t] = _mm_read_UBYTE (modreader) << 4;
245
246   for (t = 0; t < of.numtrk; t++)
247     {
248       int rep, row = 0;
249
250       UniReset ();
251       while (row < 64)
252         {
253           rep = ReadUltEvent (&ev);
254
255           if (_mm_eof (modreader))
256             {
257               _mm_errno = MMERR_LOADING_TRACK;
258               return 0;
259             }
260
261           while (rep--)
262             {
263               UBYTE eff;
264               int offset;
265
266               if (ev.sample)
267                 UniInstrument (ev.sample - 1);
268               if (ev.note)
269                 UniNote (ev.note + 2 * OCTAVE - 1);
270
271               /* first effect - various fixes by Alexander Kerkhove and
272                  Thomas Neumann */
273               eff = ev.eff >> 4;
274               switch (eff)
275                 {
276                 case 0x3:       /* tone portamento */
277                   UniEffect (UNI_ITEFFECTG, ev.dat2);
278                   break;
279                 case 0x5:
280                   break;
281                 case 0x9:       /* sample offset */
282                   offset = (ev.dat2 << 8) | ((ev.eff & 0xf) == 9 ? ev.dat1 : 0);
283                   UniEffect (UNI_ULTEFFECT9, offset);
284                   break;
285                 case 0xb:       /* panning */
286                   UniPTEffect (8, ev.dat2 * 0xf);
287                   break;
288                 case 0xc:       /* volume */
289                   UniPTEffect (eff, ev.dat2 >> 2);
290                   break;
291                 default:
292                   UniPTEffect (eff, ev.dat2);
293                   break;
294                 }
295
296               /* second effect */
297               eff = ev.eff & 0xf;
298               switch (eff)
299                 {
300                 case 0x3:       /* tone portamento */
301                   UniEffect (UNI_ITEFFECTG, ev.dat1);
302                   break;
303                 case 0x5:
304                   break;
305                 case 0x9:       /* sample offset */
306                   if ((ev.eff >> 4) != 9)
307                     UniEffect (UNI_ULTEFFECT9, ((UWORD) ev.dat1) << 8);
308                   break;
309                 case 0xb:       /* panning */
310                   UniPTEffect (8, ev.dat1 * 0xf);
311                   break;
312                 case 0xc:       /* volume */
313                   UniPTEffect (eff, ev.dat1 >> 2);
314                   break;
315                 default:
316                   UniPTEffect (eff, ev.dat1);
317                   break;
318                 }
319
320               UniNewline ();
321               row++;
322             }
323         }
324       if (!(of.tracks[t] = UniDup ()))
325         return 0;
326     }
327   return 1;
328 }
329
330 CHAR *
331 ULT_LoadTitle (void)
332 {
333   CHAR s[32];
334
335   _mm_fseek (modreader, 15, SEEK_SET);
336   if (!_mm_read_UBYTES (s, 32, modreader))
337     return NULL;
338
339   return (DupStr (s, 32, 1));
340 }
341
342 /*========== Loader information */
343
344 MLOADER load_ult =
345 {
346   NULL,
347   "ULT",
348   "ULT (UltraTracker)",
349   ULT_Init,
350   ULT_Test,
351   ULT_Load,
352   ULT_Cleanup,
353   ULT_LoadTitle
354 };
355
356
357 /* ex:set ts=4: */