Christopher SnowhillUpdated credits with my legal name.74414b99 years agoHistory
597 lines · 17.0 KB · C
RawDownload
/*  _______         ____    __         ___    ___ * \    _  \       \    /  \  /       \   \  /   /       '   '  ' *  |  | \  \       |  |    ||         |   \/   |         .      . *  |  |  |  |      |  |    ||         ||\  /|  | *  |  |  |  |      |  |    ||         || \/ |  |         '  '  ' *  |  |  |  |      |  |    ||         ||    |  |         .      . *  |  |_/  /        \  \__//          ||    |  | * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque *                                                      /  \ *                                                     / .  \ * readamf.c - Code to read a DSMI AMF 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 void it_amf_process_track(IT_ENTRY *entry_table, unsigned char *track,                                 int rows, int channels) {    int last_instrument = 0;    int tracksize = track[0] + (track[1] << 8) + (track[2] << 16);    track += 3;    while (tracksize--) {        unsigned int row = track[0];        unsigned int command = track[1];        unsigned int argument = track[2];        IT_ENTRY *entry = entry_table + row * channels;        if (row >= (unsigned int)rows)            break;        if (command < 0x7F) {            entry->mask |=                IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT | IT_ENTRY_VOLPAN;            entry->note = command;            if (!entry->instrument)                entry->instrument = last_instrument;            entry->volpan = argument;        } else if (command == 0x7F) {            signed char row_delta = (signed char)argument;            int row_source = (int)row + (int)row_delta;            if (row_source >= 0 && row_source < (int)rows) {                *entry = entry_table[row_source * channels];            }        } else if (command == 0x80) {            entry->mask |= IT_ENTRY_INSTRUMENT;            last_instrument = argument + 1;            entry->instrument = last_instrument;        } else if (command == 0x83) {            entry->mask |= IT_ENTRY_VOLPAN;            entry->volpan = argument;        } else {            unsigned int effect = command & 0x7F;            unsigned int effectvalue = argument;            switch (effect) {            case 0x01:                effect = IT_SET_SPEED;                break;             case 0x02:                effect = IT_VOLUME_SLIDE;            case 0x0A:                if (effect == 0x0A)                    effect = IT_VOLSLIDE_TONEPORTA;            case 0x0B:                if (effect == 0x0B)                    effect = IT_VOLSLIDE_VIBRATO;                if (effectvalue & 0x80)                    effectvalue = (-(signed char)effectvalue) & 0x0F;                else                    effectvalue = (effectvalue & 0x0F) << 4;                break;             case 0x04:                if (effectvalue & 0x80) {                    effect = IT_PORTAMENTO_UP;                    effectvalue = (-(signed char)effectvalue) & 0x7F;                } else {                    effect = IT_PORTAMENTO_DOWN;                }                break;             case 0x06:                effect = IT_TONE_PORTAMENTO;                break;             case 0x07:                effect = IT_TREMOR;                break;             case 0x08:                effect = IT_ARPEGGIO;                break;             case 0x09:                effect = IT_VIBRATO;                break;             case 0x0C:                effect = IT_BREAK_TO_ROW;                break;             case 0x0D:                effect = IT_JUMP_TO_ORDER;                break;             case 0x0F:                effect = IT_RETRIGGER_NOTE;                break;             case 0x10:                effect = IT_SET_SAMPLE_OFFSET;                break;             case 0x11:                if (effectvalue) {                    effect = IT_VOLUME_SLIDE;                    if (effectvalue & 0x80)                        effectvalue =                            0xF0 | ((-(signed char)effectvalue) & 0x0F);                    else                        effectvalue = 0x0F | ((effectvalue & 0x0F) << 4);                } else                    effect = 0;                break;             case 0x12:            case 0x16:                if (effectvalue) {                    int mask = (effect == 0x16) ? 0xE0 : 0xF0;                    effect = (effectvalue & 0x80) ? IT_PORTAMENTO_UP                                                  : IT_PORTAMENTO_DOWN;                    if (effectvalue & 0x80)                        effectvalue =                            mask | ((-(signed char)effectvalue) & 0x0F);                    else                        effectvalue = mask | (effectvalue & 0x0F);                } else                    effect = 0;                break;             case 0x13:                effect = IT_S;                effectvalue = EFFECT_VALUE(IT_S_NOTE_DELAY, effectvalue & 0x0F);                break;             case 0x14:                effect = IT_S;                effectvalue =                    EFFECT_VALUE(IT_S_DELAYED_NOTE_CUT, effectvalue & 0x0F);                break;             case 0x15:                effect = IT_SET_SONG_TEMPO;                break;             case 0x17:                effectvalue = (effectvalue + 64) & 0x7F;                if (entry->mask & IT_ENTRY_EFFECT) {                    if (!(entry->mask & IT_ENTRY_VOLPAN)) {                        entry->mask |= IT_ENTRY_VOLPAN;                        entry->volpan = (effectvalue / 2) + 128;                    }                    effect = 0;                } else {                    effect = IT_SET_PANNING;                }                break;             default:                effect = effectvalue = 0;            }            if (effect) {                entry->mask |= IT_ENTRY_EFFECT;                entry->effect = effect;                entry->effectvalue = effectvalue;            }        }        track += 3;    }} static int it_amf_process_pattern(IT_PATTERN *pattern, IT_ENTRY *entry_table,                                  int rows, int channels) {    int i, j;    int n_entries = rows;    IT_ENTRY *entry;     pattern->n_rows = rows;     for (i = 0, j = channels * rows; i < j; i++) {        if (entry_table[i].mask) {            n_entries++;        }    }     pattern->n_entries = n_entries;     pattern->entry = entry = malloc(n_entries * sizeof(IT_ENTRY));    if (!entry) {        return -1;    }     for (i = 0; i < rows; i++) {        for (j = 0; j < channels; j++) {            if (entry_table[i * channels + j].mask) {                *entry = entry_table[i * channels + j];                entry->channel = j;                entry++;            }        }        IT_SET_END_ROW(entry);        entry++;    }     return 0;} static int it_amf_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f,                                     int *offset, int ver) {    int exists;     exists = dumbfile_getc(f);     dumbfile_getnc((char *)sample->name, 32, f);    sample->name[32] = 0;     dumbfile_getnc((char *)sample->filename, 13, f);    sample->filename[13] = 0;     *offset = (int)dumbfile_igetl(f);    sample->length = dumbfile_igetl(f);    sample->C5_speed = dumbfile_igetw(f);    sample->default_volume = dumbfile_getc(f);    sample->global_volume = 64;    if (sample->default_volume > 64)        sample->default_volume = 64;     if (ver >= 11) {        sample->loop_start = dumbfile_igetl(f);        sample->loop_end = dumbfile_igetl(f);    } else {        sample->loop_start = dumbfile_igetw(f);        sample->loop_end = sample->length;    }     if (sample->length <= 0) {        sample->flags = 0;        return 0;    }     sample->flags = exists == 1 ? IT_SAMPLE_EXISTS : 0;     sample->default_pan = 0;    sample->finetune = 0;     if (sample->loop_end > sample->loop_start + 2 &&        sample->loop_end <= sample->length)        sample->flags |= IT_SAMPLE_LOOP;     sample->vibrato_speed = 0;    sample->vibrato_depth = 0;    sample->vibrato_rate = 0;    sample->vibrato_waveform = 0; // do we have to set _all_ these?    sample->max_resampling_quality = -1;     return dumbfile_error(f);} static int it_amf_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f) {    int i, read_length = 0;     sample->data = malloc(sample->length);     if (!sample->data)        return -1;     if (sample->length)        read_length = (int)dumbfile_getnc(sample->data, sample->length, f);     if (read_length < 0)        read_length = 0;     for (i = 0; i < read_length; i++) {        ((signed char *)sample->data)[i] ^= 0x80;    }     for (i = read_length; i < sample->length; i++) {        ((signed char *)sample->data)[i] = 0;    }     return 0; /* Sometimes the last sample is truncated :( */} static DUMB_IT_SIGDATA *it_amf_load_sigdata(DUMBFILE *f, int *version) {    DUMB_IT_SIGDATA *sigdata;    int i, j, ver, ntracks, realntracks, nchannels;     int maxsampleseekpos = 0;    int sampleseekpos[256];     unsigned short *orderstotracks;    unsigned short *trackmap;    unsigned int tracksize[256];     unsigned char **track;     static const char sig[] = "AMF";     char signature[3];     if (dumbfile_getnc(signature, 3, f) != 3 || memcmp(signature, sig, 3)) {        return NULL;    }     *version = ver = dumbfile_getc(f);    if (ver < 10 || ver > 14) {        return NULL;    }     sigdata = malloc(sizeof(*sigdata));    if (!sigdata) {        return NULL;    }     dumbfile_getnc((char *)sigdata->name, 32, f);    sigdata->name[32] = 0;    sigdata->n_samples = dumbfile_getc(f);    sigdata->n_orders = dumbfile_getc(f);    ntracks = dumbfile_igetw(f);    nchannels = dumbfile_getc(f);     if (dumbfile_error(f) || sigdata->n_samples < 1 ||        sigdata->n_samples > 255 || sigdata->n_orders < 1 ||        sigdata->n_orders > 255 || !ntracks || nchannels < 1 ||        nchannels > 32) {        free(sigdata);        return NULL;    }     sigdata->n_pchannels = nchannels;     memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);     if (ver >= 11) {        int nchannels = (ver >= 13) ? 32 : 16;        for (i = 0; i < nchannels; i++) {            signed char panpos = dumbfile_getc(f);            int pan = (panpos + 64) / 2;            if (pan < 0)                pan = 0;            else if (pan > 64)                pan = IT_SURROUND;            sigdata->channel_pan[i] = pan;        }    } else {        int sep = 32 * dumb_it_default_panning_separation / 100;        for (i = 0; i < 16; i++) {            sigdata->channel_pan[i] =                (dumbfile_getc(f) & 1) ? 32 - sep : 32 + sep;        }    }     sigdata->tempo = 125;    sigdata->speed = 6;    if (ver >= 13) {        i = dumbfile_getc(f);        if (i >= 32)            sigdata->tempo = i;        i = dumbfile_getc(f);        if (i <= 32)            sigdata->speed = i;    }     sigdata->order = malloc(sigdata->n_orders);    if (!sigdata->order) {        free(sigdata);        return NULL;    }     orderstotracks =        malloc(sigdata->n_orders * nchannels * sizeof(unsigned short));    if (!orderstotracks) {        free(sigdata->order);        free(sigdata);        return NULL;    }     for (i = 0; i < sigdata->n_orders; i++) {        sigdata->order[i] = i;        tracksize[i] = 64;        if (ver >= 14) {            tracksize[i] = dumbfile_igetw(f);        }        for (j = 0; j < nchannels; j++) {            orderstotracks[i * nchannels + j] = dumbfile_igetw(f);        }    }     if (dumbfile_error(f)) {        free(orderstotracks);        free(sigdata->order);        free(sigdata);        return NULL;    }     sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));    if (!sigdata->sample) {        free(orderstotracks);        free(sigdata->order);        free(sigdata);        return NULL;    }     sigdata->restart_position = 0;     sigdata->song_message = NULL;    sigdata->instrument = NULL;    sigdata->pattern = NULL;    sigdata->midi = NULL;    sigdata->checkpoint = NULL;     sigdata->n_instruments = 0;     for (i = 0; i < sigdata->n_samples; ++i)        sigdata->sample[i].data = NULL;     for (i = 0; i < sigdata->n_samples; ++i) {        int offset;        if (it_amf_read_sample_header(&sigdata->sample[i], f, &offset, ver)) {            goto error_ott;        }        sampleseekpos[i] = offset;        if (offset > maxsampleseekpos)            maxsampleseekpos = offset;    }     sigdata->n_patterns = sigdata->n_orders;     sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));    if (!sigdata->pattern) {        goto error_ott;    }    for (i = 0; i < sigdata->n_patterns; ++i)        sigdata->pattern[i].entry = NULL;     trackmap = malloc(ntracks * sizeof(unsigned short));    if (!trackmap) {        goto error_ott;    }     if (dumbfile_getnc((char *)trackmap, ntracks * sizeof(unsigned short), f) !=        (long)(ntracks * sizeof(unsigned short))) {        goto error_tm;    }     realntracks = 0;     for (i = 0; i < ntracks; i++) {        if (trackmap[i] > realntracks)            realntracks = trackmap[i];    }     track = calloc(realntracks, sizeof(unsigned char *));    if (!track) {        goto error_tm;    }     for (i = 0; i < realntracks; i++) {        int tracksize = dumbfile_igetw(f);        tracksize += dumbfile_getc(f) << 16;        track[i] = malloc(tracksize * 3 + 3);        if (!track[i]) {            goto error_all;        }        track[i][0] = tracksize & 255;        track[i][1] = (tracksize >> 8) & 255;        track[i][2] = (tracksize >> 16) & 255;        if (dumbfile_getnc((char *)track[i] + 3, tracksize * 3, f) !=            tracksize * 3) {            goto error_all;        }    }     for (i = 1; i <= maxsampleseekpos; i++) {        for (j = 0; j < sigdata->n_samples; j++) {            if (sampleseekpos[j] == i) {                if (it_amf_read_sample_data(&sigdata->sample[j], f)) {                    goto error_all;                }                break;            }        }

Lines 1–500 of 597.

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