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