OSDN Git Service

Import UnkoTim214
[timidity41/timidity41.git] / libunimod / load_669.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   Composer 669 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 S69HEADER
41   {
42     UBYTE marker[2];
43     CHAR message[108];
44     UBYTE nos;
45     UBYTE nop;
46     UBYTE looporder;
47     UBYTE orders[0x80];
48     UBYTE tempos[0x80];
49     UBYTE breaks[0x80];
50   }
51 S69HEADER;
52
53 /* sample information */
54 typedef struct S69SAMPLE
55   {
56     CHAR filename[13];
57     SLONG length;
58     SLONG loopbeg;
59     SLONG loopend;
60   }
61 S69SAMPLE;
62
63 /* encoded note */
64 typedef struct S69NOTE
65   {
66     UBYTE a, b, c;
67   }
68 S69NOTE;
69
70 /*========== Loader variables */
71
72 /* current pattern */
73 static S69NOTE *s69pat = NULL;
74 /* Module header */
75 static S69HEADER *mh = NULL;
76
77 /* file type identification */
78 static CHAR *S69_Version[] =
79 {
80   "Composer 669",
81   "Extended 669"
82 };
83
84 /*========== Loader code */
85
86 BOOL 
87 S69_Test (void)
88 {
89   UBYTE buf[0x80];
90
91   if (!_mm_read_UBYTES (buf, 2, modreader))
92     return 0;
93   /* look for id */
94   if (!memcmp (buf, "if", 2) || !memcmp (buf, "JN", 2))
95     {
96       int i;
97
98       /* skip song message */
99       _mm_fseek (modreader, 108, SEEK_CUR);
100       /* sanity checks */
101       if (_mm_read_UBYTE (modreader) > 64)
102         return 0;
103       if (_mm_read_UBYTE (modreader) > 128)
104         return 0;
105       if (_mm_read_UBYTE (modreader) > 127)
106         return 0;
107       /* check order table */
108       if (!_mm_read_UBYTES (buf, 0x80, modreader))
109         return 0;
110       for (i = 0; i < 0x80; i++)
111         if ((buf[i] >= 0x80) && (buf[i] != 0xff))
112           return 0;
113       /* check tempos table */
114       if (!_mm_read_UBYTES (buf, 0x80, modreader))
115         return 0;
116       for (i = 0; i < 0x80; i++)
117         if ((!buf[i]) || (buf[i] > 32))
118           return 0;
119       /* check pattern length table */
120       if (!_mm_read_UBYTES (buf, 0x80, modreader))
121         return 0;
122       for (i = 0; i < 0x80; i++)
123         if (buf[i] > 0x3f)
124           return 0;
125     }
126   else
127     return 0;
128
129   return 1;
130 }
131
132 BOOL 
133 S69_Init (void)
134 {
135   if (!(s69pat = (S69NOTE *) _mm_malloc (64 * 8 * sizeof (S69NOTE))))
136     return 0;
137   if (!(mh = (S69HEADER *) _mm_malloc (sizeof (S69HEADER))))
138     return 0;
139
140   return 1;
141 }
142
143 void 
144 S69_Cleanup (void)
145 {
146   _mm_free (s69pat);
147   _mm_free (mh);
148 }
149
150 static BOOL 
151 S69_LoadPatterns (void)
152 {
153   int track, row, channel;
154   UBYTE note, inst, vol, effect, lastfx, lastval;
155   S69NOTE *cur;
156   int tracks = 0;
157
158   if (!AllocPatterns ())
159     return 0;
160   if (!AllocTracks ())
161     return 0;
162
163   for (track = 0; track < of.numpat; track++)
164     {
165       /* set pattern break locations */
166       of.pattrows[track] = mh->breaks[track] + 1;
167
168       /* load the 669 pattern */
169       cur = s69pat;
170       for (row = 0; row < 64; row++)
171         {
172           for (channel = 0; channel < 8; channel++, cur++)
173             {
174               cur->a = _mm_read_UBYTE (modreader);
175               cur->b = _mm_read_UBYTE (modreader);
176               cur->c = _mm_read_UBYTE (modreader);
177             }
178         }
179
180       if (_mm_eof (modreader))
181         {
182           _mm_errno = MMERR_LOADING_PATTERN;
183           return 0;
184         }
185
186       /* translate the pattern */
187       for (channel = 0; channel < 8; channel++)
188         {
189           UniReset ();
190           /* set pattern tempo */
191           UniPTEffect (0xf, 78);
192           UniPTEffect (0xf, mh->tempos[track]);
193
194           lastfx = 0xff, lastval = 0;
195
196           for (row = 0; row <= mh->breaks[track]; row++)
197             {
198               int a, b, c;
199
200               /* fetch the encoded note */
201               a = s69pat[(row * 8) + channel].a;
202               b = s69pat[(row * 8) + channel].b;
203               c = s69pat[(row * 8) + channel].c;
204
205               /* decode it */
206               note = a >> 2;
207               inst = ((a & 0x3) << 4) | ((b & 0xf0) >> 4);
208               vol = b & 0xf;
209
210               if (a < 0xff)
211                 {
212                   if (a < 0xfe)
213                     {
214                       UniInstrument (inst);
215                       UniNote (note + 2 * OCTAVE);
216                       lastfx = 0xff;    /* reset background effect memory */
217                     }
218                   UniPTEffect (0xc, vol << 2);
219                 }
220
221               if ((c != 0xff) || (lastfx != 0xff))
222                 {
223                   if (c == 0xff)
224                     c = lastfx, effect = lastval;
225                   else
226                     effect = c & 0xf;
227
228                   switch (c >> 4)
229                     {
230                     case 0:     /* porta up */
231                       UniPTEffect (0x1, effect);
232                       lastfx = c, lastval = effect;
233                       break;
234                     case 1:     /* porta down */
235                       UniPTEffect (0x2, effect);
236                       lastfx = c, lastval = effect;
237                       break;
238                     case 2:     /* porta to note */
239                       UniPTEffect (0x3, effect);
240                       lastfx = c, lastval = effect;
241                       break;
242                     case 3:     /* frequency adjust */
243                       /* DMP converts this effect to S3M FF1. Why not ? */
244                       UniEffect (UNI_S3MEFFECTF, 0xf0 | effect);
245                       break;
246                     case 4:     /* vibrato */
247                       UniPTEffect (0x4, effect);
248                       lastfx = c, lastval = effect;
249                       break;
250                     case 5:     /* set speed */
251                       if (effect)
252                         UniPTEffect (0xf, effect);
253                       else if (mh->marker[0] != 0x69)
254                         {
255 #ifdef MIKMOD_DEBUG
256                           fprintf (stderr, "\r669: unsupported super fast tempo at pat=%d row=%d chan=%d\n",
257                                    track, row, channel);
258 #endif
259                         }
260                       break;
261                     }
262                 }
263               UniNewline ();
264             }
265           if (!(of.tracks[tracks++] = UniDup ()))
266             return 0;
267         }
268     }
269
270   return 1;
271 }
272
273 BOOL 
274 S69_Load (BOOL curious)
275 {
276   int i;
277   SAMPLE *current;
278   S69SAMPLE sample;
279
280   /* module header */
281   _mm_read_UBYTES (mh->marker, 2, modreader);
282   _mm_read_UBYTES (mh->message, 108, modreader);
283   mh->nos = _mm_read_UBYTE (modreader);
284   mh->nop = _mm_read_UBYTE (modreader);
285   mh->looporder = _mm_read_UBYTE (modreader);
286   _mm_read_UBYTES (mh->orders, 0x80, modreader);
287   for (i = 0; i < 0x80; i++)
288     if ((mh->orders[i] >= 0x80) && (mh->orders[i] != 0xff))
289       {
290         _mm_errno = MMERR_NOT_A_MODULE;
291         return 1;
292       }
293   _mm_read_UBYTES (mh->tempos, 0x80, modreader);
294   for (i = 0; i < 0x80; i++)
295     if ((!mh->tempos[i]) || (mh->tempos[i] > 32))
296       {
297         _mm_errno = MMERR_NOT_A_MODULE;
298         return 1;
299       }
300   _mm_read_UBYTES (mh->breaks, 0x80, modreader);
301   for (i = 0; i < 0x80; i++)
302     if (mh->breaks[i] > 0x3f)
303       {
304         _mm_errno = MMERR_NOT_A_MODULE;
305         return 1;
306       }
307
308   /* set module variables */
309   of.initspeed = 4;
310   of.inittempo = 78;
311   of.songname = DupStr (mh->message, 36, 1);
312   of.modtype = strdup (S69_Version[memcmp (mh->marker, "JN", 2) == 0]);
313   of.numchn = 8;
314   of.numpat = mh->nop;
315   of.numins = of.numsmp = mh->nos;
316   of.numtrk = of.numchn * of.numpat;
317   of.flags = UF_XMPERIODS | UF_LINEAR;
318
319   for (i = 35; (i >= 0) && (mh->message[i] == ' '); i--)
320     mh->message[i] = 0;
321   for (i = 36 + 35; (i >= 36 + 0) && (mh->message[i] == ' '); i--)
322     mh->message[i] = 0;
323   for (i = 72 + 35; (i >= 72 + 0) && (mh->message[i] == ' '); i--)
324     mh->message[i] = 0;
325   if ((mh->message[0]) || (mh->message[36]) || (mh->message[72]))
326     if ((of.comment = (CHAR *) _mm_malloc (3 * (36 + 1) + 1)))
327       {
328         strncpy (of.comment, mh->message, 36);
329         strcat (of.comment, "\r");
330         if (mh->message[36])
331           strncat (of.comment, mh->message + 36, 36);
332         strcat (of.comment, "\r");
333         if (mh->message[72])
334           strncat (of.comment, mh->message + 72, 36);
335         strcat (of.comment, "\r");
336         of.comment[3 * (36 + 1)] = 0;
337       }
338
339   if (!AllocPositions (0x80))
340     return 0;
341   for (i = 0; i < 0x80; i++)
342     {
343       if (mh->orders[i] >= mh->nop)
344         break;
345       of.positions[i] = mh->orders[i];
346     }
347   of.numpos = i;
348   of.reppos = mh->looporder < of.numpos ? mh->looporder : 0;
349
350   if (!AllocSamples ())
351     return 0;
352   current = of.samples;
353
354   for (i = 0; i < of.numins; i++)
355     {
356       /* sample information */
357       _mm_read_UBYTES ((UBYTE *) sample.filename, 13, modreader);
358       sample.length = _mm_read_I_SLONG (modreader);
359       sample.loopbeg = _mm_read_I_SLONG (modreader);
360       sample.loopend = _mm_read_I_SLONG (modreader);
361       if (sample.loopend == 0xfffff)
362         sample.loopend = 0;
363
364       if ((sample.length < 0) || (sample.loopbeg < -1) || (sample.loopend < -1))
365         {
366           _mm_errno = MMERR_LOADING_HEADER;
367           return 0;
368         }
369
370       current->samplename = DupStr (sample.filename, 13, 1);
371       current->seekpos = 0;
372       current->speed = 0;
373       current->length = sample.length;
374       current->loopstart = sample.loopbeg;
375       current->loopend = (sample.loopend < sample.length) ? sample.loopend : sample.length;
376       current->flags = (sample.loopbeg < sample.loopend) ? SF_LOOP : 0;
377       current->volume = 64;
378
379       current++;
380     }
381
382   if (!S69_LoadPatterns ())
383     return 0;
384
385   return 1;
386 }
387
388 CHAR *
389 S69_LoadTitle (void)
390 {
391   CHAR s[36];
392
393   _mm_fseek (modreader, 2, SEEK_SET);
394   if (!_mm_read_UBYTES (s, 36, modreader))
395     return NULL;
396
397   return (DupStr (s, 36, 1));
398 }
399
400 /*========== Loader information */
401
402 MLOADER load_669 =
403 {
404   NULL,
405   "669",
406   "669 (Composer 669, Unis 669)",
407   S69_Init,
408   S69_Test,
409   S69_Load,
410   S69_Cleanup,
411   S69_LoadTitle
412 };
413
414 /* ex:set ts=4: */