1418 lines · 40.4 KB · C
RawDownload
/*  _______         ____    __         ___    ___ * \    _  \       \    /  \  /       \   \  /   /       '   '  ' *  |  | \  \       |  |    ||         |   \/   |         .      . *  |  |  |  |      |  |    ||         ||\  /|  | *  |  |  |  |      |  |    ||         || \/ |  |         '  '  ' *  |  |  |  |      |  |    ||         ||    |  |         .      . *  |  |_/  /        \  \__//          ||    |  | * /_______/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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t