1 /* MikMod sound library
2 (c) 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
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.
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.
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
21 /*==============================================================================
25 Oktalyzer (OKT) module loader
27 ==============================================================================*/
30 Written by UFO <ufo303@poczta.onet.pl>
31 based on the file description compiled by Harald Zappe
32 <zappe@gaea.sietec.de>
47 #include "unimod_priv.h"
49 /*========== Module blocks */
51 /* sample information */
52 typedef struct OKTSAMPLE {
60 typedef struct OKTNOTE {
61 UBYTE note, ins, eff, dat;
64 /*========== Loader variables */
66 static OKTNOTE *okttrk = NULL;
68 /*========== Loader code */
74 if (!_mm_read_UBYTES(id, 8, modreader))
76 if (!memcmp(id, "OKTASONG", 8))
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.
94 static UBYTE *OKT_ConvertTrack(UBYTE patrows)
97 UBYTE ins, note, eff, dat;
100 for (t = 0; t < patrows; t++) {
101 note = okttrk[t].note;
107 UniNote(note + 3*OCTAVE - 1);
113 case 1: /* Porta Up */
114 UniPTEffect(0x1, dat);
116 case 2: /* Portamento Down */
117 UniPTEffect(0x2, dat);
119 case 10: /* Arpeggio 3 supported */
120 UniPTEffect(0x0, dat);
122 case 15: /* Amiga filter toggle, ignored */
124 case 25: /* Pattern Jump */
125 UniPTEffect(0xb, dat);
127 case 27: /* Release - similar to Keyoff */
128 UniWriteByte(UNI_KEYOFF);
130 case 28: /* Set Tempo */
131 UniPTEffect(0xf, dat);
133 case 31: /* volume Control */
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 */
147 fprintf(stderr, "\rUnimplemented effect (%02d,%02x)\n",
157 /* Read "channel modes" i.e. channel number and panning information */
158 static void OKT_doCMOD(void)
160 /* amiga channel panning table */
161 UBYTE amigapan[4] = { 0x00, 0xff, 0xff, 0x00 };
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];
172 /* one channel tied to the Amiga hardware voice */
173 of.panning[of.numchn++] = amigapan[t];
176 /* Read sample information */
177 static BOOL OKT_doSAMP(int len)
183 of.numins = of.numsmp = (len / 0x20);
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);
196 if (_mm_eof(modreader)) {
197 _mm_errno = MMERR_LOADING_SAMPLEINFO;
202 q->seekpos = q->length = q->loopstart = q->loopend = q->flags = 0;
206 if (s.loopbeg > s.len)
208 if (s.loopbeg + s.looplen > s.len)
209 s.looplen = s.len - s.loopbeg;
214 q->loopstart = s.loopbeg;
215 q->loopend = s.looplen + q->loopstart;
216 q->volume = s.volume;
217 q->flags = SF_SIGNED;
222 q->samplename = DupStr(s.sampname, 20, 1);
228 /* Read speed information */
229 static void OKT_doSPEE(void)
231 int tempo = _mm_read_M_UWORD(modreader);
233 of.initspeed = tempo;
236 /* Read song length information */
237 static void OKT_doSLEN(void)
239 of.numpat = _mm_read_M_UWORD(modreader);
242 /* Read pattern length information */
243 static void OKT_doPLEN(void)
245 of.numpos = _mm_read_M_UWORD(modreader);
248 /* Read order table */
249 static BOOL OKT_doPATT(void)
253 if (!of.numpos || !AllocPositions(of.numpos))
256 for (t = 0; t < 128; t++)
258 of.positions[t] = (UWORD)_mm_read_UBYTE(modreader);
265 static BOOL OKT_doPBOD(int patnum)
272 of.numtrk = of.numpat * of.numchn;
274 if (!AllocTracks() || !AllocPatterns())
279 of.pattrows[patnum] = rows = _mm_read_M_UWORD(modreader);
281 if (!(okttrk = (OKTNOTE *) _mm_calloc(rows, sizeof(OKTNOTE))) ||
282 !(patbuf = (char *)_mm_calloc(rows * of.numchn, sizeof(OKTNOTE))))
284 _mm_read_UBYTES(patbuf, rows * of.numchn * sizeof(OKTNOTE), modreader);
285 if (_mm_eof(modreader)) {
286 _mm_errno = MMERR_LOADING_PATTERN;
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];
298 if (!(of.tracks[patnum * of.numchn + i] = OKT_ConvertTrack(rows)))
306 static void OKT_doSBOD(int insnum)
308 of.samples[insnum].seekpos = _mm_ftell(modreader);
311 BOOL OKT_Load(BOOL curious)
316 BOOL seen_cmod = 0, seen_samp = 0, seen_slen = 0, seen_plen = 0, seen_patt
318 int patnum = 0, insnum = 0;
320 /* skip OKTALYZER header */
321 _mm_fseek(modreader, 8, SEEK_SET);
322 of.songname = strdup("");
324 of.modtype = strdup("Amiga Oktalyzer");
325 of.numpos = of.reppos = 0;
332 /* read block header */
333 _mm_read_UBYTES(id, 4, modreader);
334 len = _mm_read_M_ULONG(modreader);
336 if (_mm_eof(modreader))
338 fp = _mm_ftell(modreader);
340 if (!memcmp(id, "CMOD", 4)) {
345 _mm_errno = MMERR_LOADING_HEADER;
348 } else if (!memcmp(id, "SAMP", 4)) {
349 if (!seen_samp && OKT_doSAMP(len))
352 _mm_errno = MMERR_LOADING_HEADER;
355 } else if (!memcmp(id, "SPEE", 4)) {
360 _mm_errno = MMERR_LOADING_HEADER;
363 } else if (!memcmp(id, "SLEN", 4)) {
368 _mm_errno = MMERR_LOADING_HEADER;
371 } else if (!memcmp(id, "PLEN", 4)) {
376 _mm_errno = MMERR_LOADING_HEADER;
379 } else if (!memcmp(id, "PATT", 4)) {
381 _mm_errno = MMERR_LOADING_HEADER;
384 if (!seen_patt && OKT_doPATT())
387 _mm_errno = MMERR_LOADING_HEADER;
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;
396 if (!OKT_doPBOD(patnum++)) {
397 _mm_errno = MMERR_LOADING_PATTERN;
400 } else if (!memcmp(id,"SBOD",4)) {
401 /* need to know numsmp */
403 _mm_errno = MMERR_LOADING_HEADER;
406 while ((insnum < of.numins) && !of.samples[insnum].length)
408 if (insnum >= of.numins) {
409 _mm_errno = MMERR_LOADING_HEADER;
412 OKT_doSBOD(insnum++);
415 /* goto next block start position */
416 _mm_fseek(modreader, fp + len, SEEK_SET);
419 if (!seen_cmod || !seen_samp || !seen_patt ||
420 !seen_slen || !seen_plen || (patnum != of.numpat)) {
421 _mm_errno = MMERR_LOADING_HEADER;
428 CHAR *OKT_LoadTitle(void)
433 /*========== Loader information */
438 "OKT (Amiga Oktalyzer)",