virtual alure::SharedPtr<alure::Decoder> createDecoder(alure::UniquePtr<std::istream> &file) { static const std::array<DUH*(*)(DUMBFILE*),3> init_funcs{{ dumb_read_it, dumb_read_xm, dumb_read_s3m }}; auto dfs = alure::MakeUnique<DUMBFILE_SYSTEM>(); dfs->open = nullptr; dfs->skip = cb_skip; dfs->getc = cb_read_char; dfs->getnc = cb_read; dfs->close = nullptr; dfs->seek = cb_seek; dfs->get_size = cb_get_size; DUMBFILE *dfile = dumbfile_open_ex(file.get(), dfs.get()); if(!dfile) return nullptr; ALuint freq = alure::Context::GetCurrent()->getDevice()->getFrequency(); DUH_SIGRENDERER *renderer; DUH *duh; for(auto init : init_funcs) { if((duh=init(dfile)) != nullptr) { if((renderer=duh_start_sigrenderer(duh, 0, 2, 0)) != nullptr) return alure::MakeShared<DumbDecoder>( std::move(file), std::move(dfs), dfile, duh, renderer, freq ); unload_duh(duh); duh = nullptr; } dumbfile_seek(dfile, 0, SEEK_SET); } if((duh=dumb_read_mod(dfile, 1)) != nullptr) { if((renderer=duh_start_sigrenderer(duh, 0, 2, 0)) != nullptr) return alure::MakeShared<DumbDecoder>( std::move(file), std::move(dfs), dfile, duh, renderer, freq ); unload_duh(duh); duh = nullptr; } dumbfile_close(dfile); return nullptr; }
static int it_riff_dsmf_process_pattern( IT_PATTERN * pattern, DUMBFILE * f, int len ) { int length, row; unsigned flags; long start, end; int p, q, r; IT_ENTRY * entry; length = dumbfile_igetw( f ); if ( length > len ) return -1; len = length - 2; pattern->n_rows = 64; pattern->n_entries = 64; row = 0; start = dumbfile_pos( f ); end = start + len; while ( (row < 64) && !dumbfile_error( f ) && (dumbfile_pos( f ) < end) ) { p = dumbfile_getc( f ); if ( ! p ) { ++ row; continue; } flags = p & 0xF0; if (flags) { ++ pattern->n_entries; if (flags & 0x80) dumbfile_skip( f, 1 ); if (flags & 0x40) dumbfile_skip( f, 1 ); if (flags & 0x20) dumbfile_skip( f, 1 ); if (flags & 0x10) dumbfile_skip( f, 2 ); } } if ( pattern->n_entries == 64 ) return 0; pattern->entry = malloc( pattern->n_entries * sizeof( * pattern->entry ) ); if ( ! pattern->entry ) return -1; entry = pattern->entry; row = 0; if ( dumbfile_seek( f, start, DFS_SEEK_SET ) ) return -1; while ( ( row < 64 ) && !dumbfile_error( f ) && ( dumbfile_pos( f ) < end ) ) { p = dumbfile_getc( f ); if ( ! p ) { IT_SET_END_ROW( entry ); ++ entry; ++ row; continue; } flags = p; entry->channel = flags & 0x0F; entry->mask = 0; if ( flags & 0xF0 ) { if ( flags & 0x80 ) { q = dumbfile_getc( f ); if ( q ) { entry->mask |= IT_ENTRY_NOTE; entry->note = q - 1; } } if ( flags & 0x40 ) { q = dumbfile_getc( f ); if ( q ) { entry->mask |= IT_ENTRY_INSTRUMENT; entry->instrument = q; } } if ( flags & 0x20 ) { entry->mask |= IT_ENTRY_VOLPAN; entry->volpan = dumbfile_getc( f ); } if ( flags & 0x10 ) { q = dumbfile_getc( f ); r = dumbfile_getc( f ); _dumb_it_xm_convert_effect( q, r, entry, 0 ); } if (entry->mask) entry++; } } while ( row < 64 ) { IT_SET_END_ROW( entry ); ++ entry; ++ row; } pattern->n_entries = entry - pattern->entry; if ( ! pattern->n_entries ) return -1; return 0; }
struct riff *riff_parse(DUMBFILE *f, long offset, long size, unsigned proper) { unsigned stream_size; struct riff *stream; if (size < 8) return 0; if (dumbfile_seek(f, offset, DFS_SEEK_SET)) return 0; if (dumbfile_mgetl(f) != DUMB_ID('R', 'I', 'F', 'F')) return 0; stream_size = (int)dumbfile_igetl(f); if (stream_size + 8 > size) return 0; if (stream_size < 4) return 0; stream = (struct riff *)malloc(sizeof(struct riff)); if (!stream) return 0; stream->type = (int)dumbfile_mgetl(f); stream->chunk_count = 0; stream->chunks = 0; stream_size -= 4; while (stream_size && !dumbfile_error(f)) { struct riff_chunk *chunk; if (stream_size < 8) break; stream->chunks = (struct riff_chunk *)realloc( stream->chunks, (stream->chunk_count + 1) * sizeof(struct riff_chunk)); if (!stream->chunks) break; chunk = stream->chunks + stream->chunk_count; chunk->type = (int)dumbfile_mgetl(f); chunk->size = (int)dumbfile_igetl(f); chunk->offset = dumbfile_pos(f); stream_size -= 8; if (stream_size < chunk->size) break; if (chunk->type == DUMB_ID('R', 'I', 'F', 'F')) { chunk->nested = riff_parse(f, chunk->offset - 8, chunk->size + 8, proper); if (!chunk->nested) break; } else { chunk->nested = 0; } dumbfile_seek(f, chunk->offset + chunk->size, DFS_SEEK_SET); stream_size -= chunk->size; if (proper && (chunk->size & 1)) { dumbfile_skip(f, 1); --stream_size; } ++stream->chunk_count; } if (stream_size) { riff_free(stream); stream = 0; } return stream; }
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; }
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; }