/* _______ ____ __ ___ ___ * \ _ \ \ / \ / \ \ / / ' ' ' * | | \ \ | | || | \/ | . . * | | | | | | || ||\ /| | * | | | | | | || || \/ | | ' ' ' * | | | | | | || || | | . . * | |_/ / \ \__// || | | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque * / \ * / . \ * readpsm.c - Code to read an old Protracker / / \ \ * Studio module from an open file. | < / \_ * | \/ /\ / * By Chris Moeller. \_ / > / * | \ / / * | ' / * \__/ */ #include #include #include #include "dumb.h" #include "internal/it.h" static int psm_sample_compare(const void *e1, const void *e2) { const unsigned char * pa = e1; const unsigned char * pb = e2; int a = pa[37] | (pa[38] << 8) | (pa[39] << 16) | (pa[40] << 24); int b = pb[37] | (pb[38] << 8) | (pb[39] << 16) | (pb[40] << 24); return a - b; } static int it_old_psm_read_samples(IT_SAMPLE ** sample, DUMBFILE * f, int * num, const unsigned char * prebuffer, long data_pos, long data_size) { int n, o, pos, count = *num, true_num, snum, offset, flags, finetune, delta; unsigned char * buffer, * sbuffer = 0; const unsigned char * sdata; buffer = malloc(count * 64); if (!buffer) goto error; if (dumbfile_getnc(buffer, count * 64, f) < count * 64) goto error_fb; pos = dumbfile_pos(f); true_num = 0; for (n = 0; n < count; n++) { snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8); if ((snum < 1) || (snum > 255)) goto error_fb; if (true_num < snum) true_num = snum; } if (true_num > count) { IT_SAMPLE * meh = realloc(*sample, true_num * sizeof(*meh)); if (!meh) goto error_fb; for (n = count; n < true_num; n++) { meh[n].data = NULL; } *sample = meh; *num = true_num; } qsort(buffer, count, 64, &psm_sample_compare); for (n = 0; n < true_num; n++) { (*sample)[n].flags = 0; } for (n = 0; n < count; n++) { IT_SAMPLE * s; snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8); s = &((*sample)[snum - 1]); memcpy(s->filename, buffer + (n * 64), 13); s->filename[13] = 0; memcpy(s->name, buffer + (n * 64) + 13, 24); s->name[24] = 0; offset = buffer[(n * 64) + 37] | (buffer[(n * 64) + 38] << 8) | (buffer[(n * 64) + 39] << 16) | (buffer[(n * 64) + 40] << 24); flags = buffer[(n * 64) + 47]; s->length = buffer[(n * 64) + 48] | (buffer[(n * 64) + 49] << 8) | (buffer[(n * 64) + 50] << 16) | (buffer[(n * 64) + 51] << 24); s->loop_start = buffer[(n * 64) + 52] | (buffer[(n * 64) + 53] << 8) | (buffer[(n * 64) + 54] << 16) | (buffer[(n * 64) + 55] << 24); s->loop_end = buffer[(n * 64) + 56] | (buffer[(n * 64) + 57] << 8) | (buffer[(n * 64) + 58] << 16) | (buffer[(n * 64) + 59] << 24); if (s->length <= 0) continue; finetune = buffer[(n * 64) + 60]; s->default_volume = buffer[(n * 64) + 61]; s->C5_speed = buffer[(n * 64) + 62] | (buffer[(n * 64) + 63] << 8); if (finetune < 16) { if (finetune >= 8) finetune -= 16; //s->C5_speed = (long)((double)s->C5_speed * pow(DUMB_PITCH_BASE, finetune*32)); s->finetune = finetune * 32; } else s->finetune = 0; s->flags |= IT_SAMPLE_EXISTS; if (flags & 0x41) { s->flags &= ~IT_SAMPLE_EXISTS; continue; } if (flags & 0x20) s->flags |= IT_SAMPLE_PINGPONG_LOOP; if (flags & 4) s->flags |= IT_SAMPLE_16BIT; if (flags & 0x80) { s->flags |= IT_SAMPLE_LOOP; if ((unsigned int)s->loop_end > (unsigned int)s->length) s->loop_end = s->length; else if ((unsigned int)s->loop_start >= (unsigned int)s->loop_end) s->flags &= ~IT_SAMPLE_LOOP; else s->length = s->loop_end; } s->global_volume = 64; s->vibrato_speed = 0; s->vibrato_depth = 0; s->vibrato_rate = 0; s->vibrato_waveform = IT_VIBRATO_SINE; s->max_resampling_quality = -1; s->data = malloc(s->length * ((flags & 4) ? 2 : 1)); if (!s->data) goto error_fb; if ((offset >= data_pos) && ((offset + s->length * ((flags & 4) ? 2 : 1)) <= (data_pos + data_size))) { sdata = prebuffer + offset - data_pos; } else if (offset >= pos) { if (dumbfile_skip(f, offset - pos)) goto error_fb; pos = offset; offset = s->length * ((flags & 4) ? 2 : 1); sbuffer = malloc(offset); if (!sbuffer) goto error_fb; if (dumbfile_getnc(sbuffer, offset, f) < offset) goto error_fsb; sdata = sbuffer; } else goto error_fb; if (flags & 0x10) { if (flags & 8) { if (flags & 4) { for (o = 0; o < s->length; o++) ((short *)s->data)[o] = (sdata[o * 2] | (sdata[(o * 2) + 1] << 8)) ^ 0x8000; } else { for (o = 0; o < s->length; o++) ((signed char *)s->data)[o] = sdata[o] ^ 0x80; } } else { if (flags & 4) { for (o = 0; o < s->length; o++) ((short *)s->data)[o] = sdata[o * 2] | (sdata[(o * 2) + 1] << 8); } else { memcpy(s->data, sdata, s->length); } } } else { delta = 0; if (flags & 8) { /* unsigned delta? mehhh, does anything even use this? */ if (flags & 4) { for (o = 0; o < s->length; o++) { delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8)); ((short *)s->data)[o] = delta ^ 0x8000; } } else { for (o = 0; o < s->length; o++) { delta += (signed char)sdata[o]; ((signed char *)s->data)[o] = delta ^ 0x80; } } } else { if (flags & 4) { for (o = 0; o < s->length; o++) { delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8)); ((short *)s->data)[o] = delta; } } else { for (o = 0; o < s->length; o++) { delta += (signed char)sdata[o]; ((signed char *)s->data)[o] = delta; } } } } if (sbuffer) { free(sbuffer); sbuffer = 0; } } free(buffer); return 0; error_fsb: if (sbuffer) free(sbuffer); error_fb: free(buffer); error: return -1; } static int it_old_psm_read_patterns(IT_PATTERN * pattern, DUMBFILE * f, int num, int size, int pchans, int sflags) { int n, offset, psize, rows, chans, row, flags, channel; unsigned char * buffer, * ptr, * end; IT_ENTRY * entry; buffer = malloc(size); if (!buffer) goto error; if (dumbfile_getnc(buffer, size, f) < size) goto error_fb; offset = 0; for (n = 0; n < num; n++) { IT_PATTERN * p = &pattern[n]; if (offset >= size) goto error_fb; ptr = buffer + offset; psize = ptr[0] | (ptr[1] << 8); rows = ptr[2]; chans = ptr[3]; if (!rows || !chans) { p->n_rows = 1; p->n_entries = 0; continue; } psize = (psize + 15) & ~15; end = ptr + psize; ptr += 4; p->n_rows = rows; p->n_entries = rows; row = 0; while ((row < rows) && (ptr < end)) { flags = *ptr++; if (!flags) { row++; continue; } if (flags & 0xE0) { p->n_entries++; if (flags & 0x80) ptr += 2; if (flags & 0x40) ptr++; if (flags & 0x20) { ptr++; if (*ptr == 40) ptr += 3; else ptr++; } } } entry = malloc(p->n_entries * sizeof(*p->entry)); if (!entry) goto error_fb; p->entry = entry; ptr = buffer + offset + 4; row = 0; while ((row < rows) && (ptr < end)) { flags = *ptr++; if (!flags) { IT_SET_END_ROW(entry); entry++; row++; continue; } if (flags & 0xE0) { entry->mask = 0; entry->channel = channel = flags & 0x1F; if (channel >= chans) { //channel = 0; goto error_fb; } if (flags & 0x80) { if ((*ptr < 60) && (channel < pchans)) { entry->mask |= IT_ENTRY_NOTE; entry->note = *ptr + 36; } ptr++; if (*ptr) { entry->mask |= IT_ENTRY_INSTRUMENT; entry->instrument = *ptr; } ptr++; } if (flags & 0x40) { if (*ptr <= 64) { entry->mask |= IT_ENTRY_VOLPAN; entry->volpan = *ptr; } ptr++; } if (flags & 0x20) { entry->mask |= IT_ENTRY_EFFECT; switch (*ptr) { case 1: entry->effect = IT_XM_FINE_VOLSLIDE_UP; entry->effectvalue = ptr[1]; break; case 2: entry->effect = IT_VOLUME_SLIDE; entry->effectvalue = (ptr[1] << 4) & 0xF0; break; case 3: entry->effect = IT_XM_FINE_VOLSLIDE_DOWN; entry->effectvalue = ptr[1]; break; case 4: entry->effect = IT_VOLUME_SLIDE; entry->effectvalue = ptr[1] & 0xF; break; case 10: entry->effect = IT_PORTAMENTO_UP; entry->effectvalue = EFFECT_VALUE(0xF, ptr[1]); break; case 11: entry->effect = IT_PORTAMENTO_UP; entry->effectvalue = ptr[1]; break; case 12: entry->effect = IT_PORTAMENTO_DOWN; entry->effectvalue = EFFECT_VALUE(ptr[1], 0xF); break; case 13: entry->effect = IT_PORTAMENTO_DOWN; entry->effectvalue = ptr[1]; break; case 14: entry->effect = IT_TONE_PORTAMENTO; entry->effectvalue = ptr[1]; break; case 15: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_SET_GLISSANDO_CONTROL, ptr[1] & 15); break; case 16: entry->effect = IT_VOLSLIDE_TONEPORTA; entry->effectvalue = ptr[1] << 4; break; case 17: entry->effect = IT_VOLSLIDE_TONEPORTA; entry->effectvalue = ptr[1] & 0xF; break; case 20: entry->effect = IT_VIBRATO; entry->effectvalue = ptr[1]; break; case 21: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_SET_VIBRATO_WAVEFORM, ptr[1] & 11); break; case 22: entry->effect = IT_VOLSLIDE_VIBRATO; entry->effectvalue = ptr[1] << 4; break; case 23: entry->effect = IT_VOLSLIDE_VIBRATO; entry->effectvalue = ptr[1] & 0xF; break; case 30: entry->effect = IT_TREMOLO; entry->effectvalue = ptr[1]; break; case 31: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_SET_TREMOLO_WAVEFORM, ptr[1] & 11); break; case 40: entry->effect = IT_SET_SAMPLE_OFFSET; entry->effectvalue = ptr[2]; ptr += 2; break; case 41: entry->effect = IT_XM_RETRIGGER_NOTE; entry->effectvalue = ptr[1]; break; case 42: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_DELAYED_NOTE_CUT, ptr[1] & 0xF); break; case 43: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_NOTE_DELAY, ptr[1] & 0xF); break; case 50: entry->effect = IT_JUMP_TO_ORDER; entry->effectvalue = ptr[1]; break; case 51: entry->effect = IT_BREAK_TO_ROW; entry->effectvalue = ptr[1]; break; case 52: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_LOOP, ptr[1] & 0xF); break; case 53: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_DELAY, ptr[1] & 0xF); break; case 60: entry->effect = IT_SET_SPEED; entry->effectvalue = ptr[1]; break; case 61: entry->effect = IT_SET_SONG_TEMPO; entry->effectvalue = ptr[1]; break; case 70: entry->effect = IT_ARPEGGIO; entry->effectvalue = ptr[1]; break; case 71: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_FINETUNE, ptr[1] & 0xF); break; case 72: /* "balance" ... panning? */ entry->effect = IT_SET_PANNING; entry->effectvalue = ((ptr[1] - ((ptr[1] & 8) >> 3)) << 5) / 7; break; default: entry->mask &= ~IT_ENTRY_EFFECT; } ptr += 2; } if (entry->mask) entry++; } } p->n_entries = entry - p->entry; offset += psize; } free(buffer); return 0; error_fb: free(buffer); error: return -1; } #define PSM_COMPONENT_ORDERS 0 #define PSM_COMPONENT_PANPOS 1 #define PSM_COMPONENT_PATTERNS 2 #define PSM_COMPONENT_SAMPLE_HEADERS 3 #define PSM_COMPONENT_COMMENTS 4 typedef struct PSM_COMPONENT { unsigned char type; long offset; } PSM_COMPONENT; static int psm_component_compare(const void *e1, const void *e2) { return ((const PSM_COMPONENT *)e1)->offset - ((const PSM_COMPONENT *)e2)->offset; } static DUMB_IT_SIGDATA *it_old_psm_load_sigdata(DUMBFILE *f) { DUMB_IT_SIGDATA *sigdata; unsigned char * ptr = 0; PSM_COMPONENT *component; int n_components = 0; int n, flags, version, pver, n_orders, n_channels, total_pattern_size; if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',254)) goto error; sigdata = malloc(sizeof(*sigdata)); if (!sigdata) goto error; if (dumbfile_getnc(sigdata->name, 60, f) < 60 || sigdata->name[59] != 0x1A) goto error_sd; sigdata->name[59] = 0; flags = dumbfile_getc(f); version = dumbfile_getc(f); pver = dumbfile_getc(f); sigdata->speed = dumbfile_getc(f); sigdata->tempo = dumbfile_getc(f); sigdata->mixing_volume = dumbfile_getc(f); sigdata->n_orders = dumbfile_igetw(f); n_orders = dumbfile_igetw(f); sigdata->n_patterns = dumbfile_igetw(f); sigdata->n_samples = dumbfile_igetw(f); sigdata->n_pchannels = dumbfile_igetw(f); n_channels = dumbfile_igetw(f); if (dumbfile_error(f) || (flags & 1) || (version != 1 && version != 0x10) || (pver) || (sigdata->n_orders <= 0) || (sigdata->n_orders > 255) || (n_orders > 255) || (n_orders < sigdata->n_orders) || (sigdata->n_patterns > 255) || (sigdata->n_samples > 255) || (sigdata->n_pchannels > DUMB_IT_N_CHANNELS) || (sigdata->n_pchannels > n_channels) || (n_channels > DUMB_IT_N_CHANNELS)) goto error_sd; sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX; sigdata->global_volume = 128; sigdata->pan_separation = 128; sigdata->song_message = NULL; sigdata->order = NULL; sigdata->instrument = NULL; sigdata->sample = NULL; sigdata->pattern = NULL; sigdata->midi = NULL; sigdata->checkpoint = NULL; sigdata->n_instruments = 0; sigdata->restart_position = 0; sigdata->order = malloc(sigdata->n_orders); if (!sigdata->order) goto error_usd; if (sigdata->n_samples) { sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); if (!sigdata->sample) goto error_usd; 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) goto error_usd; for (n = 0; n < sigdata->n_patterns; n++) sigdata->pattern[n].entry = NULL; } component = malloc(5 * sizeof(*component)); if (!component) goto error_usd; for (n = 0; n < 5; n++) { component[n_components].offset = dumbfile_igetl(f); if (component[n_components].offset) { component[n_components].type = n; n_components++; } } if (!n_components) goto error_fc; total_pattern_size = dumbfile_igetl(f); if (!total_pattern_size) goto error_fc; qsort(component, n_components, sizeof(PSM_COMPONENT), &psm_component_compare); memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) { sigdata->channel_pan[n ] = 16; sigdata->channel_pan[n+1] = 48; sigdata->channel_pan[n+2] = 48; sigdata->channel_pan[n+3] = 16; } for (n = 0; n < n_components; n++) { int o; long data_pos, data_size; /* Whee, sample data may be before the sample headers */ data_pos = dumbfile_pos(f); if (data_pos > component[n].offset) goto error_fc; data_size = component[n].offset - data_pos; if (data_size) { ptr = malloc(data_size); if (!ptr) goto error_fc; if (dumbfile_getnc(ptr, data_size, f) < data_size) goto error_fp; } switch (component[n].type) { case PSM_COMPONENT_ORDERS: if (dumbfile_getnc(sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_fp; if (n_orders > sigdata->n_orders) if (dumbfile_skip(f, n_orders - sigdata->n_orders)) goto error_fp; if (dumbfile_igetw(f)) goto error_fp; break; case PSM_COMPONENT_PANPOS: if (dumbfile_getnc(sigdata->channel_pan, sigdata->n_pchannels, f) < sigdata->n_pchannels) goto error_fp; for (o = 0; o < sigdata->n_pchannels; o++) { sigdata->channel_pan[o] -= (sigdata->channel_pan[o] & 8) >> 3; sigdata->channel_pan[o] = ((int)sigdata->channel_pan[o] << 5) / 7; } break; case PSM_COMPONENT_PATTERNS: if (it_old_psm_read_patterns(sigdata->pattern, f, sigdata->n_patterns, total_pattern_size, sigdata->n_pchannels, flags)) goto error_fp; break; case PSM_COMPONENT_SAMPLE_HEADERS: if (it_old_psm_read_samples(&sigdata->sample, f, &sigdata->n_samples, ptr, data_pos, data_size)) goto error_fp; break; case PSM_COMPONENT_COMMENTS: if (dumbfile_mgetl(f) == DUMB_ID('T','E','X','T')) { o = dumbfile_igetw(f); if (o > 0) { sigdata->song_message = malloc(o + 1); if (dumbfile_getnc(sigdata->song_message, o, f) < o) goto error_fp; sigdata->song_message[o] = 0; } } break; } if (ptr) { free(ptr); ptr = 0; } } _dumb_it_fix_invalid_orders(sigdata); free(component); return sigdata; error_fp: if (ptr) free(ptr); error_fc: free(component); error_usd: _dumb_it_unload_sigdata(sigdata); return NULL; error_sd: free(sigdata); error: return NULL; } DUH *dumb_read_old_psm_quick(DUMBFILE *f) { sigdata_t *sigdata; DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; sigdata = it_old_psm_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] = "PSM (old)"; return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); } }