1468 lines · 46.2 KB · C
RawDownload
/*  _______         ____    __         ___    ___ * \    _  \       \    /  \  /       \   \  /   /       '   '  ' *  |  | \  \       |  |    ||         |   \/   |         .      . *  |  |  |  |      |  |    ||         ||\  /|  | *  |  |  |  |      |  |    ||         || \/ |  |         '  '  ' *  |  |  |  |      |  |    ||         ||    |  |         .      . *  |  |_/  /        \  \__//          ||    |  | * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque *                                                      /  \ *                                                     / .  \ * itread.c - Code to read an Impulse Tracker         / / \  \ *            module from an open file.              | <  /   \_ *                                                   |  \/ /\   / * Based on the loader from an IT player by Bob.      \_  /  > / * Adapted for DUMB by entheh.                          | \ / / *                                                      |  ' / *                                                       \__/ */ #include <stdlib.h>#include <string.h> //might not be necessary later; required for memset #include "dumb.h"#include "internal/it.h" #ifndef min#define min(a, b) (((a) < (b)) ? (a) : (b))#endif //#define INVESTIGATE_OLD_INSTRUMENTS typedef unsigned char byte;typedef unsigned short word;typedef unsigned long dword; typedef struct readblock_crap readblock_crap; struct readblock_crap {    unsigned char *sourcebuf;    unsigned char *sourcepos;    unsigned char *sourceend;    int rembits;}; static int readblock(DUMBFILE *f, readblock_crap *crap) {    long size;    int c;     size = dumbfile_igetw(f);    if (size < 0)        return (int)size;     crap->sourcebuf = malloc(size);    if (!crap->sourcebuf)        return -1;     c = (int)dumbfile_getnc((char *)crap->sourcebuf, size, f);    if (c < size) {        free(crap->sourcebuf);        crap->sourcebuf = NULL;        return -1;    }     crap->sourcepos = crap->sourcebuf;    crap->sourceend = crap->sourcebuf + size;    crap->rembits = 8;    return 0;} static void freeblock(readblock_crap *crap) {    free(crap->sourcebuf);    crap->sourcebuf = NULL;} static int readbits(int bitwidth, readblock_crap *crap) {    int val = 0;    int b = 0;     if (crap->sourcepos >= crap->sourceend)        return val;     while (bitwidth > crap->rembits) {        val |= *crap->sourcepos++ << b;        if (crap->sourcepos >= crap->sourceend)            return val;        b += crap->rembits;        bitwidth -= crap->rembits;        crap->rembits = 8;    }     val |= (*crap->sourcepos & ((1 << bitwidth) - 1)) << b;    *crap->sourcepos >>= bitwidth;    crap->rembits -= bitwidth;     return val;} /** WARNING - do we even need to pass `right`? *//** WARNING - why bother memsetting at all? The whole array is written... */// if we do memset, dumb_silence() would be neater...static int decompress8(DUMBFILE *f, signed char *data, int len, int it215,                       int stereo) {    int blocklen, blockpos;    byte bitwidth;    word val;    signed char d1, d2;    readblock_crap crap;     memset(&crap, 0, sizeof(crap));     for (blocklen = 0, blockpos = 0; blocklen < len;         blocklen++, blockpos += 1 + stereo)        data[blockpos] = 0;     while (len > 0) {        // Read a block of compressed data:        if (readblock(f, &crap))            return -1;        // Set up a few variables        blocklen =            (len < 0x8000) ? len : 0x8000; // Max block length is 0x8000 bytes        blockpos = 0;        bitwidth = 9;        d1 = d2 = 0;        // Start the decompression:        while (blockpos < blocklen) {            // Read a value:            val = (word)readbits(bitwidth, &crap);            // Check for bit width change:             if (bitwidth < 7) { // Method 1:                if (val == (1 << (bitwidth - 1))) {                    val = (word)readbits(3, &crap) + 1;                    bitwidth = (val < bitwidth) ? val : val + 1;                    continue;                }            } else if (bitwidth < 9) { // Method 2                byte border = (0xFF >> (9 - bitwidth)) - 4;                 if (val > border && val <= (border + 8)) {                    val -= border;                    bitwidth = (val < bitwidth) ? val : val + 1;                    continue;                }            } else if (bitwidth == 9) { // Method 3                if (val & 0x100) {                    bitwidth = (val + 1) & 0xFF;                    continue;                }            } else { // Illegal width, abort ?                freeblock(&crap);                return -1;            }             // Expand the value to signed byte:            {                signed char v; // The sample value:                if (bitwidth < 8) {                    byte shift = 8 - bitwidth;                    v = (val << shift);                    v >>= shift;                } else                    v = (signed char)val;                 // And integrate the sample value                //(It always has to end with integration doesn't it ? ;-)                d1 += v;                d2 += d1;            }             // Store !            /* Version 2.15 was an unofficial version with hacked compression             * code. Yay, better compression :D             */            *data++ = it215 ? d2 : d1;            data += stereo;            len--;            blockpos++;        }        freeblock(&crap);    }    return 0;} static int decompress16(DUMBFILE *f, short *data, int len, int it215,                        int stereo) {    int blocklen, blockpos;    byte bitwidth;    long val;    signed short d1, d2;    readblock_crap crap;     memset(&crap, 0, sizeof(crap));     for (blocklen = 0, blockpos = 0; blocklen < len;         blocklen++, blockpos += 1 + stereo)        data[blockpos] = 0;     while (len > 0) {        // Read a block of compressed data:        if (readblock(f, &crap))            return -1;        // Set up a few variables        blocklen =            (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes        blockpos = 0;        bitwidth = 17;        d1 = d2 = 0;        // Start the decompression:        while (blockpos < blocklen) {            val = readbits(bitwidth, &crap);            // Check for bit width change:             if (bitwidth < 7) { // Method 1:                if (val == (1 << (bitwidth - 1))) {                    val = readbits(4, &crap) + 1;                    bitwidth = (val < bitwidth) ? val : val + 1;                    continue;                }            } else if (bitwidth < 17) { // Method 2                word border = (0xFFFF >> (17 - bitwidth)) - 8;                 if (val > border && val <= (border + 16)) {                    val -= border;                    bitwidth = val < bitwidth ? val : val + 1;                    continue;                }            } else if (bitwidth == 17) { // Method 3                if (val & 0x10000) {                    bitwidth = (val + 1) & 0xFF;                    continue;                }            } else { // Illegal width, abort ?                freeblock(&crap);                return -1;            }             // Expand the value to signed byte:            {                short v; // The sample value:                if (bitwidth < 16) {                    byte shift = 16 - bitwidth;                    v = (short)(val << shift);                    v >>= shift;                } else                    v = (short)val;                 // And integrate the sample value                //(It always has to end with integration doesn't it ? ;-)                d1 += v;                d2 += d1;            }             // Store !            /* Version 2.15 was an unofficial version with hacked compression             * code. Yay, better compression :D             */            *data++ = it215 ? d2 : d1;            data += stereo;            len--;            blockpos++;        }        freeblock(&crap);    }    return 0;} static int it_read_envelope(IT_ENVELOPE *envelope, DUMBFILE *f) {    int n;     envelope->flags = dumbfile_getc(f);    envelope->n_nodes = dumbfile_getc(f);    if (envelope->n_nodes > 25) {        TRACE("IT error: wrong number of envelope nodes (%d)\n",              envelope->n_nodes);        envelope->n_nodes = 0;        return -1;    }    envelope->loop_start = dumbfile_getc(f);    envelope->loop_end = dumbfile_getc(f);    envelope->sus_loop_start = dumbfile_getc(f);    envelope->sus_loop_end = dumbfile_getc(f);    for (n = 0; n < envelope->n_nodes; n++) {        envelope->node_y[n] = dumbfile_getc(f);        envelope->node_t[n] = dumbfile_igetw(f);    }    dumbfile_skip(f, 75 - envelope->n_nodes * 3 + 1);     if (envelope->n_nodes <= 0)        envelope->flags &= ~IT_ENVELOPE_ON;    else {        if (envelope->loop_end >= envelope->n_nodes ||            envelope->loop_start > envelope->loop_end)            envelope->flags &= ~IT_ENVELOPE_LOOP_ON;        if (envelope->sus_loop_end >= envelope->n_nodes ||            envelope->sus_loop_start > envelope->sus_loop_end)            envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP;    }     return dumbfile_error(f);} static int it_read_old_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f) {    int n;     /*if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE)            return -1;*/    // XXX    dumbfile_skip(f, 4);     dumbfile_getnc((char *)instrument->filename, 13, f);    instrument->filename[13] = 0;     instrument->volume_envelope.flags = dumbfile_getc(f);    instrument->volume_envelope.loop_start = dumbfile_getc(f);    instrument->volume_envelope.loop_end = dumbfile_getc(f);    instrument->volume_envelope.sus_loop_start = dumbfile_getc(f);    instrument->volume_envelope.sus_loop_end = dumbfile_getc(f);     /* Skip two unused bytes. */    dumbfile_skip(f, 2);     /* In the old instrument format, fadeout ranges from 0 to 64, and is     * subtracted at intervals from a value starting at 512. In the new     * format, all these values are doubled. Therefore we double when loading     * from the old instrument format - that way we don't have to think about     * it later.     */    instrument->fadeout = dumbfile_igetw(f) << 1;    instrument->new_note_action = dumbfile_getc(f);    instrument->dup_check_type = dumbfile_getc(f);    instrument->dup_check_action = DCA_NOTE_CUT; // This might be wrong!    /** WARNING - what is the duplicate check action for old-style instruments?     */     /* Skip Tracker Version and Number of Samples. These are only used in     * separate instrument files. Also skip unused byte.     */    dumbfile_skip(f, 4);     dumbfile_getnc((char *)instrument->name, 26, f);    instrument->name[26] = 0;     /* Skip unused bytes following the Instrument Name. */    dumbfile_skip(f, 6);     instrument->pp_separation = 0;    instrument->pp_centre = 60;    instrument->global_volume = 128;    /** WARNING - should global_volume be 64 or something? */    instrument->default_pan = 32;    /** WARNING - should default_pan be 128, meaning don`t use? */    instrument->random_volume = 0;    instrument->random_pan = 0;     for (n = 0; n < 120; n++) {        instrument->map_note[n] = dumbfile_getc(f);        instrument->map_sample[n] = dumbfile_getc(f);    }     /* Skip "Volume envelope (200 bytes)". */    // - need to know better what this is for though.    dumbfile_skip(f, 200); #ifdef INVESTIGATE_OLD_INSTRUMENTS    fprintf(stderr, "Inst %02d Env:", n);#endif     for (n = 0; n < 25; n++) {        instrument->volume_envelope.node_t[n] = dumbfile_getc(f);        instrument->volume_envelope.node_y[n] = dumbfile_getc(f); #ifdef INVESTIGATE_OLD_INSTRUMENTS        fprintf(stderr, " %d,%d", instrument->volume_envelope.node_t[n],                instrument->volume_envelope.node_y[n]);#endif         // This loop is unfinished, as we can probably escape from it before        // the end if we want to. Hence the otherwise useless dumbfile_skip()        // call below.    }    dumbfile_skip(f, 50 - (n << 1));    instrument->volume_envelope.n_nodes = n; #ifdef INVESTIGATE_OLD_INSTRUMENTS    fprintf(stderr, "\n");#endif     if (dumbfile_error(f))        return -1;     {        IT_ENVELOPE *envelope = &instrument->volume_envelope;        if (envelope->n_nodes <= 0)            envelope->flags &= ~IT_ENVELOPE_ON;        else {            if (envelope->loop_end >= envelope->n_nodes ||                envelope->loop_start > envelope->loop_end)                envelope->flags &= ~IT_ENVELOPE_LOOP_ON;            if (envelope->sus_loop_end >= envelope->n_nodes ||                envelope->sus_loop_start > envelope->sus_loop_end)                envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP;        }    }     instrument->filter_cutoff = 127;    instrument->filter_resonance = 0;     instrument->pan_envelope.flags = 0;    instrument->pitch_envelope.flags = 0;     return 0;} static int it_read_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f,                              int maxlen) {    int n;    long len;     /*if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE)            return -1;*/    // XXX     if (maxlen)        len = dumbfile_pos(f);    else        len = 0;     dumbfile_skip(f, 4);     dumbfile_getnc((char *)instrument->filename, 13, f);    instrument->filename[13] = 0;     instrument->new_note_action = dumbfile_getc(f);    instrument->dup_check_type = dumbfile_getc(f);    instrument->dup_check_action = dumbfile_getc(f);    instrument->fadeout = dumbfile_igetw(f);    instrument->pp_separation = dumbfile_getc(f);    instrument->pp_centre = dumbfile_getc(f);    instrument->global_volume = dumbfile_getc(f);    instrument->default_pan = dumbfile_getc(f);    instrument->random_volume = dumbfile_getc(f);    instrument->random_pan = dumbfile_getc(f);     /* Skip Tracker Version and Number of Samples. These are only used in     * separate instrument files. Also skip unused byte.     */    dumbfile_skip(f, 4);     dumbfile_getnc((char *)instrument->name, 26, f);    instrument->name[26] = 0;     instrument->filter_cutoff = dumbfile_getc(f);    instrument->filter_resonance = dumbfile_getc(f);     /* Skip MIDI Channel, Program and Bank. */    // dumbfile_skip(f, 4);    /*instrument->output = dumbfile_getc(f);    if ( instrument->output > 16 ) {            instrument->output -= 128;    } else {            instrument->output = 0;    }    dumbfile_skip(f, 3);*/    dumbfile_skip(f, 4);     for (n = 0; n < 120; n++) {        instrument->map_note[n] = dumbfile_getc(f);        instrument->map_sample[n] = dumbfile_getc(f);    }     if (dumbfile_error(f))        return -1;     if (it_read_envelope(&instrument->volume_envelope, f))        return -1;    if (it_read_envelope(&instrument->pan_envelope, f))        return -1;    if (it_read_envelope(&instrument->pitch_envelope, f))        return -1;     if (maxlen) {        len = dumbfile_pos(f) - len;        if (maxlen - len < 124)            return 0;    }     if (dumbfile_mgetl(f) == IT_MPTX_SIGNATURE) {        for (n = 0; n < 120; n++) {            instrument->map_sample[n] += dumbfile_getc(f) << 8;        }         if (dumbfile_error(f))            return -1;    }     /*if ( dumbfile_mgetl(f) == IT_INSM_SIGNATURE ) {            long end = dumbfile_igetl(f);            end += dumbfile_pos(f);            while ( dumbfile_pos(f) < end ) {

Lines 1–500 of 1468.

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