cog/Frameworks/Dumb/dumb/src/it/itread.c

1414 lines
38 KiB
C

/* _______ ____ __ ___ ___
* \ _ \ \ / \ / \ \ / / ' ' '
* | | \ \ | | || | \/ | . .
* | | | | | | || ||\ /| |
* | | | | | | || || \/ | | ' ' '
* | | | | | | || || | | . .
* | |_/ / \ \__// || | |
* /_______/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);
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);
if (envelope->n_nodes > 25)
envelope->n_nodes = 25;
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 ) {
int chunkid = dumbfile_igetl(f);
switch ( chunkid ) {
case DUMB_ID('P','L','U','G'):
instrument->output = dumbfile_getc(f);
break;
default:
chunkid = chunkid / 0x100 + dumbfile_getc(f) * 0x1000000;
break;
}
}
if (dumbfile_error(f))
return -1;
}*/
return 0;
}
static int it_read_sample_header(IT_SAMPLE *sample, unsigned char *convert, long *offset, DUMBFILE *f)
{
/* XXX
if (dumbfile_mgetl(f) != IT_SAMPLE_SIGNATURE)
return -1;*/
int hax = 0;
long s = dumbfile_mgetl(f);
if (s != IT_SAMPLE_SIGNATURE) {
if ( s == ( IT_SAMPLE_SIGNATURE >> 16 ) ) {
s <<= 16;
s |= dumbfile_mgetw(f);
if ( s != IT_SAMPLE_SIGNATURE )
return -1;
hax = 1;
}
}
dumbfile_getnc((char *)sample->filename, 13, f);
sample->filename[13] = 0;
sample->global_volume = dumbfile_getc(f);
sample->flags = dumbfile_getc(f);
sample->default_volume = dumbfile_getc(f);
dumbfile_getnc((char *)sample->name, 26, f);
sample->name[26] = 0;
*convert = dumbfile_getc(f);
sample->default_pan = dumbfile_getc(f);
sample->length = dumbfile_igetl(f);
sample->loop_start = dumbfile_igetl(f);
sample->loop_end = dumbfile_igetl(f);
sample->C5_speed = dumbfile_igetl(f);
sample->sus_loop_start = dumbfile_igetl(f);
sample->sus_loop_end = dumbfile_igetl(f);
#ifdef STEREO_SAMPLES_COUNT_AS_TWO
if (sample->flags & IT_SAMPLE_STEREO) {
sample->length >>= 1;
sample->loop_start >>= 1;
sample->loop_end >>= 1;
sample->C5_speed >>= 1;
sample->sus_loop_start >>= 1;
sample->sus_loop_end >>= 1;
}
#endif
if (sample->flags & IT_SAMPLE_EXISTS) {
if (sample->length <= 0)
sample->flags &= ~IT_SAMPLE_EXISTS;
else {
if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
sample->flags &= ~IT_SAMPLE_LOOP;
else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
sample->flags &= ~IT_SAMPLE_LOOP;
if ((unsigned int)sample->sus_loop_end > (unsigned int)sample->length)
sample->flags &= ~IT_SAMPLE_SUS_LOOP;
else if ((unsigned int)sample->sus_loop_start >= (unsigned int)sample->sus_loop_end)
sample->flags &= ~IT_SAMPLE_SUS_LOOP;
/* We may be able to truncate the sample to save memory. */
if (sample->flags & IT_SAMPLE_LOOP &&
*convert != 0xFF) { /* not truncating compressed samples, for now... */
if ((sample->flags & IT_SAMPLE_SUS_LOOP) && sample->sus_loop_end >= sample->loop_end)
sample->length = sample->sus_loop_end;
else
sample->length = sample->loop_end;
}
}
}
*offset = dumbfile_igetl(f);
sample->vibrato_speed = dumbfile_getc(f);
sample->vibrato_depth = dumbfile_getc(f);
if ( ! hax ) {
sample->vibrato_rate = dumbfile_getc(f);
sample->vibrato_waveform = dumbfile_getc(f);
} else {
sample->vibrato_rate = 0;
sample->vibrato_waveform = 0;
}
sample->finetune = 0;
sample->max_resampling_quality = -1;
return dumbfile_error(f);
}
long _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f)
{
long n, len, delta;
signed char * ptr, * end;
signed char compression_table[16];
if (dumbfile_getnc((char *)compression_table, 16, f) != 16)
return -1;
ptr = (signed char *) sample->data;
delta = 0;
end = ptr + sample->length;
len = (sample->length + 1) / 2;
for (n = 0; n < len; n++) {
int b = dumbfile_getc(f);
if (b < 0) return -1;
delta += compression_table[b & 0x0F];
*ptr++ = delta;
if (ptr >= end) break;
delta += compression_table[b >> 4];
*ptr++ = delta;
}
return 0;
}
static long it_read_sample_data(IT_SAMPLE *sample, unsigned char convert, DUMBFILE *f)
{
long n;
long datasize = sample->length;
if (sample->flags & IT_SAMPLE_STEREO) datasize <<= 1;
sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
if (!sample->data)
return -1;
if (!(sample->flags & IT_SAMPLE_16BIT) && (convert == 0xFF)) {
if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
return -1;
} else if (sample->flags & 8) {
/* If the sample is packed, then we must unpack it. */
/* Behavior as defined by greasemonkey's munch.py and observed by XMPlay and OpenMPT */
if (sample->flags & IT_SAMPLE_STEREO) {
if (sample->flags & IT_SAMPLE_16BIT) {
decompress16(f, (short *) sample->data, (int)(datasize >> 1), convert & 4, 1);
decompress16(f, (short *) sample->data + 1, (int)(datasize >> 1), convert & 4, 1);
} else {
decompress8(f, (signed char *) sample->data, (int)(datasize >> 1), convert & 4, 1);
decompress8(f, (signed char *) sample->data + 1, (int)(datasize >> 1), convert & 4, 1);
}
} else {
if (sample->flags & IT_SAMPLE_16BIT)
decompress16(f, (short *) sample->data, (int)datasize, convert & 4, 0);
else
decompress8(f, (signed char *) sample->data, (int)datasize, convert & 4, 0);
}
} else if (sample->flags & IT_SAMPLE_16BIT) {
if (sample->flags & IT_SAMPLE_STEREO) {
if (convert & 2) {
for (n = 0; n < datasize; n += 2)
((short *)sample->data)[n] = dumbfile_mgetw(f);
for (n = 1; n < datasize; n += 2)
((short *)sample->data)[n] = dumbfile_mgetw(f);
} else {
for (n = 0; n < datasize; n += 2)
((short *)sample->data)[n] = dumbfile_igetw(f);
for (n = 1; n < datasize; n += 2)
((short *)sample->data)[n] = dumbfile_igetw(f);
}
} else {
if (convert & 2)
for (n = 0; n < datasize; n++)
((short *)sample->data)[n] = dumbfile_mgetw(f);
else
for (n = 0; n < datasize; n++)
((short *)sample->data)[n] = dumbfile_igetw(f);
}
} else {
if (sample->flags & IT_SAMPLE_STEREO) {
for (n = 0; n < datasize; n += 2)
((signed char *)sample->data)[n] = dumbfile_getc(f);
for (n = 1; n < datasize; n += 2)
((signed char *)sample->data)[n] = dumbfile_getc(f);
} else
for (n = 0; n < datasize; n++)
((signed char *)sample->data)[n] = dumbfile_getc(f);
}
if (dumbfile_error(f))
return -1;
if (!(convert & 1)) {
/* Convert to signed. */
if (sample->flags & IT_SAMPLE_16BIT)
for (n = 0; n < datasize; n++)
((short *)sample->data)[n] ^= 0x8000;
else
for (n = 0; n < datasize; n++)
((signed char *)sample->data)[n] ^= 0x80;
}
/* NOT SUPPORTED:
*
* convert & 4 - Samples stored as delta values
* convert & 16 - Samples stored as TX-Wave 12-bit values
* convert & 32 - Left/Right/All Stereo prompt
*/
return 0;
}
//#define DETECT_DUPLICATE_CHANNELS
#ifdef DETECT_DUPLICATE_CHANNELS
#include <stdio.h>
#endif
static int it_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer)
{
unsigned char cmask[DUMB_IT_N_CHANNELS];
unsigned char cnote[DUMB_IT_N_CHANNELS];
unsigned char cinstrument[DUMB_IT_N_CHANNELS];
unsigned char cvolpan[DUMB_IT_N_CHANNELS];
unsigned char ceffect[DUMB_IT_N_CHANNELS];
unsigned char ceffectvalue[DUMB_IT_N_CHANNELS];
#ifdef DETECT_DUPLICATE_CHANNELS
IT_ENTRY *dupentry[DUMB_IT_N_CHANNELS];
#endif
int n_entries = 0;
int buflen;
int bufpos = 0;
IT_ENTRY *entry;
unsigned char channel;
unsigned char mask;
memset(cmask, 0, sizeof(cmask));
memset(cnote, 0, sizeof(cnote));
memset(cinstrument, 0, sizeof(cinstrument));
memset(cvolpan, 0, sizeof(cvolpan));
memset(ceffect, 0, sizeof(ceffect));
memset(ceffectvalue, 0, sizeof(ceffectvalue));
#ifdef DETECT_DUPLICATE_CHANNELS
{
int i;
for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dupentry[i] = NULL;
}
#endif
buflen = dumbfile_igetw(f);
pattern->n_rows = dumbfile_igetw(f);
/* Skip four unused bytes. */
dumbfile_skip(f, 4);
if (dumbfile_error(f))
return -1;
/* Read in the pattern data. */
dumbfile_getnc((char *)buffer, buflen, f);
if (dumbfile_error(f))
return -1;
/* Scan the pattern data, and work out how many entries we need room for. */
while (bufpos < buflen) {
unsigned char b = buffer[bufpos++];
if (b == 0) {
/* End of row */
n_entries++;
continue;
}
channel = (b - 1) & 63;
if (b & 128)
cmask[channel] = mask = buffer[bufpos++];
else
mask = cmask[channel];
{
static const unsigned char used[16] = {0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5};
n_entries += (mask != 0);
bufpos += used[mask & 15];
}
}
pattern->n_entries = n_entries;
pattern->entry = malloc(n_entries * sizeof(*pattern->entry));
if (!pattern->entry)
return -1;
bufpos = 0;
memset(cmask, 0, sizeof(cmask));
entry = pattern->entry;
while (bufpos < buflen) {
unsigned char b = buffer[bufpos++];
if (b == 0) {
/* End of row */
IT_SET_END_ROW(entry);
entry++;
#ifdef DETECT_DUPLICATE_CHANNELS
{
int i;
for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dupentry[i] = NULL;
}
#endif
continue;
}
channel = (b - 1) & 63;
if (b & 128)
cmask[channel] = mask = buffer[bufpos++];
else
mask = cmask[channel];
if (mask) {
entry->mask = (mask & 15) | (mask >> 4);
entry->channel = channel;
if (mask & IT_ENTRY_NOTE)
cnote[channel] = entry->note = buffer[bufpos++];
else if (mask & (IT_ENTRY_NOTE << 4))
entry->note = cnote[channel];
if (mask & IT_ENTRY_INSTRUMENT)
cinstrument[channel] = entry->instrument = buffer[bufpos++];
else if (mask & (IT_ENTRY_INSTRUMENT << 4))
entry->instrument = cinstrument[channel];
if (mask & IT_ENTRY_VOLPAN)
cvolpan[channel] = entry->volpan = buffer[bufpos++];
else if (mask & (IT_ENTRY_VOLPAN << 4))
entry->volpan = cvolpan[channel];
if (mask & IT_ENTRY_EFFECT) {
ceffect[channel] = entry->effect = buffer[bufpos++];
ceffectvalue[channel] = entry->effectvalue = buffer[bufpos++];
} else {
entry->effect = ceffect[channel];
entry->effectvalue = ceffectvalue[channel];
}
#ifdef DETECT_DUPLICATE_CHANNELS
if (dupentry[channel]) {
FILE *f = fopen("dupentry.txt", "a");
if (!f) abort();
fprintf(f, "Two events on channel %d:", channel);
fprintf(f, " Event #1:");
if (dupentry[channel]->mask & IT_ENTRY_NOTE ) fprintf(f, " %03d", dupentry[channel]->note ); else fprintf(f, " ...");
if (dupentry[channel]->mask & IT_ENTRY_INSTRUMENT) fprintf(f, " %03d", dupentry[channel]->instrument); else fprintf(f, " ...");
if (dupentry[channel]->mask & IT_ENTRY_VOLPAN ) fprintf(f, " %03d", dupentry[channel]->volpan ); else fprintf(f, " ...");
if (dupentry[channel]->mask & IT_ENTRY_EFFECT) fprintf(f, " %c%02X\n", 'A' - 1 + dupentry[channel]->effect, dupentry[channel]->effectvalue); else fprintf(f, " ...\n");
fprintf(f, " Event #2:");
if (entry->mask & IT_ENTRY_NOTE ) fprintf(f, " %03d", entry->note ); else fprintf(f, " ...");
if (entry->mask & IT_ENTRY_INSTRUMENT) fprintf(f, " %03d", entry->instrument); else fprintf(f, " ...");
if (entry->mask & IT_ENTRY_VOLPAN ) fprintf(f, " %03d", entry->volpan ); else fprintf(f, " ...");
if (entry->mask & IT_ENTRY_EFFECT) fprintf(f, " %c%02X\n", 'A' - 1 + entry->effect, entry->effectvalue); else fprintf(f, " ...\n");
fclose(f);
}
dupentry[channel] = entry;
#endif
entry++;
}
}
ASSERT(entry == pattern->entry + n_entries);
return 0;
}
/* Currently we assume the sample data are stored after the sample headers in
* module files. This assumption may be unjustified; let me know if you have
* trouble.
*/
#define IT_COMPONENT_SONG_MESSAGE 1
#define IT_COMPONENT_INSTRUMENT 2
#define IT_COMPONENT_PATTERN 3
#define IT_COMPONENT_SAMPLE 4
typedef struct IT_COMPONENT
{
unsigned char type;
unsigned short n;
long offset;
short sampfirst; /* component[sampfirst] = first sample data after this */
short sampnext; /* sampnext is used to create linked lists of sample data */
}
IT_COMPONENT;
static int it_component_compare(const void *e1, const void *e2)
{
return (int)(((const IT_COMPONENT *)e1)->offset -
((const IT_COMPONENT *)e2)->offset);
}
static sigdata_t *it_load_sigdata(DUMBFILE *f)
{
DUMB_IT_SIGDATA *sigdata;
int cwt, cmwt;
int special;
int message_length, message_offset;
IT_COMPONENT *component;
int n_components = 0;
unsigned char sample_convert[4096];
int n;
unsigned char *buffer;
if (dumbfile_mgetl(f) != IT_SIGNATURE)
{
return NULL;
}
sigdata = malloc(sizeof(*sigdata));
if (!sigdata)
{
return NULL;
}
sigdata->song_message = NULL;
sigdata->order = NULL;
sigdata->instrument = NULL;
sigdata->sample = NULL;
sigdata->pattern = NULL;
sigdata->midi = NULL;
sigdata->checkpoint = NULL;
dumbfile_getnc((char *)sigdata->name, 26, f);
sigdata->name[26] = 0;
/* Skip pattern row highlight info. */
dumbfile_skip(f, 2);
sigdata->n_orders = dumbfile_igetw(f);
sigdata->n_instruments = dumbfile_igetw(f);
sigdata->n_samples = dumbfile_igetw(f);
sigdata->n_patterns = dumbfile_igetw(f);
cwt = dumbfile_igetw(f);
cmwt = dumbfile_igetw(f);
sigdata->flags = dumbfile_igetw(f);
special = dumbfile_igetw(f);
sigdata->global_volume = dumbfile_getc(f);
sigdata->mixing_volume = dumbfile_getc(f);
sigdata->speed = dumbfile_getc(f);
if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
sigdata->tempo = dumbfile_getc(f);
sigdata->pan_separation = dumbfile_getc(f); /** WARNING: use this */
/* Skip Pitch Wheel Depth */
dumbfile_skip(f, 1);
message_length = dumbfile_igetw(f);
message_offset = (int)dumbfile_igetl(f);
/* Skip Reserved. */
dumbfile_skip(f, 4);
dumbfile_getnc((char *)sigdata->channel_pan, DUMB_IT_N_CHANNELS, f);
dumbfile_getnc((char *)sigdata->channel_volume, DUMB_IT_N_CHANNELS, f);
// XXX sample count
if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_instruments > 256 || sigdata->n_samples > 4000 || sigdata->n_patterns > 256) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->order = malloc(sigdata->n_orders);
if (!sigdata->order) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (sigdata->n_instruments) {
sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
if (!sigdata->instrument) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
}
if (sigdata->n_samples) {
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
if (!sigdata->sample) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (n = 0; n < sigdata->n_samples; n++)
sigdata->sample[n].data = NULL;
}
if (sigdata->n_patterns) {
sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
if (!sigdata->pattern) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (n = 0; n < sigdata->n_patterns; n++)
sigdata->pattern[n].entry = NULL;
}
dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f);
sigdata->restart_position = 0;
component = malloc(769 * sizeof(*component));
if (!component) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (special & 1) {
component[n_components].type = IT_COMPONENT_SONG_MESSAGE;
component[n_components].offset = message_offset;
component[n_components].sampfirst = -1;
n_components++;
}
for (n = 0; n < sigdata->n_instruments; n++) {
component[n_components].type = IT_COMPONENT_INSTRUMENT;
component[n_components].n = n;
component[n_components].offset = dumbfile_igetl(f);
component[n_components].sampfirst = -1;
n_components++;
}
for (n = 0; n < sigdata->n_samples; n++) {
component[n_components].type = IT_COMPONENT_SAMPLE;
component[n_components].n = n;
component[n_components].offset = dumbfile_igetl(f);
component[n_components].sampfirst = -1;
n_components++;
}
for (n = 0; n < sigdata->n_patterns; n++) {
long offset = dumbfile_igetl(f);
if (offset) {
component[n_components].type = IT_COMPONENT_PATTERN;
component[n_components].n = n;
component[n_components].offset = offset;
component[n_components].sampfirst = -1;
n_components++;
} else {
/* Empty 64-row pattern */
sigdata->pattern[n].n_rows = 64;
sigdata->pattern[n].n_entries = 0;
}
}
if (dumbfile_error(f)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
/*
if (!(sigdata->flags & 128) != !(special & 8)) {
fprintf(stderr, "Flags Bit 7 (\"Request embedded MIDI configuration\"): %s\n", sigdata->flags & 128 ? "=SET=" : "clear");
fprintf(stderr, "Special Bit 3 (\"MIDI configuration embedded\") : %s\n", special & 8 ? "=SET=" : "clear");
fprintf(stderr, "entheh would like to investigate this IT file.\n");
fprintf(stderr, "Please contact him! entheh@users.sf.net\n");
}
*/
if (special & 8) {
/* MIDI configuration is embedded. */
unsigned char mididata[32];
int i;
sigdata->midi = malloc(sizeof(*sigdata->midi));
if (!sigdata->midi) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
// Should we be happy with this outcome in some situations?
}
// What are we skipping?
i = dumbfile_igetw(f);
if (dumbfile_error(f) || dumbfile_skip(f, 8*i)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
/* Read embedded MIDI configuration */
// What are the first 9 commands for?
if (dumbfile_skip(f, 32*9)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (i = 0; i < 16; i++) {
unsigned char len = 0;
int j, leftdigit = -1;
if (dumbfile_getnc((char *)mididata, 32, f) < 32) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->midi->SFmacroz[i] = 0;
for (j = 0; j < 32; j++) {
if (leftdigit >= 0) {
if (mididata[j] == 0) {
sigdata->midi->SFmacro[i][len++] = leftdigit;
break;
} else if (mididata[j] == ' ')
sigdata->midi->SFmacro[i][len++] = leftdigit;
else if (mididata[j] >= '0' && mididata[j] <= '9')
sigdata->midi->SFmacro[i][len++] = (leftdigit << 4) | (mididata[j] - '0');
else if (mididata[j] >= 'A' && mididata[j] <= 'F')
sigdata->midi->SFmacro[i][len++] = (leftdigit << 4) | (mididata[j] - 'A' + 0xA);
leftdigit = -1;
} else if (mididata[j] == 0)
break;
else if (mididata[j] == 'z')
sigdata->midi->SFmacroz[i] |= 1 << len++;
else if (mididata[j] >= '0' && mididata[j] <= '9')
leftdigit = mididata[j] - '0';
else if (mididata[j] >= 'A' && mididata[j] <= 'F')
leftdigit = mididata[j] - 'A' + 0xA;
}
sigdata->midi->SFmacrolen[i] = len;
}
for (i = 0; i < 128; i++) {
unsigned char len = 0;
int j, leftdigit = -1;
dumbfile_getnc((char *)mididata, 32, f);
for (j = 0; j < 32; j++) {
if (leftdigit >= 0) {
if (mididata[j] == 0) {
sigdata->midi->Zmacro[i][len++] = leftdigit;
break;
} else if (mididata[j] == ' ')
sigdata->midi->Zmacro[i][len++] = leftdigit;
else if (mididata[j] >= '0' && mididata[j] <= '9')
sigdata->midi->Zmacro[i][len++] = (leftdigit << 4) | (mididata[j] - '0');
else if (mididata[j] >= 'A' && mididata[j] <= 'F')
sigdata->midi->Zmacro[i][len++] = (leftdigit << 4) | (mididata[j] - 'A' + 0xA);
leftdigit = -1;
} else if (mididata[j] == 0)
break;
else if (mididata[j] >= '0' && mididata[j] <= '9')
leftdigit = mididata[j] - '0';
else if (mididata[j] >= 'A' && mididata[j] <= 'F')
leftdigit = mididata[j] - 'A' + 0xA;
}
sigdata->midi->Zmacrolen[i] = len;
}
}
sigdata->flags &= IT_REAL_FLAGS;
qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare);
buffer = malloc(65536);
if (!buffer) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (n = 0; n < n_components; n++) {
long offset;
int m;
/* XXX */
if ( component[n].offset == 0 ) {
switch (component[n].type) {
case IT_COMPONENT_INSTRUMENT:
memset( &sigdata->instrument[component[n].n], 0, sizeof(IT_INSTRUMENT) );
break;
case IT_COMPONENT_SAMPLE:
memset( &sigdata->sample[component[n].n], 0, sizeof(IT_SAMPLE) );
break;
case IT_COMPONENT_PATTERN:
{
IT_PATTERN * p = &sigdata->pattern[component[n].n];
p->entry = 0;
p->n_rows = 64;
p->n_entries = 0;
}
break;
}
continue;
}
if (dumbfile_seek(f, component[n].offset, DFS_SEEK_SET)) {
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
switch (component[n].type) {
case IT_COMPONENT_SONG_MESSAGE:
if ( n < n_components ) {
message_length = min( message_length, (int)(component[n+1].offset - component[n].offset) );
}
sigdata->song_message = malloc(message_length + 1);
if (sigdata->song_message) {
if (dumbfile_getnc((char *)sigdata->song_message, message_length, f) < message_length) {
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
sigdata->song_message[message_length] = 0;
}
break;
case IT_COMPONENT_INSTRUMENT:
if (cmwt < 0x200)
m = it_read_old_instrument(&sigdata->instrument[component[n].n], f);
else
m = it_read_instrument(&sigdata->instrument[component[n].n], f, (n + 1 < n_components) ? (int)(component[n+1].offset - component[n].offset) : 0);
if (m) {
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
break;
case IT_COMPONENT_PATTERN:
if (it_read_pattern(&sigdata->pattern[component[n].n], f, buffer)) {
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
break;
case IT_COMPONENT_SAMPLE:
if (it_read_sample_header(&sigdata->sample[component[n].n], &sample_convert[component[n].n], &offset, f)) {
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (sigdata->sample[component[n].n].flags & IT_SAMPLE_EXISTS) {
short *sample;
for (m = n + 1; m < n_components; m++)
if (component[m].offset > offset)
break;
m--;
sample = &component[m].sampfirst;
while (*sample >= 0 && component[*sample].offset <= offset)
sample = &component[*sample].sampnext;
component[n].sampnext = *sample;
*sample = n;
component[n].offset = offset;
}
}
m = component[n].sampfirst;
while (m >= 0) {
if (dumbfile_seek(f, component[m].offset, DFS_SEEK_SET)) {
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (it_read_sample_data(&sigdata->sample[component[m].n], sample_convert[component[m].n], f)) {
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
m = component[m].sampnext;
}
}
for ( n = 0; n < 10; n++ )
{
if ( dumbfile_getc( f ) == 'X' )
{
if ( dumbfile_getc( f ) == 'T' )
{
if ( dumbfile_getc( f ) == 'P' )
{
if ( dumbfile_getc( f ) == 'M' )
{
break;
}
}
}
}
}
if ( !dumbfile_error( f ) && n < 10 )
{
unsigned int mptx_id = (unsigned int)dumbfile_igetl( f );
while ( !dumbfile_error( f ) && mptx_id != DUMB_ID('M','P','T','S') )
{
unsigned int size = dumbfile_igetw( f );
switch (mptx_id)
{
/* TODO: Add instrument extension readers */
default:
dumbfile_skip(f, size * sigdata->n_instruments);
break;
}
mptx_id = (unsigned int)dumbfile_igetl( f );
}
mptx_id = (unsigned int)dumbfile_igetl( f );
while ( !dumbfile_error(f) && dumbfile_pos(f) < dumbfile_get_size(f) )
{
unsigned int size = dumbfile_igetw( f );
switch (mptx_id)
{
/* TODO: Add more song extension readers */
case DUMB_ID('D','T','.','.'):
if ( size == 2 )
sigdata->tempo = dumbfile_igetw( f );
else if ( size == 4 )
sigdata->tempo = (int)dumbfile_igetl( f );
break;
default:
dumbfile_skip(f, size);
break;
}
mptx_id = (unsigned int)dumbfile_igetl( f );
}
}
free(buffer);
free(component);
_dumb_it_fix_invalid_orders(sigdata);
return sigdata;
}
DUH *dumb_read_it_quick(DUMBFILE *f)
{
sigdata_t *sigdata;
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
sigdata = it_load_sigdata(f);
if (!sigdata)
return NULL;
{
const char *tag[2][2];
tag[0][0] = "TITLE";
tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name);
tag[1][0] = "FORMAT";
tag[1][1] = "IT";
return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
}
}