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