diff options
Diffstat (limited to 'plugins/dumb/dumb-kode54/src/it/readptm.c')
-rw-r--r-- | plugins/dumb/dumb-kode54/src/it/readptm.c | 1148 |
1 files changed, 574 insertions, 574 deletions
diff --git a/plugins/dumb/dumb-kode54/src/it/readptm.c b/plugins/dumb/dumb-kode54/src/it/readptm.c index d8c77297..cae73edf 100644 --- a/plugins/dumb/dumb-kode54/src/it/readptm.c +++ b/plugins/dumb/dumb-kode54/src/it/readptm.c @@ -1,574 +1,574 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readptm.c - Code to read a Poly Tracker v2.03 / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. Based on reads3m.c \_ / > /
- * by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-// IT_STEREO... :o
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/** WARNING: this is duplicated in itread.c */
-static int it_seek(DUMBFILE *f, long offset)
-{
- long pos = dumbfile_pos(f);
-
- if (pos > offset)
- return -1;
-
- if (pos < offset)
- if (dumbfile_skip(f, offset - pos))
- return -1;
-
- return 0;
-}
-
-
-
-static int it_ptm_read_sample_header(IT_SAMPLE *sample, long *offset, DUMBFILE *f)
-{
- int flags;
-
- flags = dumbfile_getc(f);
-
- dumbfile_getnc(sample->filename, 12, f);
- sample->filename[12] = 0;
-
- sample->default_volume = dumbfile_getc(f);
-
- sample->C5_speed = dumbfile_igetw(f) << 1;
-
- dumbfile_skip(f, 2); /* segment */
-
- *offset = dumbfile_igetl(f);
-
- sample->length = dumbfile_igetl(f);
- sample->loop_start = dumbfile_igetl(f);
- sample->loop_end = dumbfile_igetl(f);
-
- /* GUSBegin, GUSLStart, GUSLEnd, GUSLoop, reserverd */
- dumbfile_skip(f, 4+4+4+1+1);
-
- dumbfile_getnc(sample->name, 28, f);
- sample->name[28] = 0;
-
- /*
- if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','S'))
- return -1;
- */
-
- /* BLAH! Shit likes to have broken or missing sample IDs */
- dumbfile_skip(f, 4);
-
- if ((flags & 3) == 0) {
- /* Looks like no sample */
- sample->flags &= ~IT_SAMPLE_EXISTS;
- return dumbfile_error(f);
- }
-
- sample->global_volume = 64;
-
- sample->flags = IT_SAMPLE_EXISTS;
- if (flags & 4) sample->flags |= IT_SAMPLE_LOOP;
- if (flags & 8) sample->flags |= IT_SAMPLE_PINGPONG_LOOP;
-
- if (flags & 16) {
- sample->flags |= IT_SAMPLE_16BIT;
-
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- }
-
- if (sample->loop_end) sample->loop_end--;
-
- sample->default_pan = 0; // 0 = don't use, or 160 = centre?
-
- if (sample->length <= 0)
- sample->flags &= ~IT_SAMPLE_EXISTS;
- else if (sample->flags & IT_SAMPLE_LOOP) {
- if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
- sample->flags &= ~IT_SAMPLE_LOOP;
- else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
- sample->flags &= ~IT_SAMPLE_LOOP;
- else
- sample->length = sample->loop_end;
- }
-
-
- //Do we need to set all these?
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = IT_VIBRATO_SINE;
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-
-static int it_ptm_read_byte(DUMBFILE *f)
-{
- int meh = dumbfile_getc(f);
- if (meh < 0) return 0;
- return meh;
-}
-
-static int it_ptm_read_sample_data(IT_SAMPLE *sample, int last, DUMBFILE *f)
-{
- long n;
- int s;
-
- sample->data = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
- if (!sample->data)
- return -1;
-
- s = 0;
-
- if (sample->flags & IT_SAMPLE_16BIT) {
- unsigned char a, b;
- for (n = 0; n < sample->length; n++) {
- a = s += (signed char) it_ptm_read_byte(f);
- b = s += (signed char) it_ptm_read_byte(f);
- ((short *)sample->data)[n] = a | (b << 8);
- }
- } else {
- for (n = 0; n < sample->length; n++) {
- s += (signed char) it_ptm_read_byte(f);
- ((signed char *)sample->data)[n] = s;
- }
- }
-
- if (dumbfile_error(f) && !last)
- return -1;
-
- return 0;
-}
-
-
-
-static int it_ptm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer, int length)
-{
- int buflen = 0;
- int bufpos = 0;
- int effect, effectvalue;
-
- IT_ENTRY *entry;
-
- unsigned char channel;
-
- if (!length)
- return -1;
-
- pattern->n_rows = 0;
- pattern->n_entries = 0;
-
- /* Read in the pattern data, little by little, and work out how many
- * entries we need room for. Sorry, but this is just so funny...
- */
- for (;;) {
- unsigned char b = buffer[buflen++] = dumbfile_getc(f);
-
-#if 1
- static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5};
- channel = b & 31;
- b >>= 5;
- pattern->n_entries++;
- if (b) {
- if (buflen + used[b] >= 65536) return -1;
- dumbfile_getnc(buffer + buflen, used[b], f);
- buflen += used[b];
- } else {
- /* End of row */
- if (++pattern->n_rows == 64) break;
- if (buflen >= 65536) return -1;
- }
-#else
- if (b == 0) {
- /* End of row */
- pattern->n_entries++;
- if (++pattern->n_rows == 64) break;
- if (buflen >= 65536) return -1;
- } else {
- static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5};
- channel = b & 31;
- b >>= 5;
- if (b) {
- pattern->n_entries++;
- if (buflen + used[b] >= 65536) return -1;
- dumbfile_getnc(buffer + buflen, used[b], f);
- buflen += used[b];
- }
- }
-#endif
-
- /* We have ensured that buflen < 65536 at this point, so it is safe
- * to iterate and read at least one more byte without checking.
- * However, now would be a good time to check for errors reading from
- * the file.
- */
-
- if (dumbfile_error(f))
- return -1;
-
- /* Great. We ran out of data, but there should be data for more rows.
- * Fill the rest with null data...
- */
- if (buflen >= length && pattern->n_rows < 64)
- {
- while (pattern->n_rows < 64)
- {
- if (buflen >= 65536) return -1;
- buffer[buflen++] = 0;
- pattern->n_entries++;
- pattern->n_rows++;
- }
- break;
- }
- }
-
- pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
-
- if (!pattern->entry)
- return -1;
-
- entry = pattern->entry;
-
- while (bufpos < buflen) {
- unsigned char b = buffer[bufpos++];
-
- if (b == 0)
- {
- /* End of row */
- IT_SET_END_ROW(entry);
- entry++;
- continue;
- }
-
- channel = b & 31;
-
- if (b & 224) {
- entry->mask = 0;
- entry->channel = channel;
-
- if (b & 32) {
- unsigned char n = buffer[bufpos++];
- if (n == 254 || (n >= 1 && n <= 120)) {
- if (n == 254)
- entry->note = IT_NOTE_CUT;
- else
- entry->note = n - 1;
- entry->mask |= IT_ENTRY_NOTE;
- }
-
- entry->instrument = buffer[bufpos++];
- if (entry->instrument)
- entry->mask |= IT_ENTRY_INSTRUMENT;
- }
-
- if (b & 64) {
- effect = buffer[bufpos++];
- effectvalue = buffer[bufpos++];
- _dumb_it_ptm_convert_effect(effect, effectvalue, entry);
- }
-
- if (b & 128) {
- entry->volpan = buffer[bufpos++];
- if (entry->volpan <= 64)
- entry->mask |= IT_ENTRY_VOLPAN;
- }
-
- entry++;
- }
- }
-
- ASSERT(entry == pattern->entry + pattern->n_entries);
-
- return 0;
-}
-
-
-
-/** WARNING: this is duplicated in itread.c - also bad practice to use the same struct name unless they are unified in a header */
-/* Currently we assume the sample data are stored after the sample headers in
- * module files. This assumption may be unjustified; let me know if you have
- * trouble.
- */
-
-#define PTM_COMPONENT_INSTRUMENT 1
-#define PTM_COMPONENT_PATTERN 2
-#define PTM_COMPONENT_SAMPLE 3
-
-typedef struct PTM_COMPONENT
-{
- unsigned char type;
- unsigned char n;
- long offset;
-}
-PTM_COMPONENT;
-
-
-
-static int ptm_component_compare(const void *e1, const void *e2)
-{
- return ((const PTM_COMPONENT *)e1)->offset -
- ((const PTM_COMPONENT *)e2)->offset;
-}
-
-
-
-static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- PTM_COMPONENT *component;
- int n_components = 0;
-
- int n;
-
- unsigned char *buffer;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) return NULL;
-
- /* Skip song name. */
- dumbfile_getnc(sigdata->name, 28, f);
- sigdata->name[28] = 0;
-
- if (dumbfile_getc(f) != 0x1A || dumbfile_igetw(f) != 0x203) {
- free(sigdata);
- return NULL;
- }
-
- dumbfile_skip(f, 1);
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_orders = dumbfile_igetw(f);
- sigdata->n_instruments = 0;
- sigdata->n_samples = dumbfile_igetw(f);
- sigdata->n_patterns = dumbfile_igetw(f);
-
- if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_samples > 255 || sigdata->n_patterns > 128) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->n_pchannels = dumbfile_igetw(f);
-
- if (dumbfile_igetw(f) != 0) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- dumbfile_skip(f, 2);
-
- if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','F')) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- dumbfile_skip(f, 16);
-
- sigdata->order = malloc(sigdata->n_orders);
- if (!sigdata->order) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (sigdata->n_samples) {
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
- }
-
- if (sigdata->n_patterns) {
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
- }
-
- /** WARNING: which ones? */
- sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_A_PTM;
-
- sigdata->global_volume = 128;
- sigdata->speed = 6;
- sigdata->tempo = 125;
- sigdata->mixing_volume = 48;
-
- /* Panning positions for 32 channels */
- {
- int i;
- for (i = 0; i < 32; i++) {
- int c = dumbfile_getc(f);
- if (c <= 15) {
- sigdata->channel_volume[i] = 64;
- sigdata->channel_pan[i] = c;
- } else {
- /** WARNING: this could be improved if we support channel muting... */
- sigdata->channel_volume[i] = 0;
- sigdata->channel_pan[i] = 7;
- }
- }
- }
-
- /* Orders, byte each, length = sigdata->n_orders (should be even) */
- dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
- sigdata->restart_position = 0;
-
- component = malloc(768*sizeof(*component));
- if (!component) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (it_seek(f, 352)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (n = 0; n < sigdata->n_patterns; n++) {
- component[n_components].type = PTM_COMPONENT_PATTERN;
- component[n_components].n = n;
- component[n_components].offset = dumbfile_igetw(f) << 4;
- n_components++;
- }
-
- if (it_seek(f, 608)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (n = 0; n < sigdata->n_samples; n++) {
- if (it_ptm_read_sample_header(&sigdata->sample[n], &component[n_components].offset, f)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- if (!(sigdata->sample[n].flags & IT_SAMPLE_EXISTS)) continue;
- component[n_components].type = PTM_COMPONENT_SAMPLE;
- component[n_components].n = n;
- n_components++;
- }
-
- qsort(component, n_components, sizeof(PTM_COMPONENT), &ptm_component_compare);
-
- {
- int i;
- for (i = 0; i < 32; i++) {
- sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3;
- sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7;
- if (sigdata->channel_pan[i] > 64) sigdata->channel_pan[i] = 64;
- }
- }
-
- sigdata->pan_separation = 128;
-
- if (dumbfile_error(f)) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- buffer = malloc(65536);
- if (!buffer) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (n = 0; n < n_components; n++) {
- if (it_seek(f, component[n].offset)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- switch (component[n].type) {
-
- case PTM_COMPONENT_PATTERN:
- if (it_ptm_read_pattern(&sigdata->pattern[component[n].n], f, buffer, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- break;
-
- case PTM_COMPONENT_SAMPLE:
- if (it_ptm_read_sample_data(&sigdata->sample[component[n].n], (n + 1 == n_components), f)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
- }
-
- free(buffer);
- free(component);
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-static char hexdigit(int in)
-{
- if (in < 10) return in + '0';
- else return in + 'A' - 10;
-}
-
-DUH *dumb_read_ptm_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_ptm_load_sigdata(f);
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "PTM";
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readptm.c - Code to read a Poly Tracker v2.03 / / \ \ + * module from an open file. | < / \_ + * | \/ /\ / + * By Chris Moeller. Based on reads3m.c \_ / > / + * by entheh. | \ / / + * | ' / + * \__/ + */ + +// IT_STEREO... :o +#include <stdlib.h> +#include <string.h> + +#include "dumb.h" +#include "internal/it.h" + + + +/** WARNING: this is duplicated in itread.c */ +static int it_seek(DUMBFILE *f, long offset) +{ + long pos = dumbfile_pos(f); + + if (pos > offset) + return -1; + + if (pos < offset) + if (dumbfile_skip(f, offset - pos)) + return -1; + + return 0; +} + + + +static int it_ptm_read_sample_header(IT_SAMPLE *sample, long *offset, DUMBFILE *f) +{ + int flags; + + flags = dumbfile_getc(f); + + dumbfile_getnc(sample->filename, 12, f); + sample->filename[12] = 0; + + sample->default_volume = dumbfile_getc(f); + + sample->C5_speed = dumbfile_igetw(f) << 1; + + dumbfile_skip(f, 2); /* segment */ + + *offset = dumbfile_igetl(f); + + sample->length = dumbfile_igetl(f); + sample->loop_start = dumbfile_igetl(f); + sample->loop_end = dumbfile_igetl(f); + + /* GUSBegin, GUSLStart, GUSLEnd, GUSLoop, reserverd */ + dumbfile_skip(f, 4+4+4+1+1); + + dumbfile_getnc(sample->name, 28, f); + sample->name[28] = 0; + + /* + if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','S')) + return -1; + */ + + /* BLAH! Shit likes to have broken or missing sample IDs */ + dumbfile_skip(f, 4); + + if ((flags & 3) == 0) { + /* Looks like no sample */ + sample->flags &= ~IT_SAMPLE_EXISTS; + return dumbfile_error(f); + } + + sample->global_volume = 64; + + sample->flags = IT_SAMPLE_EXISTS; + if (flags & 4) sample->flags |= IT_SAMPLE_LOOP; + if (flags & 8) sample->flags |= IT_SAMPLE_PINGPONG_LOOP; + + if (flags & 16) { + sample->flags |= IT_SAMPLE_16BIT; + + sample->length >>= 1; + sample->loop_start >>= 1; + sample->loop_end >>= 1; + } + + if (sample->loop_end) sample->loop_end--; + + sample->default_pan = 0; // 0 = don't use, or 160 = centre? + + if (sample->length <= 0) + sample->flags &= ~IT_SAMPLE_EXISTS; + else if (sample->flags & IT_SAMPLE_LOOP) { + if ((unsigned int)sample->loop_end > (unsigned int)sample->length) + sample->flags &= ~IT_SAMPLE_LOOP; + else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end) + sample->flags &= ~IT_SAMPLE_LOOP; + else + sample->length = sample->loop_end; + } + + + //Do we need to set all these? + sample->vibrato_speed = 0; + sample->vibrato_depth = 0; + sample->vibrato_rate = 0; + sample->vibrato_waveform = IT_VIBRATO_SINE; + sample->finetune = 0; + sample->max_resampling_quality = -1; + + return dumbfile_error(f); +} + + +static int it_ptm_read_byte(DUMBFILE *f) +{ + int meh = dumbfile_getc(f); + if (meh < 0) return 0; + return meh; +} + +static int it_ptm_read_sample_data(IT_SAMPLE *sample, int last, DUMBFILE *f) +{ + long n; + int s; + + sample->data = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1)); + if (!sample->data) + return -1; + + s = 0; + + if (sample->flags & IT_SAMPLE_16BIT) { + unsigned char a, b; + for (n = 0; n < sample->length; n++) { + a = s += (signed char) it_ptm_read_byte(f); + b = s += (signed char) it_ptm_read_byte(f); + ((short *)sample->data)[n] = a | (b << 8); + } + } else { + for (n = 0; n < sample->length; n++) { + s += (signed char) it_ptm_read_byte(f); + ((signed char *)sample->data)[n] = s; + } + } + + if (dumbfile_error(f) && !last) + return -1; + + return 0; +} + + + +static int it_ptm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer, int length) +{ + int buflen = 0; + int bufpos = 0; + int effect, effectvalue; + + IT_ENTRY *entry; + + unsigned char channel; + + if (!length) + return -1; + + pattern->n_rows = 0; + pattern->n_entries = 0; + + /* Read in the pattern data, little by little, and work out how many + * entries we need room for. Sorry, but this is just so funny... + */ + for (;;) { + unsigned char b = buffer[buflen++] = dumbfile_getc(f); + +#if 1 + static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5}; + channel = b & 31; + b >>= 5; + pattern->n_entries++; + if (b) { + if (buflen + used[b] >= 65536) return -1; + dumbfile_getnc(buffer + buflen, used[b], f); + buflen += used[b]; + } else { + /* End of row */ + if (++pattern->n_rows == 64) break; + if (buflen >= 65536) return -1; + } +#else + if (b == 0) { + /* End of row */ + pattern->n_entries++; + if (++pattern->n_rows == 64) break; + if (buflen >= 65536) return -1; + } else { + static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5}; + channel = b & 31; + b >>= 5; + if (b) { + pattern->n_entries++; + if (buflen + used[b] >= 65536) return -1; + dumbfile_getnc(buffer + buflen, used[b], f); + buflen += used[b]; + } + } +#endif + + /* We have ensured that buflen < 65536 at this point, so it is safe + * to iterate and read at least one more byte without checking. + * However, now would be a good time to check for errors reading from + * the file. + */ + + if (dumbfile_error(f)) + return -1; + + /* Great. We ran out of data, but there should be data for more rows. + * Fill the rest with null data... + */ + if (buflen >= length && pattern->n_rows < 64) + { + while (pattern->n_rows < 64) + { + if (buflen >= 65536) return -1; + buffer[buflen++] = 0; + pattern->n_entries++; + pattern->n_rows++; + } + break; + } + } + + pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); + + if (!pattern->entry) + return -1; + + entry = pattern->entry; + + while (bufpos < buflen) { + unsigned char b = buffer[bufpos++]; + + if (b == 0) + { + /* End of row */ + IT_SET_END_ROW(entry); + entry++; + continue; + } + + channel = b & 31; + + if (b & 224) { + entry->mask = 0; + entry->channel = channel; + + if (b & 32) { + unsigned char n = buffer[bufpos++]; + if (n == 254 || (n >= 1 && n <= 120)) { + if (n == 254) + entry->note = IT_NOTE_CUT; + else + entry->note = n - 1; + entry->mask |= IT_ENTRY_NOTE; + } + + entry->instrument = buffer[bufpos++]; + if (entry->instrument) + entry->mask |= IT_ENTRY_INSTRUMENT; + } + + if (b & 64) { + effect = buffer[bufpos++]; + effectvalue = buffer[bufpos++]; + _dumb_it_ptm_convert_effect(effect, effectvalue, entry); + } + + if (b & 128) { + entry->volpan = buffer[bufpos++]; + if (entry->volpan <= 64) + entry->mask |= IT_ENTRY_VOLPAN; + } + + entry++; + } + } + + ASSERT(entry == pattern->entry + pattern->n_entries); + + return 0; +} + + + +/** WARNING: this is duplicated in itread.c - also bad practice to use the same struct name unless they are unified in a header */ +/* Currently we assume the sample data are stored after the sample headers in + * module files. This assumption may be unjustified; let me know if you have + * trouble. + */ + +#define PTM_COMPONENT_INSTRUMENT 1 +#define PTM_COMPONENT_PATTERN 2 +#define PTM_COMPONENT_SAMPLE 3 + +typedef struct PTM_COMPONENT +{ + unsigned char type; + unsigned char n; + long offset; +} +PTM_COMPONENT; + + + +static int ptm_component_compare(const void *e1, const void *e2) +{ + return ((const PTM_COMPONENT *)e1)->offset - + ((const PTM_COMPONENT *)e2)->offset; +} + + + +static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f) +{ + DUMB_IT_SIGDATA *sigdata; + + PTM_COMPONENT *component; + int n_components = 0; + + int n; + + unsigned char *buffer; + + sigdata = malloc(sizeof(*sigdata)); + if (!sigdata) return NULL; + + /* Skip song name. */ + dumbfile_getnc(sigdata->name, 28, f); + sigdata->name[28] = 0; + + if (dumbfile_getc(f) != 0x1A || dumbfile_igetw(f) != 0x203) { + free(sigdata); + return NULL; + } + + dumbfile_skip(f, 1); + + sigdata->song_message = NULL; + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->sample = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + sigdata->n_orders = dumbfile_igetw(f); + sigdata->n_instruments = 0; + sigdata->n_samples = dumbfile_igetw(f); + sigdata->n_patterns = dumbfile_igetw(f); + + if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_samples > 255 || sigdata->n_patterns > 128) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + sigdata->n_pchannels = dumbfile_igetw(f); + + if (dumbfile_igetw(f) != 0) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + dumbfile_skip(f, 2); + + if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','F')) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + dumbfile_skip(f, 16); + + sigdata->order = malloc(sigdata->n_orders); + if (!sigdata->order) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + if (sigdata->n_samples) { + sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); + if (!sigdata->sample) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (n = 0; n < sigdata->n_samples; n++) + sigdata->sample[n].data = NULL; + } + + if (sigdata->n_patterns) { + sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); + if (!sigdata->pattern) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (n = 0; n < sigdata->n_patterns; n++) + sigdata->pattern[n].entry = NULL; + } + + /** WARNING: which ones? */ + sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_A_PTM; + + sigdata->global_volume = 128; + sigdata->speed = 6; + sigdata->tempo = 125; + sigdata->mixing_volume = 48; + + /* Panning positions for 32 channels */ + { + int i; + for (i = 0; i < 32; i++) { + int c = dumbfile_getc(f); + if (c <= 15) { + sigdata->channel_volume[i] = 64; + sigdata->channel_pan[i] = c; + } else { + /** WARNING: this could be improved if we support channel muting... */ + sigdata->channel_volume[i] = 0; + sigdata->channel_pan[i] = 7; + } + } + } + + /* Orders, byte each, length = sigdata->n_orders (should be even) */ + dumbfile_getnc(sigdata->order, sigdata->n_orders, f); + sigdata->restart_position = 0; + + component = malloc(768*sizeof(*component)); + if (!component) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + if (it_seek(f, 352)) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + for (n = 0; n < sigdata->n_patterns; n++) { + component[n_components].type = PTM_COMPONENT_PATTERN; + component[n_components].n = n; + component[n_components].offset = dumbfile_igetw(f) << 4; + n_components++; + } + + if (it_seek(f, 608)) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + for (n = 0; n < sigdata->n_samples; n++) { + if (it_ptm_read_sample_header(&sigdata->sample[n], &component[n_components].offset, f)) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + if (!(sigdata->sample[n].flags & IT_SAMPLE_EXISTS)) continue; + component[n_components].type = PTM_COMPONENT_SAMPLE; + component[n_components].n = n; + n_components++; + } + + qsort(component, n_components, sizeof(PTM_COMPONENT), &ptm_component_compare); + + { + int i; + for (i = 0; i < 32; i++) { + sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3; + sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7; + if (sigdata->channel_pan[i] > 64) sigdata->channel_pan[i] = 64; + } + } + + sigdata->pan_separation = 128; + + if (dumbfile_error(f)) { + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + buffer = malloc(65536); + if (!buffer) { + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + for (n = 0; n < n_components; n++) { + if (it_seek(f, component[n].offset)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + switch (component[n].type) { + + case PTM_COMPONENT_PATTERN: + if (it_ptm_read_pattern(&sigdata->pattern[component[n].n], f, buffer, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + break; + + case PTM_COMPONENT_SAMPLE: + if (it_ptm_read_sample_data(&sigdata->sample[component[n].n], (n + 1 == n_components), f)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + } + } + + free(buffer); + free(component); + + _dumb_it_fix_invalid_orders(sigdata); + + return sigdata; +} + +static char hexdigit(int in) +{ + if (in < 10) return in + '0'; + else return in + 'A' - 10; +} + +DUH *dumb_read_ptm_quick(DUMBFILE *f) +{ + sigdata_t *sigdata; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_ptm_load_sigdata(f); + + if (!sigdata) + return NULL; + + { + const char *tag[2][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + tag[1][0] = "FORMAT"; + tag[1][1] = "PTM"; + return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); + } +} |