static int it_ptm_read_sample_header(IT_SAMPLE *sample, long *offset, DUMBFILE *f) { int flags; flags = dumbfile_getc(f); dumbfile_getnc((char *)sample->filename, 12, f); sample->filename[12] = 0; sample->default_volume = dumbfile_getc(f); sample->C5_speed = dumbfile_igetw(f) << 1; dumbfile_skip(f, 2); /* segment */ *offset = dumbfile_igetl(f); sample->length = dumbfile_igetl(f); sample->loop_start = dumbfile_igetl(f); sample->loop_end = dumbfile_igetl(f); /* GUSBegin, GUSLStart, GUSLEnd, GUSLoop, reserverd */ dumbfile_skip(f, 4+4+4+1+1); dumbfile_getnc((char *)sample->name, 28, f); sample->name[28] = 0; /* if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','S')) return -1; */ /* BLAH! Shit likes to have broken or missing sample IDs */ dumbfile_skip(f, 4); if ((flags & 3) == 0) { /* Looks like no sample */ sample->flags &= ~IT_SAMPLE_EXISTS; return dumbfile_error(f); } sample->global_volume = 64; sample->flags = IT_SAMPLE_EXISTS; if (flags & 4) sample->flags |= IT_SAMPLE_LOOP; if (flags & 8) sample->flags |= IT_SAMPLE_PINGPONG_LOOP; if (flags & 16) { sample->flags |= IT_SAMPLE_16BIT; sample->length >>= 1; sample->loop_start >>= 1; sample->loop_end >>= 1; }
static int readblock(DUMBFILE *f) { long size; int c; size = dumbfile_igetw(f); if (size < 0) return size; sourcebuf = malloc(size); if (!sourcebuf) return -1; c = dumbfile_getnc((char *)sourcebuf, size, f); if (c < size) { free(sourcebuf); sourcebuf = NULL; return -1; } sourcepos = sourcebuf; sourceend = sourcebuf + size; rembits = 8; return 0; }
static int limit_xm_resize(void *f, long n) { DUMBFILE *df = f; LIMITED_XM *lx = df->file; if (n < 0) return -1; if (lx->buffered || n) { if (n > lx->allocated) { unsigned char *buffered = realloc(lx->buffered, n); if (!buffered) return -1; lx->buffered = buffered; memset(buffered + lx->allocated, 0, n - lx->allocated); lx->allocated = n; } if (dumbfile_getnc((char *)lx->buffered, n, lx->remaining) < n) return -1; } else if (!n) { if (lx->buffered) free(lx->buffered); lx->buffered = NULL; lx->allocated = 0; } lx->limit = n; lx->ptr = 0; return 0; }
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 int it_asy_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer ) { int pos; int channel; int row; IT_ENTRY *entry; pattern->n_rows = 64; if ( dumbfile_getnc( buffer, 64 * 8 * 4, f ) != 64 * 8 * 4 ) return -1; /* compute number of entries */ pattern->n_entries = 64; /* Account for the row end markers */ pos = 0; for ( row = 0; row < 64; ++row ) { for ( channel = 0; channel < 8; ++channel ) { if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) ++pattern->n_entries; pos += 4; } } pattern->entry = malloc( pattern->n_entries * sizeof( *pattern->entry ) ); if ( !pattern->entry ) return -1; entry = pattern->entry; pos = 0; for ( row = 0; row < 64; ++row ) { for ( channel = 0; channel < 8; ++channel ) { if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) { entry->channel = channel; entry->mask = 0; if ( buffer[ pos + 0 ] && buffer[ pos + 0 ] < 96 ) { entry->note = buffer[ pos + 0 ]; entry->mask |= IT_ENTRY_NOTE; } if ( buffer[ pos + 1 ] && buffer[ pos + 1 ] <= 64 ) { entry->instrument = buffer[ pos + 1 ]; entry->mask |= IT_ENTRY_INSTRUMENT; } _dumb_it_xm_convert_effect( buffer[ pos + 2 ], buffer[ pos + 3 ], entry, 1 ); if ( entry->mask ) ++entry; } pos += 4; } IT_SET_END_ROW( entry ); ++entry; } pattern->n_entries = (int)(entry - pattern->entry); return 0; }
static int it_asy_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f) { int finetune, key_offset; /** 21 22 Chars Sample 1 name. If the name is not a full 22 chars in length, it will be null terminated. If the sample name begins with a '#' character (ASCII $23 (35)) then this is assumed not to be an instrument name, and is probably a message. */ dumbfile_getnc((char *)sample->name, 22, f); sample->name[22] = 0; sample->filename[0] = 0; /** Each finetune step changes the note 1/8th of a semitone. */ finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */ sample->default_volume = dumbfile_getc(f); // Should we be setting global_volume to this instead? sample->global_volume = 64; if (sample->default_volume > 64) sample->default_volume = 64; key_offset = (signed char)dumbfile_getc(f); /* base key offset */ sample->length = dumbfile_igetl(f); sample->loop_start = dumbfile_igetl(f); sample->loop_end = sample->loop_start + dumbfile_igetl(f); if (sample->length <= 0) { sample->flags = 0; return 0; } sample->flags = IT_SAMPLE_EXISTS; sample->default_pan = 0; sample->C5_speed = (int)(AMIGA_CLOCK / 214.0 * pow(DUMB_SEMITONE_BASE, key_offset)); //( long )( 16726.0 * pow( // DUMB_PITCH_BASE, finetune //* 32 ) ); sample->finetune = finetune * 32; // the above line might be wrong 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); }
/* I (entheh) have two XM files saved by a very naughty program. After a * 16-bit sample, it saved a rogue byte. The length of the sample was indeed * an odd number, incremented to include the rogue byte. * * In this function we are converting sample lengths and loop points so they * are measured in samples. This means we forget about the extra bytes, and * they don't get skipped. So we fail trying to read the next instrument. * * To get around this, this function returns the number of rogue bytes that * won't be accounted for by reading sample->length samples. It returns a * negative number on failure. */ static int it_xm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f) { int type; int relative_note_number; /* relative to C4 */ int finetune; int roguebytes; int roguebytesmask; int reserved; sample->length = dumbfile_igetl(f); sample->loop_start = dumbfile_igetl(f); sample->loop_end = sample->loop_start + dumbfile_igetl(f); sample->global_volume = 64; sample->default_volume = dumbfile_getc(f); finetune = (signed char)dumbfile_getc(f); /* -128..127 <=> -1 semitone .. +127/128 of a semitone */ type = dumbfile_getc(f); sample->default_pan = dumbfile_getc(f); /* 0-255 */ relative_note_number = (signed char)dumbfile_getc(f); reserved = dumbfile_getc(f); dumbfile_getnc((char *)sample->name, 22, f); sample->name[22] = 0; trim_whitespace((char *)sample->name, 22); sample->filename[0] = 0; if (dumbfile_error(f)) return -1; sample->C5_speed = (long)(16726.0*pow(DUMB_SEMITONE_BASE, relative_note_number) /**pow(DUMB_PITCH_BASE, )*/ ); sample->finetune = finetune*2; sample->flags = IT_SAMPLE_EXISTS; if (reserved == 0xAD && (!(type & (XM_SAMPLE_16BIT | XM_SAMPLE_STEREO)))) { /* F U Olivier Lapicque */ roguebytes = 4; roguebytesmask = 4 << 2; } else { roguebytes = (int)sample->length; roguebytesmask = 3; } if (type & XM_SAMPLE_16BIT) { sample->flags |= IT_SAMPLE_16BIT; sample->length >>= 1; sample->loop_start >>= 1; sample->loop_end >>= 1; } else
/* I (entheh) have two XM files saved by a very naughty program. After a * 16-bit sample, it saved a rogue byte. The length of the sample was indeed * an odd number, incremented to include the rogue byte. * * In this function we are converting sample lengths and loop points so they * are measured in samples. This means we forget about the extra bytes, and * they don't get skipped. So we fail trying to read the next instrument. * * To get around this, this function returns the number of rogue bytes that * won't be accounted for by reading sample->length samples. It returns a * negative number on failure. */ static int it_xm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f) { int type; int relative_note_number; /* relative to C4 */ int finetune; int roguebytes; int roguebytesmask; sample->length = dumbfile_igetl(f); sample->loop_start = dumbfile_igetl(f); sample->loop_end = sample->loop_start + dumbfile_igetl(f); sample->global_volume = 64; sample->default_volume = dumbfile_getc(f); finetune = (signed char)dumbfile_getc(f); /* -128..127 <=> -1 semitone .. +127/128 of a semitone */ type = dumbfile_getc(f); sample->default_pan = dumbfile_getc(f); /* 0-255 */ relative_note_number = (signed char)dumbfile_getc(f); dumbfile_skip(f, 1); /* reserved */ dumbfile_getnc(sample->name, 22, f); sample->name[22] = 0; sample->filename[0] = 0; if (dumbfile_error(f)) return -1; sample->C5_speed = (long)(16726.0*pow(DUMB_SEMITONE_BASE, relative_note_number)*pow(DUMB_PITCH_BASE, finetune*2)); sample->flags = IT_SAMPLE_EXISTS; roguebytes = (int)sample->length; roguebytesmask = 3; if (type & XM_SAMPLE_16BIT) { sample->flags |= IT_SAMPLE_16BIT; sample->length >>= 1; sample->loop_start >>= 1; sample->loop_end >>= 1; } else
/* dumb_read_riff_quick(): reads a RIFF file into a DUH struct, returning a * pointer to the DUH struct. When you have finished with it, you must pass * the pointer to unload_duh() so that the memory can be freed. */ DUH *dumb_read_riff_quick( DUMBFILE * f ) { DUH * duh; struct riff * stream; { unsigned char * buffer = 0; unsigned size = 0; unsigned read; do { buffer = realloc( buffer, 32768 + size ); if ( ! buffer ) return 0; read = dumbfile_getnc( buffer + size, 32768, f ); if ( read < 0 ) { free( buffer ); return 0; } size += read; } while ( read == 32768 ); stream = riff_parse( buffer, size, 1 ); if ( ! stream ) stream = riff_parse( buffer, size, 0 ); free( buffer ); } if ( ! stream ) return 0; if ( stream->type == DUMB_ID( 'A', 'M', ' ', ' ' ) ) duh = dumb_read_riff_am( stream ); else if ( stream->type == DUMB_ID( 'A', 'M', 'F', 'F' ) ) duh = dumb_read_riff_amff( stream ); else if ( stream->type == DUMB_ID( 'D', 'S', 'M', 'F' ) ) duh = dumb_read_riff_dsmf( stream ); else duh = 0; riff_free( stream ); return duh; }
static void *sequence_load_signal(DUH *duh, DUMBFILE *file) { long size; unsigned char *signal; (void)duh; size = dumbfile_igetl(file); if (dumbfile_error(file) || size <= 0) return NULL; signal = malloc(size); if (!signal) return NULL; if (dumbfile_getnc((char *)signal, size, file) < size) { free(signal); return NULL; } return signal; }
static int it_asy_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f) { long truncated_size; /* let's get rid of the sample data coming after the end of the loop */ if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) { truncated_size = sample->length - sample->loop_end; sample->length = sample->loop_end; } else { truncated_size = 0; } sample->data = malloc(sample->length); if (!sample->data) return -1; if (sample->length) dumbfile_getnc(sample->data, sample->length, f); dumbfile_skip(f, truncated_size); return dumbfile_error(f); }
static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f) { DUMB_IT_SIGDATA *sigdata; unsigned n_channels; unsigned i, j, k, l; IFF_CHUNKED *mod; const IFF_CHUNK *chunk; char signature[8]; if (dumbfile_getnc(signature, 8, f) < 8 || memcmp(signature, "OKTASONG", 8)) { return NULL; } mod = dumbfile_read_okt(f); if (!mod) return NULL; sigdata = (DUMB_IT_SIGDATA *) malloc(sizeof(*sigdata)); if (!sigdata) { free_okt(mod); return NULL; } sigdata->name[0] = 0; chunk = get_chunk_by_type(mod, DUMB_ID('S','P','E','E'), 0); if (!chunk || chunk->size < 2) { free(sigdata); free_okt(mod); return NULL; } sigdata->speed = (chunk->data[0] << 8) | chunk->data[1]; chunk = get_chunk_by_type(mod, DUMB_ID('S','A','M','P'), 0); if (!chunk || chunk->size < 32) { free(sigdata); free_okt(mod); return NULL; } sigdata->n_samples = chunk->size / 32; chunk = get_chunk_by_type(mod, DUMB_ID('C','M','O','D'), 0); if (!chunk || chunk->size < 8) { free(sigdata); free_okt(mod); return NULL; } n_channels = 0; for (i = 0; i < 4; i++) { j = (chunk->data[i * 2] << 8) | chunk->data[i * 2 + 1]; if (!j) n_channels++; else if (j == 1) n_channels += 2; } if (!n_channels) { free(sigdata); free_okt(mod); return NULL; } sigdata->n_pchannels = n_channels; sigdata->sample = (IT_SAMPLE *) malloc(sigdata->n_samples * sizeof(*sigdata->sample)); if (!sigdata->sample) { free(sigdata); free_okt(mod); return NULL; } sigdata->song_message = NULL; sigdata->order = NULL; sigdata->instrument = NULL; sigdata->pattern = NULL; sigdata->midi = NULL; sigdata->checkpoint = NULL; sigdata->n_instruments = 0; for (i = 0; i < (unsigned)sigdata->n_samples; i++) sigdata->sample[i].data = NULL; chunk = get_chunk_by_type(mod, DUMB_ID('S','A','M','P'), 0); for (i = 0; i < (unsigned)sigdata->n_samples; i++) { it_okt_read_sample_header(&sigdata->sample[i], chunk->data + 32 * i); } sigdata->restart_position = 0; chunk = get_chunk_by_type(mod, DUMB_ID('P','L','E','N'), 0); if (!chunk || chunk->size < 2) { _dumb_it_unload_sigdata(sigdata); free_okt(mod); return NULL; } sigdata->n_orders = (chunk->data[0] << 8) | chunk->data[1]; // what if this is > 128? if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { _dumb_it_unload_sigdata(sigdata); free_okt(mod); return NULL; } chunk = get_chunk_by_type(mod, DUMB_ID('P','A','T','T'), 0); if (!chunk || chunk->size < (unsigned)sigdata->n_orders) { _dumb_it_unload_sigdata(sigdata); free_okt(mod); return NULL; } sigdata->order = (unsigned char *) malloc(sigdata->n_orders); if (!sigdata->order) { _dumb_it_unload_sigdata(sigdata); free_okt(mod); return NULL; } memcpy(sigdata->order, chunk->data, sigdata->n_orders); /* Work out how many patterns there are. */ chunk = get_chunk_by_type(mod, DUMB_ID('S','L','E','N'), 0); if (!chunk || chunk->size < 2) { _dumb_it_unload_sigdata(sigdata); free_okt(mod); return NULL; } sigdata->n_patterns = (chunk->data[0] << 8) | chunk->data[1]; j = get_chunk_count(mod, DUMB_ID('P','B','O','D')); if (sigdata->n_patterns > (int)j) sigdata->n_patterns = (int)j; if (!sigdata->n_patterns) { _dumb_it_unload_sigdata(sigdata); free_okt(mod); return NULL; } sigdata->pattern = (IT_PATTERN *) malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); if (!sigdata->pattern) { _dumb_it_unload_sigdata(sigdata); free_okt(mod); return NULL; } for (i = 0; i < (unsigned)sigdata->n_patterns; i++) sigdata->pattern[i].entry = NULL; /* Read in the patterns */ for (i = 0; i < (unsigned)sigdata->n_patterns; i++) { chunk = get_chunk_by_type(mod, DUMB_ID('P','B','O','D'), i); if (it_okt_read_pattern(&sigdata->pattern[i], chunk->data, chunk->size, n_channels) != 0) { _dumb_it_unload_sigdata(sigdata); free_okt(mod); return NULL; } } /* And finally, the sample data */ k = get_chunk_count(mod, DUMB_ID('S','B','O','D')); for (i = 0, j = 0; i < (unsigned)sigdata->n_samples && j < k; i++) { if (sigdata->sample[i].flags & IT_SAMPLE_EXISTS) { chunk = get_chunk_by_type(mod, DUMB_ID('S','B','O','D'), j); if (it_okt_read_sample_data(&sigdata->sample[i], (const char *)chunk->data, chunk->size)) { _dumb_it_unload_sigdata(sigdata); free_okt(mod); return NULL; } j++; } } for (; i < (unsigned)sigdata->n_samples; i++) { sigdata->sample[i].flags = 0; } chunk = get_chunk_by_type(mod, DUMB_ID('C','M','O','D'), 0); for (i = 0, j = 0; i < n_channels && j < 4; j++) { k = (chunk->data[j * 2] << 8) | chunk->data[j * 2 + 1]; l = (j == 1 || j == 2) ? 48 : 16; if (k == 0) { sigdata->channel_pan[i++] = l; } else if (k == 1) { sigdata->channel_pan[i++] = l; sigdata->channel_pan[i++] = l; } } free_okt(mod); /* Now let's initialise the remaining variables, and we're done! */ sigdata->flags = IT_WAS_AN_OKT | IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO; sigdata->global_volume = 128; sigdata->mixing_volume = 48; /* We want 50 ticks per second; 50/6 row advances per second; * 50*10=500 row advances per minute; 500/4=125 beats per minute. */ sigdata->tempo = 125; sigdata->pan_separation = 128; memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); memset(sigdata->channel_pan + n_channels, 32, DUMB_IT_N_CHANNELS - n_channels); _dumb_it_fix_invalid_orders(sigdata); return sigdata; }
static IFF_CHUNKED *dumbfile_read_okt(DUMBFILE *f) { IFF_CHUNKED *mod = (IFF_CHUNKED *) malloc(sizeof(*mod)); if (!mod) return NULL; mod->chunk_count = 0; mod->chunks = 0; for (;;) { long bytes_read; IFF_CHUNK * chunk = ( IFF_CHUNK * ) realloc( mod->chunks, ( mod->chunk_count + 1 ) * sizeof( IFF_CHUNK ) ); if ( !chunk ) { if ( mod->chunks ) free( mod->chunks ); free( mod ); return NULL; } mod->chunks = chunk; chunk += mod->chunk_count; bytes_read = dumbfile_mgetl( f ); if ( bytes_read < 0 ) break; chunk->type = bytes_read; chunk->size = dumbfile_mgetl( f ); if ( dumbfile_error( f ) ) break; chunk->data = (unsigned char *) malloc( chunk->size ); if ( !chunk->data ) { free( mod->chunks ); free( mod ); return NULL; } bytes_read = dumbfile_getnc( ( char * ) chunk->data, chunk->size, f ); if ( bytes_read < (long)chunk->size ) { if ( bytes_read <= 0 ) { free( chunk->data ); break; } else { chunk->size = bytes_read; mod->chunk_count++; break; } } mod->chunk_count++; } if ( !mod->chunk_count ) { if ( mod->chunks ) free(mod->chunks); free(mod); mod = NULL; } return mod; }
DUH *dumb_read_any_quick(DUMBFILE *f, int restrict_, int subsong) { unsigned char signature[maximum_signature_size]; unsigned long signature_size; DUH *duh = NULL; /* signature_size = dumbfile_get_size(f); */ signature_size = dumbfile_getnc((char *)signature, maximum_signature_size, f); dumbfile_seek(f, 0, DFS_SEEK_SET); if (signature_size >= 4 && signature[0] == 'I' && signature[1] == 'M' && signature[2] == 'P' && signature[3] == 'M') { duh = dumb_read_it_quick(f); } else if (signature_size >= 17 && !memcmp(signature, "Extended Module: ", 17)) { duh = dumb_read_xm_quick(f); } else if (signature_size >= 0x30 && signature[0x2C] == 'S' && signature[0x2D] == 'C' && signature[0x2E] == 'R' && signature[0x2F] == 'M') { duh = dumb_read_s3m_quick(f); } else if (signature_size >= 30 && /*signature[28] == 0x1A &&*/ signature[29] == 2 && (!strnicmp((const char *)signature + 20, "!Scream!", 8) || !strnicmp((const char *)signature + 20, "BMOD2STM", 8) || !strnicmp((const char *)signature + 20, "WUZAMOD!", 8))) { duh = dumb_read_stm_quick(f); } else if (signature_size >= 2 && ((signature[0] == 0x69 && signature[1] == 0x66) || (signature[0] == 0x4A && signature[1] == 0x4E))) { duh = dumb_read_669_quick(f); } else if (signature_size >= 0x30 && signature[0x2C] == 'P' && signature[0x2D] == 'T' && signature[0x2E] == 'M' && signature[0x2F] == 'F') { duh = dumb_read_ptm_quick(f); } else if (signature_size >= 4 && signature[0] == 'P' && signature[1] == 'S' && signature[2] == 'M' && signature[3] == ' ') { duh = dumb_read_psm_quick(f, subsong); } else if (signature_size >= 4 && signature[0] == 'P' && signature[1] == 'S' && signature[2] == 'M' && signature[3] == 254) { duh = dumb_read_old_psm_quick(f); } else if (signature_size >= 3 && signature[0] == 'M' && signature[1] == 'T' && signature[2] == 'M') { duh = dumb_read_mtm_quick(f); } else if (signature_size >= 4 && signature[0] == 'R' && signature[1] == 'I' && signature[2] == 'F' && signature[3] == 'F') { duh = dumb_read_riff_quick(f); } else if (signature_size >= 24 && !memcmp(signature, "ASYLUM Music Format", 19) && !memcmp(signature + 19, " V1.0", 5)) { duh = dumb_read_asy_quick(f); } else if (signature_size >= 3 && signature[0] == 'A' && signature[1] == 'M' && signature[2] == 'F') { duh = dumb_read_amf_quick(f); } else if (signature_size >= 8 && !memcmp(signature, "OKTASONG", 8)) { duh = dumb_read_okt_quick(f); } if (!duh) { dumbfile_seek(f, 0, DFS_SEEK_SET); duh = dumb_read_mod_quick(f, restrict_); } return duh; }
static int it_s3m_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer) { int buflen = 0; int bufpos = 0; IT_ENTRY *entry; unsigned char channel; /* Haha, this is hilarious! * * Well, after some experimentation, it seems that different S3M writers * define the format in different ways. The S3M docs say that the first * two bytes hold the "length of [the] packed pattern", and the packed * pattern data follow. Judging by the contents of ARMANI.S3M, packaged * with ScreamTracker itself, the measure of length _includes_ the two * bytes used to store the length; in other words, we should read * (length - 2) more bytes. However, aryx.s3m, packaged with ModPlug * Tracker, excludes these two bytes, so (length) more bytes must be * read. * * Call me crazy, but I just find it insanely funny that the format was * misunderstood in this way :D * * Now we can't just risk reading two extra bytes, because then we * overshoot, and DUMBFILEs don't support backward seeking (for a good * reason). Luckily, there is a way. We can read the data little by * little, and stop when we have 64 rows in memory. Provided we protect * against buffer overflow, this method should work with all sensibly * written S3M files. If you find one for which it does not work, please * let me know at [email protected] so I can look at it. */ /* Discard the length. */ dumbfile_skip(f, 2); if (dumbfile_error(f)) return -1; pattern->n_rows = 0; pattern->n_entries = 0; /* Read in the pattern data, little by little, and work out how many * entries we need room for. Sorry, but this is just so funny... */ for (;;) { unsigned char b = buffer[buflen++] = dumbfile_getc(f); #if 1 static const unsigned char used[8] = {0, 2, 1, 3, 2, 4, 3, 5}; channel = b & 31; b >>= 5; pattern->n_entries++; if (b) { if (buflen + used[b] >= 65536) return -1; dumbfile_getnc(buffer + buflen, used[b], f); buflen += used[b]; } else { /* End of row */ if (++pattern->n_rows == 64) break; if (buflen >= 65536) return -1; } #else if (b == 0) { /* End of row */ pattern->n_entries++; if (++pattern->n_rows == 64) break; if (buflen >= 65536) return -1; } else { static const unsigned char used[8] = {0, 2, 1, 3, 2, 4, 3, 5}; channel = b & 31; b >>= 5; if (b) { pattern->n_entries++; if (buflen + used[b] >= 65536) return -1; dumbfile_getnc(buffer + buflen, used[b], f); buflen += used[b]; } } #endif /* We have ensured that buflen < 65536 at this point, so it is safe * to iterate and read at least one more byte without checking. * However, now would be a good time to check for errors reading from * the file. */ if (dumbfile_error(f)) return -1; } pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); if (!pattern->entry) return -1; entry = pattern->entry; while (bufpos < buflen) { unsigned char b = buffer[bufpos++]; #if 1 if (!(b & ~31)) #else if (b == 0) #endif { /* End of row */ IT_SET_END_ROW(entry); entry++; continue; } channel = b & 31; if (b & 224) { entry->mask = 0; entry->channel = channel; if (b & 32) { unsigned char n = buffer[bufpos++]; if (n != 255) { if (n == 254) entry->note = IT_NOTE_CUT; else entry->note = (n >> 4) * 12 + (n & 15); entry->mask |= IT_ENTRY_NOTE; } entry->instrument = buffer[bufpos++]; if (entry->instrument) entry->mask |= IT_ENTRY_INSTRUMENT; } if (b & 64) { entry->volpan = buffer[bufpos++]; if (entry->volpan != 255) entry->mask |= IT_ENTRY_VOLPAN; } if (b & 128) { entry->effect = buffer[bufpos++]; entry->effectvalue = buffer[bufpos++]; if (entry->effect != 255) { entry->mask |= IT_ENTRY_EFFECT; if (entry->effect == IT_BREAK_TO_ROW) entry->effectvalue -= (entry->effectvalue >> 4) * 6; }
static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA *extra, DUMBFILE *f) { unsigned long size, bytes_read; unsigned short vol_points[24]; unsigned short pan_points[24]; int i, type; const unsigned long max_size = 4 + 22 + 1 + 2 + 4 + 96 + 48 + 48 + 1 * 14 + 2 + 2; unsigned long skip_end = 0; /* Header size. Tends to be more than the actual size of the structure. * So unread bytes must be skipped before reading the first sample * header. */ if ( limit_xm_resize( f, 4 ) < 0 ) return -1; size = dumbfile_igetl(f); if ( size == 0 ) size = max_size; else if ( size > max_size ) { skip_end = size - max_size; size = max_size; } if ( limit_xm_resize( f, size - 4 ) < 0 ) return -1; dumbfile_getnc((char *)instrument->name, 22, f); instrument->name[22] = 0; trim_whitespace((char *)instrument->name, 22); instrument->filename[0] = 0; dumbfile_skip(f, 1); /* Instrument type. Should be 0, but seems random. */ extra->n_samples = dumbfile_igetw(f); if (dumbfile_error(f) || (unsigned int)extra->n_samples > XM_MAX_SAMPLES_PER_INSTRUMENT) return -1; bytes_read = 4 + 22 + 1 + 2; if (extra->n_samples) { /* sample header size */ /*i = dumbfile_igetl(f); if (!i || i > 0x28) i = 0x28;*/ dumbfile_skip(f, 4); i = 0x28; extra->sample_header_size = i; /* sample map */ for (i = 0; i < 96; i++) { instrument->map_sample[i] = dumbfile_getc(f) + 1; instrument->map_note[i] = i; } if (dumbfile_error(f)) return 1; /* volume/panning envelopes */ for (i = 0; i < 24; i++) vol_points[i] = dumbfile_igetw(f); for (i = 0; i < 24; i++) pan_points[i] = dumbfile_igetw(f); instrument->volume_envelope.n_nodes = dumbfile_getc(f); instrument->pan_envelope.n_nodes = dumbfile_getc(f); if (dumbfile_error(f)) return -1; instrument->volume_envelope.sus_loop_start = dumbfile_getc(f); instrument->volume_envelope.loop_start = dumbfile_getc(f); instrument->volume_envelope.loop_end = dumbfile_getc(f); instrument->pan_envelope.sus_loop_start = dumbfile_getc(f); instrument->pan_envelope.loop_start = dumbfile_getc(f); instrument->pan_envelope.loop_end = dumbfile_getc(f); /* The envelope handler for XM files won't use sus_loop_end. */ type = dumbfile_getc(f); instrument->volume_envelope.flags = 0; if ((type & XM_ENVELOPE_ON) && instrument->volume_envelope.n_nodes) instrument->volume_envelope.flags |= IT_ENVELOPE_ON; if (type & XM_ENVELOPE_LOOP) instrument->volume_envelope.flags |= IT_ENVELOPE_LOOP_ON; #if 1 if (type & XM_ENVELOPE_SUSTAIN) instrument->volume_envelope.flags |= IT_ENVELOPE_SUSTAIN_LOOP; #else // This is now handled in itrender.c /* let's avoid fading out when reaching the last envelope node */ if (!(type & XM_ENVELOPE_LOOP)) { instrument->volume_envelope.loop_start = instrument->volume_envelope.n_nodes-1; instrument->volume_envelope.loop_end = instrument->volume_envelope.n_nodes-1; } instrument->volume_envelope.flags |= IT_ENVELOPE_LOOP_ON; #endif type = dumbfile_getc(f); instrument->pan_envelope.flags = 0; if ((type & XM_ENVELOPE_ON) && instrument->pan_envelope.n_nodes) instrument->pan_envelope.flags |= IT_ENVELOPE_ON; if (type & XM_ENVELOPE_LOOP) instrument->pan_envelope.flags |= IT_ENVELOPE_LOOP_ON; // should this be here? if (type & XM_ENVELOPE_SUSTAIN) instrument->pan_envelope.flags |= IT_ENVELOPE_SUSTAIN_LOOP; if (it_xm_make_envelope(&instrument->volume_envelope, vol_points, 0) != 0) { TRACE("XM error: volume envelope\n"); if (instrument->volume_envelope.flags & IT_ENVELOPE_ON) return -1; } if (it_xm_make_envelope(&instrument->pan_envelope, pan_points, -32) != 0) { TRACE("XM error: pan envelope\n"); if (instrument->pan_envelope.flags & IT_ENVELOPE_ON) return -1; } instrument->pitch_envelope.flags = 0; extra->vibrato_type = dumbfile_getc(f); extra->vibrato_sweep = dumbfile_getc(f); extra->vibrato_depth = dumbfile_getc(f); extra->vibrato_speed = dumbfile_getc(f); if (dumbfile_error(f) || extra->vibrato_type > 4) // XXX return -1; /** WARNING: lossy approximation */ instrument->fadeout = (dumbfile_igetw(f)*128 + 64)/0xFFF; dumbfile_skip(f, 2); /* reserved */ bytes_read += 4 + 96 + 48 + 48 + 14*1 + 2 + 2; } else for (i = 0; i < 96; i++) instrument->map_sample[i] = 0; if (size > bytes_read && dumbfile_skip(f, size - bytes_read)) return -1; if (skip_end && limit_xm_skip_end(f, skip_end)) return -1; instrument->new_note_action = NNA_NOTE_CUT; instrument->dup_check_type = DCT_OFF; instrument->dup_check_action = DCA_NOTE_CUT; instrument->pp_separation = 0; instrument->pp_centre = 60; /* C-5 */ instrument->global_volume = 128; instrument->default_pan = 32; instrument->random_volume = 0; instrument->random_pan = 0; instrument->filter_cutoff = 0; instrument->filter_resonance = 0; return 0; }
static int it_xm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer, int version) { int size; int pos; int channel; int row; int effect, effectvalue; IT_ENTRY *entry; /* pattern header size */ if (dumbfile_igetl(f) != ( version == 0x0102 ? 0x08 : 0x09 ) ) { TRACE("XM error: unexpected pattern header size\n"); return -1; } /* pattern data packing type */ if (dumbfile_getc(f) != 0) { TRACE("XM error: unexpected pattern packing type\n"); return -1; } if ( version == 0x0102 ) pattern->n_rows = dumbfile_getc(f) + 1; else pattern->n_rows = dumbfile_igetw(f); /* 1..256 */ size = dumbfile_igetw(f); pattern->n_entries = 0; if (dumbfile_error(f)) return -1; if (size == 0) return 0; if (size > 1280 * n_channels) { TRACE("XM error: pattern data size > %d bytes\n", 1280 * n_channels); return -1; } if (dumbfile_getnc((char *)buffer, size, f) < size) return -1; /* compute number of entries */ pattern->n_entries = 0; pos = channel = row = 0; while (pos < size) { if (!(buffer[pos] & XM_ENTRY_PACKED) || (buffer[pos] & 31)) pattern->n_entries++; channel++; if (channel >= n_channels) { channel = 0; row++; pattern->n_entries++; } if (buffer[pos] & XM_ENTRY_PACKED) { static const char offset[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5 }; pos += 1 + offset[buffer[pos] & 31]; } else { pos += 5; } } if (row > pattern->n_rows) { TRACE("XM error: wrong number of rows in pattern data\n"); return -1; } /* Whoops, looks like some modules may be short, a few channels, maybe even rows... */ while (row < pattern->n_rows) { pattern->n_entries++; row++; } pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); if (!pattern->entry) return -1; /* read the entries */ entry = pattern->entry; pos = channel = row = 0; while (pos < size) { unsigned char mask; if (buffer[pos] & XM_ENTRY_PACKED) mask = buffer[pos++] & 31; else mask = 31; if (mask) { ASSERT(entry < pattern->entry + pattern->n_entries); entry->channel = channel; entry->mask = 0; if (mask & XM_ENTRY_NOTE) { int note = buffer[pos++]; /* 1-96 <=> C0-B7 */ entry->note = (note == XM_NOTE_OFF) ? (IT_NOTE_OFF) : (note-1); entry->mask |= IT_ENTRY_NOTE; } if (mask & XM_ENTRY_INSTRUMENT) { entry->instrument = buffer[pos++]; /* 1-128 */ entry->mask |= IT_ENTRY_INSTRUMENT; } if (mask & XM_ENTRY_VOLUME) it_xm_convert_volume(buffer[pos++], entry); effect = effectvalue = 0; if (mask & XM_ENTRY_EFFECT) effect = buffer[pos++]; if (mask & XM_ENTRY_EFFECTVALUE) effectvalue = buffer[pos++]; _dumb_it_xm_convert_effect(effect, effectvalue, entry, 0); entry++; } channel++; if (channel >= n_channels) { channel = 0; row++; IT_SET_END_ROW(entry); entry++; } } while (row < pattern->n_rows) { row++; IT_SET_END_ROW(entry); entry++; } return 0; }
static int it_riff_dsmf_process_sample( IT_SAMPLE * sample, DUMBFILE * f, int len ) { int flags; dumbfile_getnc( (char *) sample->filename, 13, f ); sample->filename[ 14 ] = 0; flags = dumbfile_igetw( f ); sample->default_volume = dumbfile_getc( f ); sample->length = dumbfile_igetl( f ); sample->loop_start = dumbfile_igetl( f ); sample->loop_end = dumbfile_igetl( f ); dumbfile_skip( f, 32 - 28 ); sample->C5_speed = dumbfile_igetw( f ) * 2; dumbfile_skip( f, 36 - 34 ); dumbfile_getnc( (char *) sample->name, 28, f ); sample->name[ 28 ] = 0; /*if ( data[ 0x38 ] || data[ 0x39 ] || data[ 0x3A ] || data[ 0x3B ] ) return -1;*/ if ( ! sample->length ) { sample->flags &= ~IT_SAMPLE_EXISTS; return 0; } /*if ( flags & ~( 2 | 1 ) ) return -1;*/ if ( sample->length + 64 > len ) return -1; sample->flags = IT_SAMPLE_EXISTS; sample->default_pan = 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 & 1 ) { 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; if ( flags & 0x10 ) sample->flags |= IT_SAMPLE_PINGPONG_LOOP; } } sample->data = malloc( sample->length ); if ( ! sample->data ) return -1; dumbfile_getnc( sample->data, sample->length, f ); if ( ! ( flags & 2 ) ) { for ( flags = 0; flags < sample->length; ++flags ) ( ( signed char * ) sample->data ) [ flags ] ^= 0x80; } return 0; }
static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( DUMBFILE * f, struct riff * stream ) { DUMB_IT_SIGDATA *sigdata; int n, o, found; if ( ! stream ) goto error; if ( stream->type != DUMB_ID( 'D', 'S', 'M', 'F' ) ) goto error; sigdata = malloc(sizeof(*sigdata)); if ( ! sigdata ) goto error; sigdata->n_patterns = 0; sigdata->n_samples = 0; sigdata->name[0] = 0; found = 0; for ( n = 0; (unsigned)n < stream->chunk_count; ++n ) { struct riff_chunk * c = stream->chunks + n; switch( c->type ) { case DUMB_ID( 'S' ,'O' ,'N' ,'G' ): /* initialization data */ if ( ( found ) || ( c->size < 192 ) ) goto error_sd; found = 1; break; case DUMB_ID( 'P', 'A', 'T', 'T' ): ++ sigdata->n_patterns; break; case DUMB_ID( 'I', 'N', 'S', 'T' ): ++ sigdata->n_samples; break; } } if ( !found || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd; if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd; sigdata->song_message = NULL; sigdata->order = NULL; sigdata->instrument = NULL; sigdata->sample = NULL; sigdata->pattern = NULL; sigdata->midi = NULL; sigdata->checkpoint = NULL; sigdata->mixing_volume = 48; sigdata->pan_separation = 128; sigdata->n_instruments = 0; sigdata->n_orders = 0; sigdata->restart_position = 0; memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) { int sep = 32 * dumb_it_default_panning_separation / 100; sigdata->channel_pan[n ] = 32 - sep; sigdata->channel_pan[n+1] = 32 + sep; sigdata->channel_pan[n+2] = 32 + sep; sigdata->channel_pan[n+3] = 32 - sep; } for ( n = 0; (unsigned)n < stream->chunk_count; ++n ) { struct riff_chunk * c = stream->chunks + n; switch ( c->type ) { case DUMB_ID( 'S', 'O', 'N', 'G' ): if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd; dumbfile_getnc( (char *) sigdata->name, 28, f ); sigdata->name[ 28 ] = 0; sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX; dumbfile_skip( f, 36 - 28 ); sigdata->n_orders = dumbfile_igetw( f ); //sigdata->n_samples = ptr[ 38 ] | ( ptr[ 39 ] << 8 ); // whatever //sigdata->n_patterns = ptr[ 40 ] | ( ptr[ 41 ] << 8 ); dumbfile_skip( f, 42 - 38 ); sigdata->n_pchannels = dumbfile_igetw( f ); sigdata->global_volume = dumbfile_getc( f ); sigdata->mixing_volume = dumbfile_getc( f ); sigdata->speed = dumbfile_getc( f ); sigdata->tempo = dumbfile_getc( f ); for ( o = 0; o < 16; ++o ) { sigdata->channel_pan[ o ] = dumbfile_getc( f ) / 2; } sigdata->order = malloc( 128 ); if ( ! sigdata->order ) goto error_usd; dumbfile_getnc( (char *) sigdata->order, 128, f ); break; } } sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) ); if ( ! sigdata->pattern ) goto error_usd; for ( n = 0; n < sigdata->n_patterns; ++n ) sigdata->pattern[ n ].entry = NULL; sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) ); if ( ! sigdata->sample ) goto error_usd; for ( n = 0; n < sigdata->n_samples; ++n ) { IT_SAMPLE * sample = sigdata->sample + n; sample->data = NULL; } sigdata->n_samples = 0; sigdata->n_patterns = 0; for ( n = 0; (unsigned)n < stream->chunk_count; ++n ) { struct riff_chunk * c = stream->chunks + n; switch ( c->type ) { case DUMB_ID( 'P', 'A', 'T', 'T' ): if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd; if ( it_riff_dsmf_process_pattern( sigdata->pattern + sigdata->n_patterns, f, c->size ) ) goto error_usd; ++ sigdata->n_patterns; break; case DUMB_ID( 'I', 'N', 'S', 'T' ): if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd; if ( it_riff_dsmf_process_sample( sigdata->sample + sigdata->n_samples, f, c->size ) ) goto error_usd; ++ sigdata->n_samples; break; } } _dumb_it_fix_invalid_orders( sigdata ); return sigdata; error_usd: _dumb_it_unload_sigdata( sigdata ); goto error; error_sd: free( sigdata ); error: return NULL; }
static int it_s3m_read_sample_header(IT_SAMPLE *sample, long *offset, unsigned char *pack, int cwtv, DUMBFILE *f) { unsigned char type; int flags; type = dumbfile_getc(f); dumbfile_getnc((char *)sample->filename, 12, f); sample->filename[12] = 0; if (type > 1) { /** WARNING: no adlib support */ dumbfile_skip(f, 3 + 12 + 1 + 1 + 2 + 2 + 2 + 12); dumbfile_getnc((char *)sample->name, 28, f); sample->name[28] = 0; dumbfile_skip(f, 4); sample->flags &= ~IT_SAMPLE_EXISTS; return dumbfile_error(f); } *offset = dumbfile_getc(f) << 20; *offset += dumbfile_igetw(f) << 4; sample->length = dumbfile_igetl(f); sample->loop_start = dumbfile_igetl(f); sample->loop_end = dumbfile_igetl(f); sample->default_volume = dumbfile_getc(f); dumbfile_skip(f, 1); flags = dumbfile_getc(f); if (flags < 0 || (flags != 0 && flags != 4)) /* Sample is packed apparently (or error reading from file). We don't * know how to read packed samples. */ return -1; *pack = flags; flags = dumbfile_getc(f); sample->C5_speed = dumbfile_igetl(f) << 1; /* Skip four unused bytes and three internal variables. */ dumbfile_skip(f, 4 + 2 + 2 + 4); dumbfile_getnc((char *)sample->name, 28, f); sample->name[28] = 0; if (type == 0 || sample->length <= 0) { /* Looks like no-existy. Anyway, there's for sure no 'SCRS' ... */ sample->flags &= ~IT_SAMPLE_EXISTS; return dumbfile_error(f); } if (dumbfile_mgetl(f) != DUMB_ID('S', 'C', 'R', 'S')) return -1; sample->global_volume = 64; sample->flags = IT_SAMPLE_EXISTS; if (flags & 1) sample->flags |= IT_SAMPLE_LOOP; /* The ST3 TECH.DOC is unclear on this, but IMAGO Orpheus is not. Piece of * crap. */ if (flags & 2) { sample->flags |= IT_SAMPLE_STEREO; if ((cwtv & 0xF000) == 0x2000) { sample->length >>= 1; sample->loop_start >>= 1; sample->loop_end >>= 1; }
static int it_s3m_read_sample_header(IT_SAMPLE *sample, long *offset, DUMBFILE *f) { unsigned char type; int flags; type = dumbfile_getc(f); if (type > 1) { /** WARNING: no adlib support */ } dumbfile_getnc(sample->filename, 13, f); sample->filename[13] = 0; *offset = dumbfile_igetw(f) << 4; sample->length = dumbfile_igetl(f); sample->loop_start = dumbfile_igetl(f); sample->loop_end = dumbfile_igetl(f); sample->default_volume = dumbfile_getc(f); dumbfile_skip(f, 1); if (dumbfile_getc(f) != 0) /* Sample is packed apparently (or error reading from file). We don't * know how to read packed samples. */ return -1; flags = dumbfile_getc(f); sample->C5_speed = dumbfile_igetl(f) << 1; /* Skip four unused bytes and three internal variables. */ dumbfile_skip(f, 4+2+2+4); dumbfile_getnc(sample->name, 28, f); sample->name[28] = 0; if (type == 0) { /* Looks like no-existy. Anyway, there's for sure no 'SCRS' ... */ sample->flags &= ~IT_SAMPLE_EXISTS; return dumbfile_error(f); } if (dumbfile_mgetl(f) != DUMB_ID('S','C','R','S')) return -1; sample->global_volume = 64; sample->flags = IT_SAMPLE_EXISTS; if (flags & 1) sample->flags |= IT_SAMPLE_LOOP; if (flags & 2) sample->flags |= IT_SAMPLE_STEREO; if (flags & 4) sample->flags |= IT_SAMPLE_16BIT; sample->default_pan = 0; // 0 = don't use, or 160 = centre? if (sample->length <= 0) sample->flags &= ~IT_SAMPLE_EXISTS; else if (sample->flags & IT_SAMPLE_LOOP) { 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; else /* ScreamTracker seems not to save what comes after the loop end * point, but rather to assume it is a duplicate of what comes at * the loop start point. I am not completely sure of this though. * It is easy to evade; simply truncate the sample. */ sample->length = sample->loop_end; } //Do we need to set all these? sample->vibrato_speed = 0; sample->vibrato_depth = 0; sample->vibrato_rate = 0; sample->vibrato_waveform = IT_VIBRATO_SINE; return dumbfile_error(f); }
static DUMB_IT_SIGDATA *it_asy_load_sigdata(DUMBFILE *f) { DUMB_IT_SIGDATA *sigdata; int i; static const char sig_part[] = "ASYLUM Music Format"; static const char sig_rest[] = " V1.0"; /* whee, string space optimization with format type below */ char signature[32]; if (dumbfile_getnc(signature, 32, f) != 32 || memcmp(signature, sig_part, 19) || memcmp(signature + 19, sig_rest, 5)) { return NULL; } sigdata = malloc(sizeof(*sigdata)); if (!sigdata) { return NULL; } sigdata->speed = dumbfile_getc(f); /* XXX seems to fit the files I have */ sigdata->tempo = dumbfile_getc(f); /* ditto */ sigdata->n_samples = dumbfile_getc(f); /* ditto */ sigdata->n_patterns = dumbfile_getc(f); sigdata->n_orders = dumbfile_getc(f); sigdata->restart_position = dumbfile_getc(f); if (dumbfile_error(f) || !sigdata->n_samples || sigdata->n_samples > 64 || !sigdata->n_patterns || !sigdata->n_orders) { free(sigdata); return NULL; } if (sigdata->restart_position > sigdata->n_orders) /* XXX */ sigdata->restart_position = 0; sigdata->order = malloc(sigdata->n_orders); if (!sigdata->order) { free(sigdata); return NULL; } if (dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f) != sigdata->n_orders || dumbfile_skip(f, 256 - sigdata->n_orders)) { free(sigdata->order); free(sigdata); return NULL; } sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); if (!sigdata->sample) { free(sigdata->order); free(sigdata); return NULL; } 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) { if (it_asy_read_sample_header(&sigdata->sample[i], f)) { _dumb_it_unload_sigdata(sigdata); return NULL; } } if (dumbfile_skip(f, 37 * (64 - sigdata->n_samples))) { _dumb_it_unload_sigdata(sigdata); return NULL; } sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); if (!sigdata->pattern) { _dumb_it_unload_sigdata(sigdata); return NULL; } for (i = 0; i < sigdata->n_patterns; ++i) sigdata->pattern[i].entry = NULL; /* Read in the patterns */ { unsigned char *buffer = malloc(64 * 8 * 4); /* 64 rows * 8 channels * 4 bytes */ if (!buffer) { _dumb_it_unload_sigdata(sigdata); return NULL; } for (i = 0; i < sigdata->n_patterns; ++i) { if (it_asy_read_pattern(&sigdata->pattern[i], f, buffer) != 0) { free(buffer); _dumb_it_unload_sigdata(sigdata); return NULL; } } free(buffer); } /* And finally, the sample data */ for (i = 0; i < sigdata->n_samples; ++i) { if (it_asy_read_sample_data(&sigdata->sample[i], f)) { _dumb_it_unload_sigdata(sigdata); return NULL; } } /* Now let's initialise the remaining variables, and we're done! */ sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO; sigdata->global_volume = 128; sigdata->mixing_volume = 48; sigdata->pan_separation = 128; sigdata->n_pchannels = 8; sigdata->name[0] = 0; memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) { int sep = 32 * dumb_it_default_panning_separation / 100; sigdata->channel_pan[i + 0] = 32 - sep; sigdata->channel_pan[i + 1] = 32 + sep; sigdata->channel_pan[i + 2] = 32 + sep; sigdata->channel_pan[i + 3] = 32 - sep; } if (_dumb_it_fix_invalid_orders(sigdata) < 0) { _dumb_it_unload_sigdata(sigdata); return NULL; } return sigdata; }