/* _______ ____ __ ___ ___ * \ _ \ \ / \ / \ \ / / ' ' ' * | | \ \ | | || | \/ | . . * | | | | | | || ||\ /| | * | | | | | | || || \/ | | ' ' ' * | | | | | | || || | | . . * | |_/ / \ \__// || | | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque * / \ * / . \ * readpsm.c - Code to read a Protracker Studio / / \ \ * module from an open file. | < / \_ * | \/ /\ / * By Christopher Snowhill. \_ / > / * | \ / / * | ' / * \__/ */ #include <stdlib.h>#include <string.h> #include "dumb.h"#include "internal/it.h" #ifndef min#define min(a, b) (((a) < (b)) ? (a) : (b))#endif #ifdef _MSC_VER#define snprintf sprintf_s#endif #define PSMV_OLD 940730#define PSMV_NEW 940902 typedef struct _PSMCHUNK { int id; size_t len; unsigned char *data;} PSMCHUNK; typedef struct _PSMEVENT { int type; unsigned char data[8];} PSMEVENT; #define PSM_EVENT_END 0#define PSM_EVENT_PLAY_PATTERN 1#define PSM_EVENT_JUMP_TO_LINE 4#define PSM_EVENT_SET_SPEED 7#define PSM_EVENT_SET_BPM 8#define PSM_EVENT_SAMPLE_MAP_TABLE 12#define PSM_EVENT_CHANGE_PAN 13#define PSM_EVENT_CHANGE_VOL 14 static int it_psm_process_sample(IT_SAMPLE *sample, const unsigned char *data, size_t len, int id, int version) { int flags; int insno; size_t length; int loopstart; int loopend; int panpos; int defvol; int samplerate; if (len < 0x60) return -1; flags = data[0]; if (version == PSMV_OLD) { memcpy(sample->name, data + 0x0D, 34); sample->name[34] = 0; insno = data[0x34] | (data[0x35] << 8); length = data[0x36] | (data[0x37] << 8) | (data[0x38] << 16) | (data[0x39] << 24); loopstart = data[0x3A] | (data[0x3B] << 8) | (data[0x3C] << 16) | (data[0x3D] << 24); loopend = data[0x3E] | (data[0x3F] << 8) | (data[0x40] << 16) | (data[0x41] << 24); panpos = data[0x43]; defvol = data[0x44]; samplerate = data[0x49] | (data[0x4A] << 8) | (data[0x4B] << 16) | (data[0x4C] << 24); } else /*if (version == PSMV_NEW)*/ { memcpy(sample->name, data + 0x11, 34); sample->name[34] = 0; insno = data[0x38] | (data[0x39] << 8); length = data[0x3A] | (data[0x3B] << 8) | (data[0x3C] << 16) | (data[0x3D] << 24); loopstart = data[0x3E] | (data[0x3F] << 8) | (data[0x40] << 16) | (data[0x41] << 24); loopend = data[0x42] | (data[0x43] << 8) | (data[0x44] << 16) | (data[0x45] << 24); panpos = data[0x48]; defvol = data[0x49]; samplerate = data[0x4E] | (data[0x4F] << 8) | (data[0x50] << 16) | (data[0x51] << 24); } if (insno != id) return -1; if (length <= 0) { sample->flags &= ~IT_SAMPLE_EXISTS; return 0; } if ((length > len - 0x60) || ((flags & 0x7F) != 0)) return -1; sample->flags = IT_SAMPLE_EXISTS; sample->length = length; sample->loop_start = loopstart; sample->loop_end = loopend; sample->C5_speed = samplerate; sample->default_volume = defvol >> 1; sample->default_pan = 0; sample->filename[0] = 0; sample->global_volume = 64; 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; if (flags & 0x80) { if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) && ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end)) { sample->length = sample->loop_end; sample->flags |= IT_SAMPLE_LOOP; } } sample->data = malloc(sample->length); if (!sample->data) return -1; flags = 0; data += 0x60; for (insno = 0; insno < sample->length; insno++) { flags += (signed char)(*data++); ((signed char *)sample->data)[insno] = flags; } return 0;} static int it_psm_process_pattern(IT_PATTERN *pattern, const unsigned char *data, size_t len, int speed, int bpm, const unsigned char *pan, const int *vol, int version) { size_t length, pos, rowlen; int nrows, row; unsigned flags, chan; IT_ENTRY *entry; length = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); if (len > length) len = length; if (version == PSMV_OLD) { if (len < 10) return -1; data += 8; len -= 8; } else /*if (version == PSMV_NEW)*/ { if (len < 14) return -1; data += 12; len -= 12; } nrows = data[0] | (data[1] << 8); if (!nrows) { pattern->n_rows = 0; pattern->n_entries = 0; pattern->entry = NULL; return 0; } pattern->n_rows = nrows; data += 2; len -= 2; pattern->n_entries = 0; row = 0; pos = 2; rowlen = data[0] | (data[1] << 8); while ((row < nrows) && (pos < len)) { if (pos >= rowlen) { row++; rowlen += data[pos] | (data[pos + 1] << 8); pos += 2; continue; } flags = data[pos++]; chan = data[pos++]; if (chan > 63) return -1; if (flags & 0xF0) { pattern->n_entries++; if (flags & 0x80) pos++; if (flags & 0x40) pos++; if (flags & 0x20) pos++; if (flags & 0x10) { switch (data[pos]) { case 0x29: pos++; case 0x33: pos++; default: pos += 2; } } } } if (!pattern->n_entries) return 0; pattern->n_entries += nrows; if (speed) pattern->n_entries++; if (bpm >= 0x20) pattern->n_entries++; for (pos = 0; pos < 32; pos++) { if (!(pan[pos * 2 + 1] & 0xF9)) pattern->n_entries++; if (vol[pos] != -1) pattern->n_entries++; } pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); if (!pattern->entry) return -1; entry = pattern->entry; if (speed) { entry->channel = 0; entry->mask = IT_ENTRY_EFFECT; entry->effect = IT_SET_SPEED; entry->effectvalue = speed; entry++; } if (bpm >= 0x20) { entry->channel = 0; entry->mask = IT_ENTRY_EFFECT; entry->effect = IT_SET_SONG_TEMPO; entry->effectvalue = bpm; entry++; } for (pos = 0; pos < 32; pos++) { if (!(pan[pos * 2 + 1] & 0xF9)) { entry->channel = pos; entry->mask = IT_ENTRY_EFFECT; switch (pan[pos * 2 + 1]) { case 0: entry->effect = IT_SET_PANNING; entry->effectvalue = pan[pos * 2] ^ 128; break; case 2: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_SET_SURROUND_SOUND, 1); break; case 4: entry->effect = IT_SET_PANNING; entry->effectvalue = 128; break; } entry++; } if (vol[pos] != -1) { entry->channel = pos; entry->mask = IT_ENTRY_EFFECT; entry->effect = IT_SET_CHANNEL_VOLUME; entry->effectvalue = (vol[pos] + 2) >> 2; entry++; } } row = 0; pos = 2; rowlen = data[0] | (data[1] << 8); while ((row < nrows) && (pos < len)) { if (pos >= rowlen) { IT_SET_END_ROW(entry); entry++; row++; rowlen += data[pos] | (data[pos + 1] << 8); pos += 2; continue; } flags = data[pos++]; entry->channel = data[pos++]; entry->mask = 0; if (flags & 0xF0) { if (flags & 0x80) { entry->mask |= IT_ENTRY_NOTE; if (version == PSMV_OLD) { if ((data[pos] < 0x80)) entry->note = (data[pos] >> 4) * 12 + (data[pos] & 0x0f) + 12; else entry->mask &= ~IT_ENTRY_NOTE; } else /*if (version == PSMV_NEW)*/ { if ((data[pos]) && (data[pos] < 84)) entry->note = data[pos] + 35; else entry->mask &= ~IT_ENTRY_NOTE; } pos++; } if (flags & 0x40) { entry->mask |= IT_ENTRY_INSTRUMENT; entry->instrument = data[pos++] + 1; } if (flags & 0x20) { entry->mask |= IT_ENTRY_VOLPAN; entry->volpan = (data[pos++] + 1) >> 1; } if (flags & 0x10) { entry->mask |= IT_ENTRY_EFFECT; length = data[pos + 1]; switch (data[pos]) { case 1: entry->effect = IT_VOLUME_SLIDE; if (version == PSMV_OLD) entry->effectvalue = ((length & 0x1e) << 3) | 0xF; else /*if (version == PSMV_NEW)*/ entry->effectvalue = (length << 4) | 0xF; break; case 2: entry->effect = IT_VOLUME_SLIDE; if (version == PSMV_OLD) entry->effectvalue = (length << 3) & 0xF0; else /*if (version == PSMV_NEW)*/ entry->effectvalue = (length << 4) & 0xF0; break; case 3: entry->effect = IT_VOLUME_SLIDE; if (version == PSMV_OLD) entry->effectvalue = (length >> 1) | 0xF0; else /*if (version == PSMV_NEW)*/ entry->effectvalue = length | 0xF0; break; case 4: entry->effect = IT_VOLUME_SLIDE; if (version == PSMV_OLD) entry->effectvalue = (length >> 1) & 0xF; else /*if (version == PSMV_NEW)*/ entry->effectvalue = length & 0xF; break; case 12: entry->effect = IT_PORTAMENTO_UP; if (version == PSMV_OLD) { if (length < 4) entry->effectvalue = length | 0xF0; else entry->effectvalue = length >> 2; } else /*if (version == PSMV_NEW)*/ { entry->effectvalue = length; } break; case 14: entry->effect = IT_PORTAMENTO_DOWN; if (version == PSMV_OLD) { if (length < 4) entry->effectvalue = length | 0xF0; else entry->effectvalue = length >> 2; } else /*if (version == PSMV_NEW)*/ { entry->effectvalue = length; } break; case 15: entry->effect = IT_TONE_PORTAMENTO; if (version == PSMV_OLD) entry->effectvalue = length >> 2; else /*if (version == PSMV_NEW)*/ entry->effectvalue = length; break; case 0x15: entry->effect = IT_VIBRATO; entry->effectvalue = length; break; case 0x18: entry->effect = IT_VOLSLIDE_VIBRATO; entry->effectvalue = length; break; case 0x29: entry->effect = IT_SET_SAMPLE_OFFSET; entry->effectvalue = data[pos + 2]; pos += 2; break; case 0x2A: entry->effect = IT_RETRIGGER_NOTE; entry->effectvalue = length; break; case 0x33:#if 0 entry->effect = IT_POSITION_JUMP; entry->effectvalue = data[pos+2];#else entry->mask &= ~IT_ENTRY_EFFECT;#endif pos++; break; case 0x34: entry->effect = IT_BREAK_TO_ROW; entry->effectvalue = length; break; case 0x3D: entry->effect = IT_SET_SPEED; entry->effectvalue = length; break; case 0x3E: if (length >= 0x20) { entry->effect = IT_SET_SONG_TEMPO; entry->effectvalue = length; } else { entry->mask &= ~IT_ENTRY_EFFECT; } break; case 0x47: entry->effect = IT_ARPEGGIO; entry->effectvalue = length; break; default: return -1; } pos += 2; } if (entry->mask) entry++; } } while (row < nrows) { IT_SET_END_ROW(entry); entry++; row++; } pattern->n_entries = (int)(entry - pattern->entry); if (!pattern->n_entries) return -1; return 0;} static void free_chunks(PSMCHUNK *chunk, int count) { int n; for (n = 0; n < count; n++) { if (chunk[n].data) free(chunk[n].data);Lines 1–500 of 1418. Load more
/* _______ ____ __ ___ ___ * \ _ \ \ / \ / \ \ / / ' ' ' * | | \ \ | | || | \/ | . . * | | | | | | || ||\ /| | * | | | | | | || || \/ | | ' ' ' * | | | | | | || || | | . . * | |_/ / \ \__// || | | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque * / \ * / . \ * readpsm.c - Code to read a Protracker Studio / / \ \ * module from an open file. | < / \_ * | \/ /\ / * By Christopher Snowhill. \_ / > / * | \ / / * | ' / * \__/ */ #include <stdlib.h> #include <string.h> #include "dumb.h" #include "internal/it.h" #ifndef min #define min(a, b) (((a) < (b)) ? (a) : (b)) #endif #ifdef _MSC_VER #define snprintf sprintf_s #endif #define PSMV_OLD 940730 #define PSMV_NEW 940902 typedef struct _PSMCHUNK { int id; size_t len; unsigned char *data; } PSMCHUNK; typedef struct _PSMEVENT { int type; unsigned char data[8]; } PSMEVENT; #define PSM_EVENT_END 0 #define PSM_EVENT_PLAY_PATTERN 1 #define PSM_EVENT_JUMP_TO_LINE 4 #define PSM_EVENT_SET_SPEED 7 #define PSM_EVENT_SET_BPM 8 #define PSM_EVENT_SAMPLE_MAP_TABLE 12 #define PSM_EVENT_CHANGE_PAN 13 #define PSM_EVENT_CHANGE_VOL 14 static int it_psm_process_sample(IT_SAMPLE *sample, const unsigned char *data, size_t len, int id, int version) { int flags; int insno; size_t length; int loopstart; int loopend; int panpos; int defvol; int samplerate; if (len < 0x60) return -1; flags = data[0]; if (version == PSMV_OLD) { memcpy(sample->name, data + 0x0D, 34); sample->name[34] = 0; insno = data[0x34] | (data[0x35] << 8); length = data[0x36] | (data[0x37] << 8) | (data[0x38] << 16) | (data[0x39] << 24); loopstart = data[0x3A] | (data[0x3B] << 8) | (data[0x3C] << 16) | (data[0x3D] << 24); loopend = data[0x3E] | (data[0x3F] << 8) | (data[0x40] << 16) | (data[0x41] << 24); panpos = data[0x43]; defvol = data[0x44]; samplerate = data[0x49] | (data[0x4A] << 8) | (data[0x4B] << 16) | (data[0x4C] << 24); } else /*if (version == PSMV_NEW)*/ { memcpy(sample->name, data + 0x11, 34); sample->name[34] = 0; insno = data[0x38] | (data[0x39] << 8); length = data[0x3A] | (data[0x3B] << 8) | (data[0x3C] << 16) | (data[0x3D] << 24); loopstart = data[0x3E] | (data[0x3F] << 8) | (data[0x40] << 16) | (data[0x41] << 24); loopend = data[0x42] | (data[0x43] << 8) | (data[0x44] << 16) | (data[0x45] << 24); panpos = data[0x48]; defvol = data[0x49]; samplerate = data[0x4E] | (data[0x4F] << 8) | (data[0x50] << 16) | (data[0x51] << 24); } if (insno != id) return -1; if (length <= 0) { sample->flags &= ~IT_SAMPLE_EXISTS; return 0; } if ((length > len - 0x60) || ((flags & 0x7F) != 0)) return -1; sample->flags = IT_SAMPLE_EXISTS; sample->length = length; sample->loop_start = loopstart; sample->loop_end = loopend; sample->C5_speed = samplerate; sample->default_volume = defvol >> 1; sample->default_pan = 0; sample->filename[0] = 0; sample->global_volume = 64; 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; if (flags & 0x80) { if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) && ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end)) { sample->length = sample->loop_end; sample->flags |= IT_SAMPLE_LOOP; } } sample->data = malloc(sample->length); if (!sample->data) return -1; flags = 0; data += 0x60; for (insno = 0; insno < sample->length; insno++) { flags += (signed char)(*data++); ((signed char *)sample->data)[insno] = flags; } return 0; } static int it_psm_process_pattern(IT_PATTERN *pattern, const unsigned char *data, size_t len, int speed, int bpm, const unsigned char *pan, const int *vol, int version) { size_t length, pos, rowlen; int nrows, row; unsigned flags, chan; IT_ENTRY *entry; length = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); if (len > length) len = length; if (version == PSMV_OLD) { if (len < 10) return -1; data += 8; len -= 8; } else /*if (version == PSMV_NEW)*/ { if (len < 14) return -1; data += 12; len -= 12; } nrows = data[0] | (data[1] << 8); if (!nrows) { pattern->n_rows = 0; pattern->n_entries = 0; pattern->entry = NULL; return 0; } pattern->n_rows = nrows; data += 2; len -= 2; pattern->n_entries = 0; row = 0; pos = 2; rowlen = data[0] | (data[1] << 8); while ((row < nrows) && (pos < len)) { if (pos >= rowlen) { row++; rowlen += data[pos] | (data[pos + 1] << 8); pos += 2; continue; } flags = data[pos++]; chan = data[pos++]; if (chan > 63) return -1; if (flags & 0xF0) { pattern->n_entries++; if (flags & 0x80) pos++; if (flags & 0x40) pos++; if (flags & 0x20) pos++; if (flags & 0x10) { switch (data[pos]) { case 0x29: pos++; case 0x33: pos++; default: pos += 2; } } } } if (!pattern->n_entries) return 0; pattern->n_entries += nrows; if (speed) pattern->n_entries++; if (bpm >= 0x20) pattern->n_entries++; for (pos = 0; pos < 32; pos++) { if (!(pan[pos * 2 + 1] & 0xF9)) pattern->n_entries++; if (vol[pos] != -1) pattern->n_entries++; } pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); if (!pattern->entry) return -1; entry = pattern->entry; if (speed) { entry->channel = 0; entry->mask = IT_ENTRY_EFFECT; entry->effect = IT_SET_SPEED; entry->effectvalue = speed; entry++; } if (bpm >= 0x20) { entry->channel = 0; entry->mask = IT_ENTRY_EFFECT; entry->effect = IT_SET_SONG_TEMPO; entry->effectvalue = bpm; entry++; } for (pos = 0; pos < 32; pos++) { if (!(pan[pos * 2 + 1] & 0xF9)) { entry->channel = pos; entry->mask = IT_ENTRY_EFFECT; switch (pan[pos * 2 + 1]) { case 0: entry->effect = IT_SET_PANNING; entry->effectvalue = pan[pos * 2] ^ 128; break; case 2: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_SET_SURROUND_SOUND, 1); break; case 4: entry->effect = IT_SET_PANNING; entry->effectvalue = 128; break; } entry++; } if (vol[pos] != -1) { entry->channel = pos; entry->mask = IT_ENTRY_EFFECT; entry->effect = IT_SET_CHANNEL_VOLUME; entry->effectvalue = (vol[pos] + 2) >> 2; entry++; } } row = 0; pos = 2; rowlen = data[0] | (data[1] << 8); while ((row < nrows) && (pos < len)) { if (pos >= rowlen) { IT_SET_END_ROW(entry); entry++; row++; rowlen += data[pos] | (data[pos + 1] << 8); pos += 2; continue; } flags = data[pos++]; entry->channel = data[pos++]; entry->mask = 0; if (flags & 0xF0) { if (flags & 0x80) { entry->mask |= IT_ENTRY_NOTE; if (version == PSMV_OLD) { if ((data[pos] < 0x80)) entry->note = (data[pos] >> 4) * 12 + (data[pos] & 0x0f) + 12; else entry->mask &= ~IT_ENTRY_NOTE; } else /*if (version == PSMV_NEW)*/ { if ((data[pos]) && (data[pos] < 84)) entry->note = data[pos] + 35; else entry->mask &= ~IT_ENTRY_NOTE; } pos++; } if (flags & 0x40) { entry->mask |= IT_ENTRY_INSTRUMENT; entry->instrument = data[pos++] + 1; } if (flags & 0x20) { entry->mask |= IT_ENTRY_VOLPAN; entry->volpan = (data[pos++] + 1) >> 1; } if (flags & 0x10) { entry->mask |= IT_ENTRY_EFFECT; length = data[pos + 1]; switch (data[pos]) { case 1: entry->effect = IT_VOLUME_SLIDE; if (version == PSMV_OLD) entry->effectvalue = ((length & 0x1e) << 3) | 0xF; else /*if (version == PSMV_NEW)*/ entry->effectvalue = (length << 4) | 0xF; break; case 2: entry->effect = IT_VOLUME_SLIDE; if (version == PSMV_OLD) entry->effectvalue = (length << 3) & 0xF0; else /*if (version == PSMV_NEW)*/ entry->effectvalue = (length << 4) & 0xF0; break; case 3: entry->effect = IT_VOLUME_SLIDE; if (version == PSMV_OLD) entry->effectvalue = (length >> 1) | 0xF0; else /*if (version == PSMV_NEW)*/ entry->effectvalue = length | 0xF0; break; case 4: entry->effect = IT_VOLUME_SLIDE; if (version == PSMV_OLD) entry->effectvalue = (length >> 1) & 0xF; else /*if (version == PSMV_NEW)*/ entry->effectvalue = length & 0xF; break; case 12: entry->effect = IT_PORTAMENTO_UP; if (version == PSMV_OLD) { if (length < 4) entry->effectvalue = length | 0xF0; else entry->effectvalue = length >> 2; } else /*if (version == PSMV_NEW)*/ { entry->effectvalue = length; } break; case 14: entry->effect = IT_PORTAMENTO_DOWN; if (version == PSMV_OLD) { if (length < 4) entry->effectvalue = length | 0xF0; else entry->effectvalue = length >> 2; } else /*if (version == PSMV_NEW)*/ { entry->effectvalue = length; } break; case 15: entry->effect = IT_TONE_PORTAMENTO; if (version == PSMV_OLD) entry->effectvalue = length >> 2; else /*if (version == PSMV_NEW)*/ entry->effectvalue = length; break; case 0x15: entry->effect = IT_VIBRATO; entry->effectvalue = length; break; case 0x18: entry->effect = IT_VOLSLIDE_VIBRATO; entry->effectvalue = length; break; case 0x29: entry->effect = IT_SET_SAMPLE_OFFSET; entry->effectvalue = data[pos + 2]; pos += 2; break; case 0x2A: entry->effect = IT_RETRIGGER_NOTE; entry->effectvalue = length; break; case 0x33: #if 0 entry->effect = IT_POSITION_JUMP; entry->effectvalue = data[pos+2]; #else entry->mask &= ~IT_ENTRY_EFFECT; #endif pos++; break; case 0x34: entry->effect = IT_BREAK_TO_ROW; entry->effectvalue = length; break; case 0x3D: entry->effect = IT_SET_SPEED; entry->effectvalue = length; break; case 0x3E: if (length >= 0x20) { entry->effect = IT_SET_SONG_TEMPO; entry->effectvalue = length; } else { entry->mask &= ~IT_ENTRY_EFFECT; } break; case 0x47: entry->effect = IT_ARPEGGIO; entry->effectvalue = length; break; default: return -1; } pos += 2; } if (entry->mask) entry++; } } while (row < nrows) { IT_SET_END_ROW(entry); entry++; row++; } pattern->n_entries = (int)(entry - pattern->entry); if (!pattern->n_entries) return -1; return 0; } static void free_chunks(PSMCHUNK *chunk, int count) { int n; for (n = 0; n < count; n++) { if (chunk[n].data) free(chunk[n].data);