745 lines · 23.3 KB · C
RawDownload
/*  _______         ____    __         ___    ___ * \    _  \       \    /  \  /       \   \  /   /       '   '  ' *  |  | \  \       |  |    ||         |   \/   |         .      . *  |  |  |  |      |  |    ||         ||\  /|  | *  |  |  |  |      |  |    ||         || \/ |  |         '  '  ' *  |  |  |  |      |  |    ||         ||    |  |         .      . *  |  |_/  /        \  \__//          ||    |  | * /_______/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;                    }

Lines 1–500 of 745.

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