OSDN Git Service

Import UnkoTim214
[timidity41/timidity41.git] / libunimod / load_okt.c
1 /*      MikMod sound library
2         (c) 1999, 2000 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   Oktalyzer (OKT) module loader
26
27 ==============================================================================*/
28
29 /*
30         Written by UFO <ufo303@poczta.onet.pl>
31         based on the file description compiled by Harald Zappe
32                                                               <zappe@gaea.sietec.de>
33
34 */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43
44 #include <stdio.h>
45 #include <string.h>
46
47 #include "unimod_priv.h"
48
49 /*========== Module blocks */
50
51 /* sample information */
52 typedef struct OKTSAMPLE {
53         CHAR sampname[20];
54         ULONG len;
55         UWORD loopbeg;
56         UWORD looplen;
57         UBYTE volume;
58 } OKTSAMPLE;
59
60 typedef struct OKTNOTE {
61         UBYTE note, ins, eff, dat;
62 } OKTNOTE;
63
64 /*========== Loader variables */
65
66 static OKTNOTE *okttrk = NULL;
67
68 /*========== Loader code */
69
70 BOOL OKT_Test(void)
71 {
72         CHAR id[8];
73
74         if (!_mm_read_UBYTES(id, 8, modreader))
75                 return 0;
76         if (!memcmp(id, "OKTASONG", 8))
77                 return 1;
78
79         return 0;
80 }
81
82 /*      Pattern analysis routine.
83         Effects not implemented (yet) : (in decimal)
84         11 Arpeggio 4: Change note every 50Hz tick between N,H,N,L
85         12 Arpeggio 5: Change note every 50Hz tick between H,H,N
86                    N = normal note being played in this channel (1-36)
87                    L = normal note number minus upper four bits of 'data'.
88                    H = normal note number plus  lower four bits of 'data'.
89     13 Decrease note number by 'data' once per tick.
90     17 Increase note number by 'data' once per tick.
91     21 Decrease note number by 'data' once per line.
92     30 Increase note number by 'data' once per line.
93 */
94 static UBYTE *OKT_ConvertTrack(UBYTE patrows)
95 {
96         int t;
97         UBYTE ins, note, eff, dat;
98
99         UniReset();
100         for (t = 0; t < patrows; t++) {
101                 note = okttrk[t].note;
102                 ins = okttrk[t].ins;
103                 eff = okttrk[t].eff;
104                 dat = okttrk[t].dat;
105
106                 if (note) {
107                         UniNote(note + 3*OCTAVE - 1);
108                         UniInstrument(ins);
109                 }
110
111                 if (eff)
112                         switch (eff) {
113                           case 1:                       /* Porta Up */
114                                 UniPTEffect(0x1, dat);
115                                 break;
116                           case 2:                       /* Portamento Down */
117                                 UniPTEffect(0x2, dat);
118                                 break;
119                           case 10:                      /* Arpeggio 3 supported */
120                                 UniPTEffect(0x0, dat);
121                                 break;
122                           case 15:      /* Amiga filter toggle, ignored */
123                                 break;
124                           case 25:                      /* Pattern Jump */
125                                 UniPTEffect(0xb, dat);
126                                 break;
127                           case 27:                      /* Release - similar to Keyoff */
128                                 UniWriteByte(UNI_KEYOFF);
129                                 break;
130                           case 28:                      /* Set Tempo */
131                                 UniPTEffect(0xf, dat);
132                                 break;
133                           case 31:                      /* volume Control */
134                                 if (dat <= 0x40)
135                                         UniPTEffect(0xc, dat);
136                                 else if (dat <= 0x50)
137                                         UniEffect(UNI_XMEFFECTA, (dat - 0x40)); /* fast fade out */
138                                 else if (dat <= 0x60)
139                                         UniEffect(UNI_XMEFFECTA, (dat - 0x50) << 4);    /* fast fade in */
140                                 else if (dat <= 0x70)
141                                         UniEffect(UNI_XMEFFECTEB, (dat - 0x60));        /* slow fade out */
142                                 else if (dat <= 0x80)
143                                         UniEffect(UNI_XMEFFECTEA, (dat - 0x70));        /* slow fade in */
144                                 break;
145 #ifdef MIKMOD_DEBUG
146                           default:
147                                 fprintf(stderr, "\rUnimplemented effect (%02d,%02x)\n",
148                                                 eff, dat);
149 #endif
150                         }
151
152                 UniNewline();
153         }
154         return UniDup();
155 }
156
157 /* Read "channel modes" i.e. channel number and panning information */
158 static void OKT_doCMOD(void)
159 {
160         /* amiga channel panning table */
161         UBYTE amigapan[4] = { 0x00, 0xff, 0xff, 0x00 };
162         int t;
163
164         of.numchn = 0;
165
166         for (t = 0; t < 4; t++)
167                 if (_mm_read_M_UWORD(modreader)) {
168                         /* two channels tied to the same Amiga hardware voice */
169                         of.panning[of.numchn++] = amigapan[t];
170                         of.panning[of.numchn++] = amigapan[t];
171                 } else
172                         /* one channel tied to the Amiga hardware voice */
173                         of.panning[of.numchn++] = amigapan[t];
174 }
175
176 /* Read sample information */
177 static BOOL OKT_doSAMP(int len)
178 {
179         int t;
180         SAMPLE *q;
181         OKTSAMPLE s;
182
183         of.numins = of.numsmp = (len / 0x20);
184         if (!AllocSamples())
185                 return 0;
186
187         for (t = 0, q = of.samples; t < of.numins; t++, q++) {
188                 _mm_read_UBYTES(s.sampname, 20, modreader);
189                 s.len = _mm_read_M_ULONG(modreader);
190                 s.loopbeg = _mm_read_M_UWORD(modreader);
191                 s.looplen = _mm_read_M_UWORD(modreader);
192                 _mm_read_UBYTE(modreader);
193                 s.volume = _mm_read_UBYTE(modreader);
194                 _mm_read_M_UWORD(modreader);
195
196                 if (_mm_eof(modreader)) {
197                         _mm_errno = MMERR_LOADING_SAMPLEINFO;
198                         return 0;
199                 }
200
201                 if (!s.len)
202                         q->seekpos = q->length = q->loopstart = q->loopend = q->flags = 0;
203                 else {
204                         s.len--;
205                         /* sanity checks */
206                         if (s.loopbeg > s.len)
207                                 s.loopbeg = s.len;
208                         if (s.loopbeg + s.looplen > s.len)
209                                 s.looplen = s.len - s.loopbeg;
210                         if (s.looplen < 2)
211                                 s.looplen = 0;
212
213                         q->length = s.len;
214                         q->loopstart = s.loopbeg;
215                         q->loopend = s.looplen + q->loopstart;
216                         q->volume = s.volume;
217                         q->flags = SF_SIGNED;
218
219                         if (s.looplen)
220                                 q->flags |= SF_LOOP;
221                 }
222                 q->samplename = DupStr(s.sampname, 20, 1);
223                 q->speed = 8363;
224         }
225         return 1;
226 }
227
228 /* Read speed information */
229 static void OKT_doSPEE(void)
230 {
231         int tempo = _mm_read_M_UWORD(modreader);
232
233         of.initspeed = tempo;
234 }
235
236 /* Read song length information */
237 static void OKT_doSLEN(void)
238 {
239         of.numpat = _mm_read_M_UWORD(modreader);
240 }
241
242 /* Read pattern length information */
243 static void OKT_doPLEN(void)
244 {
245         of.numpos = _mm_read_M_UWORD(modreader);
246 }
247
248 /* Read order table */
249 static BOOL OKT_doPATT(void)
250 {
251         int t;
252
253         if (!of.numpos || !AllocPositions(of.numpos))
254                 return 0;
255
256         for (t = 0; t < 128; t++)
257                 if (t < of.numpos)
258                         of.positions[t] = (UWORD)_mm_read_UBYTE(modreader);
259                 else
260                         break;
261
262         return 1;
263 }
264
265 static BOOL OKT_doPBOD(int patnum)
266 {
267         char *patbuf;
268         int rows, i;
269         int u;
270
271         if (!patnum) {
272                 of.numtrk = of.numpat * of.numchn;
273
274                 if (!AllocTracks() || !AllocPatterns())
275                         return 0;
276         }
277
278         /* Read pattern */
279         of.pattrows[patnum] = rows = _mm_read_M_UWORD(modreader);
280
281         if (!(okttrk = (OKTNOTE *) _mm_calloc(rows, sizeof(OKTNOTE))) ||
282             !(patbuf = (char *)_mm_calloc(rows * of.numchn, sizeof(OKTNOTE))))
283                 return 0;
284         _mm_read_UBYTES(patbuf, rows * of.numchn * sizeof(OKTNOTE), modreader);
285         if (_mm_eof(modreader)) {
286                 _mm_errno = MMERR_LOADING_PATTERN;
287                 return 0;
288         }
289
290         for (i = 0; i < of.numchn; i++) {
291                 for (u = 0; u < rows; u++) {
292                         okttrk[u].note = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE)];
293                         okttrk[u].ins = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 1];
294                         okttrk[u].eff = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 2];
295                         okttrk[u].dat = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 3];
296                 }
297
298                 if (!(of.tracks[patnum * of.numchn + i] = OKT_ConvertTrack(rows)))
299                         return 0;
300         }
301         _mm_free(patbuf);
302         _mm_free(okttrk);
303         return 1;
304 }
305
306 static void OKT_doSBOD(int insnum)
307 {
308         of.samples[insnum].seekpos = _mm_ftell(modreader);
309 }
310
311 BOOL OKT_Load(BOOL curious)
312 {
313         UBYTE id[4];
314         ULONG len;
315         ULONG fp;
316         BOOL seen_cmod = 0, seen_samp = 0, seen_slen = 0, seen_plen = 0, seen_patt
317                         = 0, seen_spee = 0;
318         int patnum = 0, insnum = 0;
319
320         /* skip OKTALYZER header */
321         _mm_fseek(modreader, 8, SEEK_SET);
322         of.songname = strdup("");
323
324         of.modtype = strdup("Amiga Oktalyzer");
325         of.numpos = of.reppos = 0;
326         
327         /* default values */
328         of.initspeed = 6;
329         of.inittempo = 125;
330         
331         while (1) {
332                 /* read block header */
333                 _mm_read_UBYTES(id, 4, modreader);
334                 len = _mm_read_M_ULONG(modreader);
335                 
336                 if (_mm_eof(modreader))
337                         break;
338                 fp = _mm_ftell(modreader);
339                 
340                 if (!memcmp(id, "CMOD", 4)) {
341                         if (!seen_cmod) {
342                                 OKT_doCMOD();
343                                 seen_cmod = 1;
344                         } else {
345                                 _mm_errno = MMERR_LOADING_HEADER;
346                                 return 0;
347                         }
348                 } else if (!memcmp(id, "SAMP", 4)) {
349                         if (!seen_samp && OKT_doSAMP(len))
350                                 seen_samp = 1;
351                         else {
352                                 _mm_errno = MMERR_LOADING_HEADER;
353                                 return 0;
354                         }
355                 } else if (!memcmp(id, "SPEE", 4)) {
356                         if (!seen_spee) {
357                                 OKT_doSPEE();
358                                 seen_spee = 1;
359                         } else {
360                                 _mm_errno = MMERR_LOADING_HEADER;
361                                 return 0;
362                         }
363                 } else if (!memcmp(id, "SLEN", 4)) {
364                         if (!seen_slen) {
365                                 OKT_doSLEN();
366                                 seen_slen = 1;
367                         } else {
368                                 _mm_errno = MMERR_LOADING_HEADER;
369                                 return 0;
370                         }
371                 } else if (!memcmp(id, "PLEN", 4)) {
372                         if (!seen_plen) {
373                                 OKT_doPLEN();
374                                 seen_plen = 1;
375                         } else {
376                                 _mm_errno = MMERR_LOADING_HEADER;
377                                 return 0;
378                         }
379                 } else if (!memcmp(id, "PATT", 4)) {
380                         if (!seen_plen) {
381                                 _mm_errno = MMERR_LOADING_HEADER;
382                                 return 0;
383                         }
384                         if (!seen_patt && OKT_doPATT())
385                                 seen_patt = 1;
386                         else {
387                                 _mm_errno = MMERR_LOADING_HEADER;
388                                 return 0;
389                         }
390                 } else if (!memcmp(id,"PBOD", 4)) {
391                         /* need to know numpat and numchn */
392                         if (!seen_slen || !seen_cmod || (patnum >= of.numpat)) {
393                                 _mm_errno = MMERR_LOADING_HEADER;
394                                 return 0;
395                         }
396                         if (!OKT_doPBOD(patnum++)) {
397                                 _mm_errno = MMERR_LOADING_PATTERN;
398                                 return 0;
399                         }
400                 } else if (!memcmp(id,"SBOD",4)) {
401                         /* need to know numsmp */
402                         if (!seen_samp) {
403                                 _mm_errno = MMERR_LOADING_HEADER;
404                                 return 0;
405                         }
406                         while ((insnum < of.numins) && !of.samples[insnum].length)
407                                 insnum++;
408                         if (insnum >= of.numins) {
409                                 _mm_errno = MMERR_LOADING_HEADER;
410                                 return 0;
411                         }
412                         OKT_doSBOD(insnum++);
413                 }
414
415                 /* goto next block start position */
416                 _mm_fseek(modreader, fp + len, SEEK_SET);
417         }
418
419         if (!seen_cmod || !seen_samp || !seen_patt ||
420                 !seen_slen || !seen_plen || (patnum != of.numpat)) {
421                 _mm_errno = MMERR_LOADING_HEADER;
422                 return 0;
423         }
424
425         return 1;
426 }
427
428 CHAR *OKT_LoadTitle(void)
429 {
430         return strdup("");
431 }
432
433 /*========== Loader information */
434
435 MLOADER load_okt = {
436         NULL,
437         "OKT",
438         "OKT (Amiga Oktalyzer)",
439         NULL,
440         OKT_Test,
441         OKT_Load,
442         NULL,
443         OKT_LoadTitle
444 };
445
446 /* ex:set ts=4: */