ref: 55dc14c317eca4d0ca2b1860514223b66eaa6eb6
dir: /src/it/readoldpsm.c/
/* _______ ____ __ ___ ___ * \ _ \ \ / \ / \ \ / / ' ' ' * | | \ \ | | || | \/ | . . * | | | | | | || ||\ /| | * | | | | | | || || \/ | | ' ' ' * | | | | | | || || | | . . * | |_/ / \ \__// || | | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque * / \ * / . \ * readpsm.c - Code to read an old Protracker / / \ \ * Studio module from an open file. | < / \_ * | \/ /\ / * By Christopher Snowhill. \_ / > / * | \ / / * | ' / * \__/ */ #include <stdlib.h> #include <string.h> #include <math.h> #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) { int n, o, count = *num, true_num, snum, offset, flags, finetune, delta; unsigned char *buffer; const unsigned char *sdata; long sample_bytes; buffer = malloc(count * 64); if (!buffer) goto error; if (dumbfile_getnc((char *)buffer, count * 64, f) < count * 64) goto error_fb; 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 < *num; n++) { (*sample)[n].flags = 0; } for (n = 0; n < count; n++) { IT_SAMPLE smp; IT_SAMPLE *s; snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8); s = &((*sample)[snum - 1]); memcpy(smp.filename, buffer + (n * 64), 13); smp.filename[13] = 0; memcpy(smp.name, buffer + (n * 64) + 13, 24); smp.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]; smp.length = buffer[(n * 64) + 48] | (buffer[(n * 64) + 49] << 8) | (buffer[(n * 64) + 50] << 16) | (buffer[(n * 64) + 51] << 24); smp.loop_start = buffer[(n * 64) + 52] | (buffer[(n * 64) + 53] << 8) | (buffer[(n * 64) + 54] << 16) | (buffer[(n * 64) + 55] << 24); smp.loop_end = buffer[(n * 64) + 56] | (buffer[(n * 64) + 57] << 8) | (buffer[(n * 64) + 58] << 16) | (buffer[(n * 64) + 59] << 24); if (smp.length <= 0) continue; finetune = buffer[(n * 64) + 60]; smp.default_volume = buffer[(n * 64) + 61]; smp.C5_speed = buffer[(n * 64) + 62] | (buffer[(n * 64) + 63] << 8); if (finetune & 15) { finetune &= 15; if (finetune >= 8) finetune -= 16; // s->C5_speed = (long)((double)s->C5_speed * pow(DUMB_PITCH_BASE, // finetune*32)); smp.finetune = finetune * 32; } else smp.finetune = 0; smp.flags = IT_SAMPLE_EXISTS; if (flags & 0x41) continue; if (flags & 0x20) smp.flags |= IT_SAMPLE_PINGPONG_LOOP; if (flags & 4) smp.flags |= IT_SAMPLE_16BIT; if (flags & 0x80) { smp.flags |= IT_SAMPLE_LOOP; if ((unsigned int)smp.loop_end > (unsigned int)smp.length) smp.loop_end = smp.length; else if ((unsigned int)smp.loop_start >= (unsigned int)smp.loop_end) smp.flags &= ~IT_SAMPLE_LOOP; else smp.length = smp.loop_end; } smp.global_volume = 64; smp.vibrato_speed = 0; smp.vibrato_depth = 0; smp.vibrato_rate = 0; smp.vibrato_waveform = IT_VIBRATO_SINE; smp.max_resampling_quality = -1; sample_bytes = smp.length * ((flags & 4) ? 2 : 1); smp.data = malloc(sample_bytes); if (!smp.data) goto error_fb; sdata = (const unsigned char *)smp.data; if (dumbfile_seek(f, offset, DFS_SEEK_SET) || dumbfile_getnc(smp.data, sample_bytes, f) < sample_bytes) goto error_fd; if (flags & 0x10) { if (flags & 8) { if (flags & 4) { for (o = 0; o < smp.length; o++) ((short *)smp.data)[o] = (sdata[o * 2] | (sdata[(o * 2) + 1] << 8)) ^ 0x8000; } else { for (o = 0; o < smp.length; o++) ((signed char *)smp.data)[o] = sdata[o] ^ 0x80; } } else { if (flags & 4) { for (o = 0; o < smp.length; o++) ((short *)smp.data)[o] = sdata[o * 2] | (sdata[(o * 2) + 1] << 8); } else { memcpy(smp.data, sdata, smp.length); } } } else { delta = 0; if (flags & 8) { /* unsigned delta? mehhh, does anything even use this? */ if (flags & 4) { for (o = 0; o < smp.length; o++) { delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8)); ((short *)smp.data)[o] = delta ^ 0x8000; } } else { for (o = 0; o < smp.length; o++) { delta += (signed char)sdata[o]; ((signed char *)smp.data)[o] = delta ^ 0x80; } } } else { if (flags & 4) { for (o = 0; o < smp.length; o++) { delta += (signed short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8)); ((signed short *)smp.data)[o] = delta; } } else { for (o = 0; o < smp.length; o++) { delta += (signed char)sdata[o]; ((signed char *)smp.data)[o] = delta; } } } } if (s->data) free(s->data); *s = smp; } free(buffer); return 0; error_fd: free((void *)sdata); 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 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((char *)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; if (offset + psize > size) goto error_fb; 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) { if (*ptr == 40) ptr += 4; else ptr += 2; } } } 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 + 35; } 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 = (int)(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 (int)(((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; 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((char *)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 = (int)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) { int sep = 32 * dumb_it_default_panning_separation / 100; sigdata->channel_pan[n] = 32 - sep; sigdata->channel_pan[n + 1] = 32 + sep; sigdata->channel_pan[n + 2] = 32 + sep; sigdata->channel_pan[n + 3] = 32 - sep; } for (n = 0; n < n_components; n++) { int o; if (dumbfile_seek(f, component[n].offset, DFS_SEEK_SET)) goto error_fc; switch (component[n].type) { case PSM_COMPONENT_ORDERS: if (dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_fc; if (n_orders > sigdata->n_orders) if (dumbfile_skip(f, n_orders - sigdata->n_orders)) goto error_fc; if (dumbfile_igetw(f)) goto error_fc; break; case PSM_COMPONENT_PANPOS: if (dumbfile_getnc((char *)sigdata->channel_pan, sigdata->n_pchannels, f) < sigdata->n_pchannels) goto error_fc; 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)) goto error_fc; break; case PSM_COMPONENT_SAMPLE_HEADERS: if (it_old_psm_read_samples(&sigdata->sample, f, &sigdata->n_samples)) goto error_fc; 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((char *)sigdata->song_message, o, f) < o) goto error_fc; sigdata->song_message[o] = 0; } } break; } } if (_dumb_it_fix_invalid_orders(sigdata) < 0) goto error_fc; free(component); return sigdata; 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] = (const char *)(((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); } }