summaryrefslogtreecommitdiff
path: root/apps/codecs/dumb/src/it/readmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/dumb/src/it/readmod.c')
-rw-r--r--apps/codecs/dumb/src/it/readmod.c594
1 files changed, 594 insertions, 0 deletions
diff --git a/apps/codecs/dumb/src/it/readmod.c b/apps/codecs/dumb/src/it/readmod.c
new file mode 100644
index 0000000000..452c8900a4
--- /dev/null
+++ b/apps/codecs/dumb/src/it/readmod.c
@@ -0,0 +1,594 @@
1/* _______ ____ __ ___ ___
2 * \ _ \ \ / \ / \ \ / / ' ' '
3 * | | \ \ | | || | \/ | . .
4 * | | | | | | || ||\ /| |
5 * | | | | | | || || \/ | | ' ' '
6 * | | | | | | || || | | . .
7 * | |_/ / \ \__// || | |
8 * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
9 * / \
10 * / . \
11 * readmod.c - Code to read a good old-fashioned / / \ \
12 * Amiga module from an open file. | < / \_
13 * | \/ /\ /
14 * By Ben Davis. \_ / > /
15 * | \ / /
16 * | ' /
17 * \__/
18 */
19
20#include <stdlib.h>
21#include <string.h>
22#include <math.h>
23
24#include "dumb.h"
25#include "internal/it.h"
26
27
28
29static int it_mod_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer)
30{
31 int pos;
32 int channel;
33 int row;
34 IT_ENTRY *entry;
35
36 pattern->n_rows = 64;
37
38 if (n_channels == 0) {
39 /* Read the first four channels, leaving gaps for the rest. */
40 for (pos = 0; pos < 64*8*4; pos += 8*4)
41 dumbfile_getnc(buffer + pos, 4*4, f);
42 /* Read the other channels into the gaps we left. */
43 for (pos = 4*4; pos < 64*8*4; pos += 8*4)
44 dumbfile_getnc(buffer + pos, 4*4, f);
45
46 n_channels = 8;
47 } else
48 dumbfile_getnc(buffer, 64 * n_channels * 4, f);
49
50 if (dumbfile_error(f))
51 return -1;
52
53 /* compute number of entries */
54 pattern->n_entries = 64; /* Account for the row end markers */
55 pos = 0;
56 for (row = 0; row < 64; row++) {
57 for (channel = 0; channel < n_channels; channel++) {
58 if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3])
59 pattern->n_entries++;
60 pos += 4;
61 }
62 }
63
64 pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
65 if (!pattern->entry)
66 return -1;
67
68 entry = pattern->entry;
69 pos = 0;
70 for (row = 0; row < 64; row++) {
71 for (channel = 0; channel < n_channels; channel++) {
72 if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3]) {
73 unsigned char sample = (buffer[pos+0] & 0xF0) | (buffer[pos+2] >> 4);
74 int period = ((int)(buffer[pos+0] & 0x0F) << 8) | buffer[pos+1];
75
76 entry->channel = channel;
77 entry->mask = 0;
78
79 if (period) {
80 int note;
81 entry->mask |= IT_ENTRY_NOTE;
82
83 /* frequency = (AMIGA_DIVISOR / 8) / (period * 2)
84 * C-1: period = 214 -> frequency = 16726
85 * so, set C5_speed to 16726
86 * and period = 214 should translate to C5 aka 60
87 * halve the period, go up an octive
88 *
89 * period = 214 / pow(DUMB_SEMITONE_BASE, note - 60)
90 * pow(DUMB_SEMITONE_BASE, note - 60) = 214 / period
91 * note - 60 = log(214/period) / log(DUMB_SEMITONE_BASE)
92 */
93 note = (int)floor(log(214.0/period) / log(DUMB_SEMITONE_BASE) + 60.5);
94 entry->note = MID(0, note, 119);
95 // or should we preserve the period?
96 //entry->note = buffer[pos+0] & 0x0F; /* High nibble */
97 //entry->volpan = buffer[pos+1]; /* Low byte */
98 // and what about finetune?
99 }
100
101 if (sample) {
102 entry->mask |= IT_ENTRY_INSTRUMENT;
103 entry->instrument = sample;
104 }
105
106 _dumb_it_xm_convert_effect(buffer[pos+2] & 0x0F, buffer[pos+3], entry);
107
108 entry++;
109 }
110 pos += 4;
111 }
112 IT_SET_END_ROW(entry);
113 entry++;
114 }
115
116 return 0;
117}
118
119
120
121/* This function does not skip the name (22 bytes); it is assumed the caller
122 * has already done that.
123 */
124static int it_mod_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
125{
126 int finetune;
127
128/**
129 21 22 Chars Sample 1 name. If the name is not a full
130 22 chars in length, it will be null
131 terminated.
132
133If
134the sample name begins with a '#' character (ASCII $23 (35)) then this is
135assumed not to be an instrument name, and is probably a message.
136*/
137 sample->length = dumbfile_mgetw(f) << 1;
138 finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */
139/** Each finetune step changes the note 1/8th of a semitone. */
140 sample->global_volume = 64;
141 sample->default_volume = dumbfile_getc(f); // Should we be setting global_volume to this instead?
142 sample->loop_start = dumbfile_mgetw(f) << 1;
143 sample->loop_end = sample->loop_start + (dumbfile_mgetw(f) << 1);
144/**
145Once this sample has been played completely from beginning
146to end, if the repeat length (next field) is greater than two bytes it
147will loop back to this position in the sample and continue playing. Once
148it has played for the repeat length, it continues to loop back to the
149repeat start offset. This means the sample continues playing until it is
150told to stop.
151*/
152
153 if (sample->length <= 0) {
154 sample->flags = 0;
155 return 0;
156 }
157
158 sample->flags = IT_SAMPLE_EXISTS;
159
160 sample->default_pan = 0;
161 sample->C5_speed = (long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
162 // the above line might be wrong
163
164 if (sample->loop_end > sample->length)
165 sample->loop_end = sample->length;
166
167 if (sample->loop_end - sample->loop_start > 2)
168 sample->flags |= IT_SAMPLE_LOOP;
169
170 sample->vibrato_speed = 0;
171 sample->vibrato_depth = 0;
172 sample->vibrato_rate = 0;
173 sample->vibrato_waveform = 0; // do we have to set _all_ these?
174
175 return dumbfile_error(f);
176}
177
178
179
180static int it_mod_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f)
181{
182 long i;
183 long truncated_size;
184
185 /* let's get rid of the sample data coming after the end of the loop */
186 if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
187 truncated_size = sample->length - sample->loop_end;
188 sample->length = sample->loop_end;
189 } else {
190 truncated_size = 0;
191 }
192
193 sample->left = malloc(sample->length * sizeof(*sample->left));
194
195 if (!sample->left)
196 return -1;
197
198 /* Sample data are stored in "8-bit two's compliment format" (sic). */
199 for (i = 0; i < sample->length; i++)
200 sample->left[i] = (int)(signed char)dumbfile_getc(f) << 16;
201
202 /* skip truncated data */
203 dumbfile_skip(f, truncated_size);
204 // Should we be truncating it?
205
206 if (dumbfile_error(f))
207 return -1;
208
209 return 0;
210}
211
212
213
214typedef struct BUFFERED_MOD BUFFERED_MOD;
215
216struct BUFFERED_MOD
217{
218 unsigned char *buffered;
219 long ptr, len;
220 DUMBFILE *remaining;
221};
222
223
224
225static int buffer_mod_skip(void *f, long n)
226{
227 BUFFERED_MOD *bm = f;
228 if (bm->buffered) {
229 bm->ptr += n;
230 if (bm->ptr >= bm->len) {
231 free(bm->buffered);
232 bm->buffered = NULL;
233 return dumbfile_skip(bm->remaining, bm->ptr - bm->len);
234 }
235 return 0;
236 }
237 return dumbfile_skip(bm->remaining, n);
238}
239
240
241
242static int buffer_mod_getc(void *f)
243{
244 BUFFERED_MOD *bm = f;
245 if (bm->buffered) {
246 int rv = bm->buffered[bm->ptr++];
247 if (bm->ptr >= bm->len) {
248 free(bm->buffered);
249 bm->buffered = NULL;
250 }
251 return rv;
252 }
253 return dumbfile_getc(bm->remaining);
254}
255
256
257
258static long buffer_mod_getnc(char *ptr, long n, void *f)
259{
260 BUFFERED_MOD *bm = f;
261 if (bm->buffered) {
262 int left = bm->len - bm->ptr;
263 if (n >= left) {
264 int rv;
265 memcpy(ptr, bm->buffered + bm->ptr, left);
266 free(bm->buffered);
267 bm->buffered = NULL;
268 rv = dumbfile_getnc(ptr + left, n - left, bm->remaining);
269 return left + MAX(rv, 0);
270 }
271 memcpy(ptr, bm->buffered + bm->ptr, n);
272 bm->ptr += n;
273 return n;
274 }
275 return dumbfile_getnc(ptr, n, bm->remaining);
276}
277
278
279
280static void buffer_mod_close(void *f)
281{
282 BUFFERED_MOD *bm = f;
283 if (bm->buffered) free(bm->buffered);
284 /* Do NOT close bm->remaining */
285 free(f);
286}
287
288
289
290DUMBFILE_SYSTEM buffer_mod_dfs = {
291 NULL,
292 &buffer_mod_skip,
293 &buffer_mod_getc,
294 &buffer_mod_getnc,
295 &buffer_mod_close
296};
297
298
299
300#define MOD_FFT_OFFSET (20 + 31*(22+2+1+1+2+2) + 1 + 1 + 128)
301
302static DUMBFILE *dumbfile_buffer_mod(DUMBFILE *f, unsigned long *fft)
303{
304 BUFFERED_MOD *bm = malloc(sizeof(*bm));
305 if (!bm) return NULL;
306
307 bm->buffered = malloc(MOD_FFT_OFFSET + 4);
308 if (!bm->buffered) {
309 free(bm);
310 return NULL;
311 }
312
313 bm->len = dumbfile_getnc(bm->buffered, MOD_FFT_OFFSET + 4, f);
314
315 if (bm->len > 0) {
316 if (bm->len >= MOD_FFT_OFFSET + 4)
317 *fft = (unsigned long)bm->buffered[MOD_FFT_OFFSET ] << 24
318 | (unsigned long)bm->buffered[MOD_FFT_OFFSET+1] << 16
319 | (unsigned long)bm->buffered[MOD_FFT_OFFSET+2] << 8
320 | (unsigned long)bm->buffered[MOD_FFT_OFFSET+3];
321 else
322 *fft = 0;
323 bm->ptr = 0;
324 } else {
325 free(bm->buffered);
326 bm->buffered = NULL;
327 }
328
329 bm->remaining = f;
330
331 return dumbfile_open_ex(bm, &buffer_mod_dfs);
332}
333
334
335
336static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f)
337{
338 DUMB_IT_SIGDATA *sigdata;
339 int n_channels;
340 int i;
341 unsigned long fft;
342
343 f = dumbfile_buffer_mod(f, &fft);
344 if (!f)
345 return NULL;
346
347 /**
348 1 20 Chars Title of the song. If the title is not a
349 full 20 chars in length, it will be null-
350 terminated.
351 */
352 if (dumbfile_skip(f, 20)) {
353 dumbfile_close(f);
354 return NULL;
355 }
356
357 sigdata = malloc(sizeof(*sigdata));
358 if (!sigdata) {
359 dumbfile_close(f);
360 return NULL;
361 }
362
363 sigdata->n_samples = 31;
364
365 switch (fft) {
366 case DUMB_ID('M','.','K','.'):
367 case DUMB_ID('M','!','K','!'):
368 case DUMB_ID('M','&','K','!'):
369 case DUMB_ID('N','.','T','.'):
370 case DUMB_ID('F','L','T','4'):
371 n_channels = 4;
372 break;
373 case DUMB_ID('F','L','T','8'):
374 n_channels = 0;
375 /* 0 indicates a special case; two four-channel patterns must be
376 * combined into one eight-channel pattern. Pattern indexes must
377 * be halved. Why oh why do they obfuscate so?
378 */
379 for (i = 0; i < 128; i++)
380 sigdata->order[i] >>= 1;
381 break;
382 case DUMB_ID('C','D','8','1'):
383 case DUMB_ID('O','C','T','A'):
384 case DUMB_ID('O','K','T','A'):
385 n_channels = 8;
386 break;
387 case DUMB_ID('1','6','C','N'):
388 n_channels = 16;
389 break;
390 case DUMB_ID('3','2','C','N'):
391 n_channels = 32;
392 break;
393 default:
394 /* If we get an illegal tag, assume 4 channels 15 samples. */
395 if ((fft & 0x0000FFFFL) == DUMB_ID(0,0,'C','H')) {
396 if (fft >= '1' << 24 && fft < '4' << 24) {
397 n_channels = ((fft & 0x00FF0000L) >> 16) - '0';
398 if ((unsigned int)n_channels >= 10) {
399 /* Rightmost character wasn't a digit. */
400 n_channels = 4;
401 sigdata->n_samples = 15;
402 } else {
403 n_channels += (((fft & 0xFF000000L) >> 24) - '0') * 10;
404 /* MODs should really only go up to 32 channels, but we're lenient. */
405 if ((unsigned int)(n_channels - 1) >= DUMB_IT_N_CHANNELS - 1) {
406 /* No channels or too many? Can't be right... */
407 n_channels = 4;
408 sigdata->n_samples = 15;
409 }
410 }
411 } else {
412 n_channels = 4;
413 sigdata->n_samples = 15;
414 }
415 } else if ((fft & 0x00FFFFFFL) == DUMB_ID(0,'C','H','N')) {
416 n_channels = (fft >> 24) - '0';
417 if ((unsigned int)(n_channels - 1) >= 9) {
418 /* Character was '0' or it wasn't a digit */
419 n_channels = 4;
420 sigdata->n_samples = 15;
421 }
422 } else if ((fft & 0xFFFFFF00L) == DUMB_ID('T','D','Z',0)) {
423 n_channels = (fft & 0x000000FFL) - '0';
424 if ((unsigned int)(n_channels - 1) >= 9) {
425 /* We've been very lenient, given that it should have
426 * been 1, 2 or 3, but this MOD has been very naughty and
427 * must be punished.
428 */
429 n_channels = 4;
430 sigdata->n_samples = 15;
431 }
432 } else {
433 n_channels = 4;
434 sigdata->n_samples = 15;
435 }
436 }
437
438 sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
439 if (!sigdata->sample) {
440 free(sigdata);
441 dumbfile_close(f);
442 return NULL;
443 }
444
445 sigdata->order = NULL;
446 sigdata->instrument = NULL;
447 sigdata->pattern = NULL;
448 sigdata->midi = NULL;
449 sigdata->checkpoint = NULL;
450
451 for (i = 0; i < sigdata->n_samples; i++)
452 sigdata->sample[i].right = sigdata->sample[i].left = NULL;
453
454 for (i = 0; i < sigdata->n_samples; i++) {
455 if (dumbfile_skip(f, 22) ||
456 it_mod_read_sample_header(&sigdata->sample[i], f))
457 {
458 _dumb_it_unload_sigdata(sigdata);
459 dumbfile_close(f);
460 return NULL;
461 }
462 }
463
464 sigdata->n_orders = dumbfile_getc(f);
465 sigdata->restart_position = dumbfile_getc(f);
466 // what if this is >= 127? what about with Fast Tracker II?
467
468 if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right?
469 _dumb_it_unload_sigdata(sigdata);
470 dumbfile_close(f);
471 return NULL;
472 }
473
474 //if (sigdata->restart_position >= sigdata->n_orders)
475 //sigdata->restart_position = 0;
476
477 sigdata->order = malloc(128); /* We may need to scan the extra ones! */
478 if (!sigdata->order) {
479 _dumb_it_unload_sigdata(sigdata);
480 dumbfile_close(f);
481 return NULL;
482 }
483 if (dumbfile_getnc(sigdata->order, 128, f) < 128) {
484 _dumb_it_unload_sigdata(sigdata);
485 dumbfile_close(f);
486 return NULL;
487 }
488
489 /* "The old NST format contains only 15 samples (instead of 31). Further
490 * it doesn't contain a file format tag (id). So Pattern data offset is
491 * at 20+15*30+1+1+128."
492 * - Then I shall assume the File Format Tag never exists if there are
493 * only 15 samples. I hope this isn't a faulty assumption...
494 */
495 if (sigdata->n_samples == 31)
496 dumbfile_skip(f, 4);
497
498 /* Work out how many patterns there are. */
499 sigdata->n_patterns = -1;
500 for (i = 0; i < 128; i++)
501 if (sigdata->n_patterns < sigdata->order[i])
502 sigdata->n_patterns = sigdata->order[i];
503 sigdata->n_patterns++;
504
505 /* May as well try to save a tiny bit of memory. */
506 if (sigdata->n_orders < 128) {
507 unsigned char *order = realloc(sigdata->order, sigdata->n_orders);
508 if (order) sigdata->order = order;
509 }
510
511 sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
512 if (!sigdata->pattern) {
513 _dumb_it_unload_sigdata(sigdata);
514 dumbfile_close(f);
515 return NULL;
516 }
517 for (i = 0; i < sigdata->n_patterns; i++)
518 sigdata->pattern[i].entry = NULL;
519
520 /* Read in the patterns */
521 {
522 unsigned char *buffer = malloc(256 * n_channels); /* 64 rows * 4 bytes */
523 if (!buffer) {
524 _dumb_it_unload_sigdata(sigdata);
525 dumbfile_close(f);
526 return NULL;
527 }
528 for (i = 0; i < sigdata->n_patterns; i++) {
529 if (it_mod_read_pattern(&sigdata->pattern[i], f, n_channels, buffer) != 0) {
530 free(buffer);
531 _dumb_it_unload_sigdata(sigdata);
532 dumbfile_close(f);
533 return NULL;
534 }
535 }
536 free(buffer);
537 }
538
539 /* And finally, the sample data */
540 for (i = 0; i < sigdata->n_samples; i++) {
541 if (it_mod_read_sample_data(&sigdata->sample[i], f)) {
542 _dumb_it_unload_sigdata(sigdata);
543 dumbfile_close(f);
544 return NULL;
545 }
546 }
547
548 dumbfile_close(f); /* Destroy the BUFFERED_MOD DUMBFILE we were using. */
549 /* The DUMBFILE originally passed to our function is intact. */
550
551 /* Now let's initialise the remaining variables, and we're done! */
552 sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO;
553
554 sigdata->global_volume = 128;
555 sigdata->mixing_volume = 48;
556 /* We want 50 ticks per second; 50/6 row advances per second;
557 * 50*10=500 row advances per minute; 500/4=125 beats per minute.
558 */
559 sigdata->speed = 6;
560 sigdata->tempo = 125;
561 sigdata->pan_separation = 128;
562
563 memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
564
565 for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
566 sigdata->channel_pan[i+0] = 16;
567 sigdata->channel_pan[i+1] = 48;
568 sigdata->channel_pan[i+2] = 48;
569 sigdata->channel_pan[i+3] = 16;
570 }
571
572 _dumb_it_fix_invalid_orders(sigdata);
573
574 return sigdata;
575}
576
577
578
579DUH *dumb_read_mod(DUMBFILE *f)
580{
581 sigdata_t *sigdata;
582 long length;
583
584 DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
585
586 sigdata = it_mod_load_sigdata(f);
587
588 if (!sigdata)
589 return NULL;
590
591 length = _dumb_it_build_checkpoints(sigdata);
592
593 return make_duh(length, 1, &descptr, &sigdata);
594}