diff --git a/Frameworks/vgmstream/vgmstream/src/coding/tantalus_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/tantalus_decoder.c index deb712ad5..7b03413b1 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/tantalus_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/tantalus_decoder.c @@ -10,7 +10,6 @@ void decode_tantalus(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspac size_t bytes_per_frame, samples_per_frame; int32_t hist1 = stream->adpcm_history1_32; - int32_t hist2 = stream->adpcm_history2_32; /* external interleave (fixed size), mono */ diff --git a/Frameworks/vgmstream/vgmstream/src/formats.c b/Frameworks/vgmstream/vgmstream/src/formats.c index fdfd5b332..a1b983a52 100644 --- a/Frameworks/vgmstream/vgmstream/src/formats.c +++ b/Frameworks/vgmstream/vgmstream/src/formats.c @@ -347,6 +347,7 @@ static const char* extension_list[] = { "mds", "mdsp", "med", + "mhwk", "mjb", "mi4", //fake extension for .mib (renamed, to be removed) "mib", @@ -536,7 +537,7 @@ static const char* extension_list[] = { "skx", "slb", //txth/reserved [THE Nekomura no Hitobito (PS2)] "sli", - "smc", + "smh", "smk", "smp", "smv", @@ -558,6 +559,7 @@ static const char* extension_list[] = { "spsd", "spw", "srsa", + "srcd", "ss2", "ssd", //txth/reserved [Zack & Wiki (Wii)] "ssf", @@ -1253,7 +1255,7 @@ static const meta_info meta_info_list[] = { {meta_LSF_N1NJ4N, "Gizmondo Studios Helsingborg LSF header"}, {meta_XWAV, "feelplus XWAV header"}, {meta_RAW_SNDS, "PC .snds raw header"}, - {meta_HYPERSCAN_KVAG, "Mattel Hyperscan KVAG"}, + {meta_KVAG, "Mattel KVAG header"}, {meta_PSND, "Polarbit PSND header"}, {meta_ADP_WILDFIRE, "Wildfire ADP! header"}, {meta_QD_ADP, "Quantic Dream .ADP header"}, @@ -1479,6 +1481,8 @@ static const meta_info meta_info_list[] = { {meta_AUDIOPKG, "Inevitable .AUDIOPKG header"}, {meta_SWAR, "Nintendo SWAR header"}, {meta_IVB, "Metro IVB header"}, + {meta_SRCD, "Capcom SRCD header"}, + {meta_MHWK, "Broderbund MHWK header"} }; void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) { diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_mxch.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_mxch.c index f15afbcbb..2862f1e18 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_mxch.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_mxch.c @@ -1,22 +1,22 @@ -#include "layout.h" -#include "../vgmstream.h" - -//MxCh blocked layout as used by Lego Island -void block_update_mxch(off_t block_offset, VGMSTREAM * vgmstream) { - vgmstream->current_block_offset = block_offset; - vgmstream->next_block_offset = block_offset + - read_32bitLE(vgmstream->current_block_offset+4,vgmstream->ch[0].streamfile)+8; - /* skip pad blocks */ - while ( - read_32bitBE(vgmstream->current_block_offset, - vgmstream->ch[0].streamfile) == 0x70616420) - { - vgmstream->current_block_offset = vgmstream->next_block_offset; - vgmstream->next_block_offset = vgmstream->current_block_offset + - read_32bitLE(vgmstream->current_block_offset+4,vgmstream->ch[0].streamfile)+8; - } - vgmstream->current_block_size = - read_32bitLE(vgmstream->current_block_offset+4, vgmstream->ch[0].streamfile)-0xe; - // only one channel for now - vgmstream->ch[0].offset = vgmstream->current_block_offset+8+0xe; -} +#include "layout.h" +#include "../vgmstream.h" + +//MxCh blocked layout as used by Lego Island +void block_update_mxch(off_t block_offset, VGMSTREAM * vgmstream) { + vgmstream->current_block_offset = block_offset; + vgmstream->next_block_offset = block_offset + + read_32bitLE(vgmstream->current_block_offset+4,vgmstream->ch[0].streamfile)+8; + /* skip pad blocks */ + while ( + read_32bitBE(vgmstream->current_block_offset, + vgmstream->ch[0].streamfile) == 0x70616420) + { + vgmstream->current_block_offset = vgmstream->next_block_offset; + vgmstream->next_block_offset = vgmstream->current_block_offset + + read_32bitLE(vgmstream->current_block_offset+4,vgmstream->ch[0].streamfile)+8; + } + vgmstream->current_block_size = + read_32bitLE(vgmstream->current_block_offset+4, vgmstream->ch[0].streamfile)-0xe; + // only one channel for now + vgmstream->ch[0].offset = vgmstream->current_block_offset+8+0xe; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/astl.c b/Frameworks/vgmstream/vgmstream/src/meta/astl.c index 6f8098200..aca89892d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/astl.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/astl.c @@ -25,13 +25,13 @@ VGMSTREAM* init_vgmstream_astl(STREAMFILE* sf) { // 28: -1? // 2c: -1? - if (read_u16le(0x30,sf) != 0x0001) // PCM only - return NULL; - channels = read_u16le(0x32, sf); - int sample_rate = read_s32le(0x34,sf); - // 38: bitrate - // 3a: block size - // 3c: bps + // fmt-like + int format = read_u16le(0x30 + 0x00, sf); + channels = read_u16le(0x30 + 0x02, sf); + int sample_rate = read_s32le(0x30 + 0x04, sf); + // 08: avg bitrate + // 0a: block size + // 0e: bps loop_flag = 0; // unlike X360 no apparent loop info in the files @@ -42,11 +42,51 @@ VGMSTREAM* init_vgmstream_astl(STREAMFILE* sf) { vgmstream->meta_type = meta_ASTL; vgmstream->sample_rate = sample_rate; - vgmstream->num_samples = pcm16_bytes_to_samples(data_size, channels); - vgmstream->coding_type = coding_PCM16LE; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x2; + switch(format) { + case 0x0001: + vgmstream->num_samples = pcm16_bytes_to_samples(data_size, channels); + vgmstream->coding_type = coding_PCM16LE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + break; + +#ifdef VGM_USE_FFMPEG + case 0xFFFE: { // WAVEFORMATEXTENSIBLE + uint32_t avg_bitrate = read_u32le(0x30 + 0x08, sf); + uint16_t block_size = read_u16le(0x30 + 0x0c, sf); + uint32_t channel_layout = read_u32le(0x30 + 0x14, sf); + // actually a GUID but first 32b matches fmt (0x0162 / STATIC_KSDATAFORMAT_SUBTYPE_WMAUDIO3 only?) + uint32_t xwma_format = read_u32le(0x30 + 0x18, sf); + + uint32_t dpds_offset = 0x30 + 0x28; + uint32_t dpds_size; + uint32_t offset = dpds_offset; + // TODO channel layout + + vgmstream->codec_data = init_ffmpeg_xwma(sf, start_offset, data_size, xwma_format, channels, sample_rate, avg_bitrate, block_size); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; + + vgmstream->channel_layout = channel_layout; + + // somehow there is no dpds size, so find last value before null padding + while (offset < start_offset) { + uint32_t sample = read_u32le(offset, sf); + if (sample == 0) + break; + offset += 0x04; + } + + dpds_size = offset - dpds_offset; + vgmstream->num_samples = xwma_dpds_get_samples(sf, dpds_offset, dpds_size, channels, false); + break; + } +#endif + default: + goto fail; + } if (!vgmstream_open_stream(vgmstream, sf, start_offset)) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bar.c b/Frameworks/vgmstream/vgmstream/src/meta/bar.c index 636e80020..ecc09cc98 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/bar.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/bar.c @@ -9,7 +9,7 @@ VGMSTREAM * init_vgmstream_bar(STREAMFILE *streamFile) { off_t start_offset; off_t ch2_start_offset; int loop_flag; - int channel_count; + int channel_count; long file_size; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_swvr.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_swvr.c index 6f1ff03a2..e17ce1332 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ea_swvr.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_swvr.c @@ -175,10 +175,10 @@ VGMSTREAM* init_vgmstream_ea_swvr(STREAMFILE* sf) { do { block_update(vgmstream->next_block_offset,vgmstream); switch(vgmstream->coding_type) { - case coding_PSX: num_samples = ps_bytes_to_samples(vgmstream->current_block_size,1); break; - case coding_NGC_DSP: num_samples = dsp_bytes_to_samples(vgmstream->current_block_size,1); break; + case coding_PSX: num_samples = ps_bytes_to_samples(vgmstream->current_block_size,1); break; + case coding_NGC_DSP: num_samples = dsp_bytes_to_samples(vgmstream->current_block_size,1); break; case coding_PCM8_U_int: num_samples = pcm_bytes_to_samples(vgmstream->current_block_size,1,8); break; - default: num_samples = 0; break; + default: num_samples = 0; break; } vgmstream->num_samples += num_samples; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb5_fev.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb5_fev.c index ce2005140..2e30763f9 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb5_fev.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb5_fev.c @@ -50,11 +50,18 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) { goto fail; switch(chunk_type) { - case 0x4C495354: /* "LIST" with "SNDH" (usually v0x28 but also in Fall Guys's BNK_Music_RoundReveal) */ - if (read_u32be(offset + 0x04, sf) == 0x534E4448) { + case 0x4C495354: /* "LIST" */ + // "SNDH" (usually v0x28 but also in Fall Guys's BNK_Music_RoundReveal) + if (read_u32be(offset + 0x04, sf) == get_id32be("SNDH")) { bank_offset = offset + 0x0c; bank_size = read_s32le(offset + 0x08,sf); } + + // multiple CrankcaseAudio REV ADM3 [Rennsport (PC)] + if (read_u32be(offset + 0x00, sf) == get_id32be("PEFX")) { + bank_offset = offset; + bank_size = chunk_size; + } break; case 0x534E4448: /* "SNDH" */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h index d6961f354..f1f48552d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h @@ -1572,6 +1572,9 @@ static const hcakey_info hcakey_list[] = { // Sand Land (multi) {910990237314908160}, // 0CA47CCB51010000 + // Patapon 1 & 2 Reloaded (PC) + {3316332033470531258}, // 2E05FA69EC4286BA + }; #endif diff --git a/Frameworks/vgmstream/vgmstream/src/meta/idsp_ie.c b/Frameworks/vgmstream/vgmstream/src/meta/idsp_ie.c index 30fccc323..8b5bd52a7 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/idsp_ie.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/idsp_ie.c @@ -1,44 +1,45 @@ -#include "meta.h" -#include "../coding/coding.h" - - -/* IDSP - from Inevitable Entertainment games [Defender (GC)] */ -VGMSTREAM * init_vgmstream_idsp_ie(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset; - int loop_flag, channel_count; - - - /* checks */ - if ( !check_extensions(streamFile,"idsp") ) - goto fail; - if (read_32bitBE(0x00,streamFile) != 0x49445350) /* "IDSP" */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitBE(0x0C,streamFile); - if (channel_count > 2) goto fail; - start_offset = 0x70; - - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - vgmstream->meta_type = meta_IDSP_IE; - vgmstream->sample_rate = read_32bitBE(0x08,streamFile); - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->num_samples = dsp_bytes_to_samples(read_32bitBE(0x04,streamFile), channel_count); - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitBE(0x10,streamFile); - dsp_read_coefs_be(vgmstream,streamFile,0x14,0x2E); - - if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} +#include "meta.h" +#include "../coding/coding.h" + + +/* IDSP - from Inevitable Entertainment games [Defender (GC)] */ +VGMSTREAM* init_vgmstream_idsp_ie(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + off_t start_offset; + int loop_flag, channels; + + + /* checks */ + if (!is_id32be(0x00, sf, "IDSP")) + return NULL; + if (!check_extensions(sf,"idsp")) + return NULL; + + channels = read_s32be(0x0C,sf); + if (channels > 2) return NULL; + + loop_flag = 0; + start_offset = 0x70; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_IDSP_IE; + vgmstream->sample_rate = read_s32be(0x08,sf); + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = dsp_bytes_to_samples(read_u32be(0x04,sf), channels); + + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_u32be(0x10,sf); + dsp_read_coefs_be(vgmstream, sf, 0x14, 0x2E); + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/imc.c b/Frameworks/vgmstream/vgmstream/src/meta/imc.c index 3ac6d6e42..fb79e924e 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/imc.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/imc.c @@ -1,115 +1,113 @@ -#include "meta.h" -#include "../coding/coding.h" - -/* .IMC - from iNiS Gitaroo Man (PS2) */ -VGMSTREAM * init_vgmstream_imc(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset; - int loop_flag, channel_count, sample_rate, interleave, blocks; - size_t file_size, data_size; - - - /* checks */ - /* .imc: extension from the main container */ - if (!check_extensions(streamFile, "imc")) - goto fail; - - channel_count = read_32bitLE(0x00, streamFile); - sample_rate = read_32bitLE(0x04, streamFile); - interleave = read_32bitLE(0x08, streamFile) * 0x10; /* number of frames in a block */ - blocks = read_32bitLE(0x0c, streamFile); /* number of interleave blocks (even in mono) */ - - file_size = get_streamfile_size(streamFile); - loop_flag = 0; - start_offset = 0x10; - - /* extra checks since the header is so simple */ - if (channel_count < 1 || channel_count > 8) - goto fail; - if (sample_rate < 11025 || sample_rate > 48000) - /* game can play 11025, 16000, 22050, 32000, 44100, 48000. Anything else will be - silent in-game. ST10.IMC subsongs 42-47 use 22000, those are unused silent audio */ - goto fail; - if (interleave*blocks + start_offset != file_size) - goto fail; - - data_size = file_size - start_offset; - data_size -= ps_find_padding(streamFile, start_offset, data_size, channel_count, interleave, 0); - - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count, loop_flag); - if (!vgmstream) goto fail; - - vgmstream->meta_type = meta_IMC; - vgmstream->sample_rate = sample_rate; - vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count); - vgmstream->coding_type = coding_PSX; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = interleave; - - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} - -/* ****************************************************************************** */ - -/* .IMC in containers */ -VGMSTREAM * init_vgmstream_imc_container(STREAMFILE *streamFile) { - VGMSTREAM *vgmstream = NULL; - STREAMFILE *temp_streamFile = NULL; - off_t header_offset, subfile_offset, next_offset, name_offset; - size_t subfile_size; - int total_subsongs, target_subsong = streamFile->stream_index; - - - /* checks */ - if (!check_extensions(streamFile, "imc")) - goto fail; - - total_subsongs = read_32bitLE(0x00, streamFile); - if (target_subsong == 0) target_subsong = 1; - if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; - - - header_offset = 0x04 + 0x20*(target_subsong-1); - - name_offset = header_offset + 0x00; - /* 0x08: flags? (0x702ADE77|0x002ADE77|0x20000000|etc) */ - /* 0x0c: same for all songs in single .imc but varies between .imc */ - subfile_offset = read_32bitLE(header_offset + 0x10,streamFile); - /* 0x14: flags/size? (0xF0950000|0x3CFA1200|etc) */ - /* 0x18: same for all songs in single .imc but varies between .imc */ - /* 0x1c: flags? (0 or 2) */ - - if (target_subsong == total_subsongs) { - next_offset = get_streamfile_size(streamFile); - } - else { - next_offset = read_32bitLE(header_offset + 0x20 + 0x10,streamFile); - } - subfile_size = next_offset - subfile_offset; - - - temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL); - if (!temp_streamFile) goto fail; - - vgmstream = init_vgmstream_imc(temp_streamFile); - if (!vgmstream) goto fail; - - close_streamfile(temp_streamFile); - vgmstream->num_streams = total_subsongs; - read_string(vgmstream->stream_name,0x08+1, name_offset,streamFile); - - return vgmstream; - -fail: - close_streamfile(temp_streamFile); - close_vgmstream(vgmstream); - return NULL; -} +#include "meta.h" +#include "../coding/coding.h" + +/* .IMC (subfile) - from iNiS Gitaroo Man (PS2) */ +VGMSTREAM* init_vgmstream_imc(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + + /* checks */ + /* .imc: extension from the main container */ + if (!check_extensions(sf, "imc")) + return NULL; + + int channels = read_s32le(0x00, sf); + int sample_rate = read_s32le(0x04, sf); + int interleave = read_s32le(0x08, sf) * 0x10; // number of frames in a block + int blocks = read_s32le(0x0c, sf); // number of interleave blocks (even in mono) + + uint32_t start_offset = 0x10; + uint32_t file_size = get_streamfile_size(sf); + bool loop_flag = false; + + // extra checks since the header is so simple + if (channels < 1 || channels > 8) + return NULL; + + // Game can play 11025, 16000, 22050, 32000, 44100, 48000. Anything else will be + // silent in-game. ST10.IMC subsongs 42-47 use 22000, those are unused silent audio + if (sample_rate < 11025 || sample_rate > 48000) + return NULL; + + if (interleave * blocks + start_offset != file_size) + return NULL; + + uint32_t data_size = file_size - start_offset; + data_size -= ps_find_padding(sf, start_offset, data_size, channels, interleave, 0); + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_IMC; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = ps_bytes_to_samples(data_size, channels); + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + +/* ****************************************************************************** */ + +/* .IMC in containers */ +VGMSTREAM* init_vgmstream_imc_container(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + STREAMFILE* temp_sf = NULL; + off_t header_offset, subfile_offset, next_offset, name_offset; + size_t subfile_size; + int total_subsongs, target_subsong = sf->stream_index; + + + /* checks */ + if (!check_extensions(sf, "imc")) + return NULL; + + total_subsongs = read_s32le(0x00, sf); + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; + + + header_offset = 0x04 + 0x20 * (target_subsong - 1); + + name_offset = header_offset + 0x00; + /* 0x08: flags? (0x702ADE77|0x002ADE77|0x20000000|etc) */ + /* 0x0c: same for all songs in single .imc but varies between .imc */ + subfile_offset = read_u32le(header_offset + 0x10,sf); + /* 0x14: flags/size? (0xF0950000|0x3CFA1200|etc) */ + /* 0x18: same for all songs in single .imc but varies between .imc */ + /* 0x1c: flags? (0 or 2) */ + + if (target_subsong == total_subsongs) { + next_offset = get_streamfile_size(sf); + } + else { + next_offset = read_u32le(header_offset + 0x20 + 0x10,sf); + } + subfile_size = next_offset - subfile_offset; + + + temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, NULL); + if (!temp_sf) goto fail; + + vgmstream = init_vgmstream_imc(temp_sf); + if (!vgmstream) goto fail; + + vgmstream->num_streams = total_subsongs; + read_string(vgmstream->stream_name,0x08+1, name_offset,sf); + + close_streamfile(temp_sf); + return vgmstream; + +fail: + close_streamfile(temp_sf); + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/kvag.c b/Frameworks/vgmstream/vgmstream/src/meta/kvag.c new file mode 100644 index 000000000..f1a7e7506 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/kvag.c @@ -0,0 +1,32 @@ +#include "meta.h" +#include "../util/meta_utils.h" + +/* KVAG - Mattel Hyperscan games [Marvel Heroes (Hyperscan), X-Men (Hyperscan)] */ +VGMSTREAM* init_vgmstream_hyperscan_kvag(STREAMFILE* sf) { + + /* checks */ + if (!is_id32be(0x00,sf, "KVAG")) + return NULL; + if (!check_extensions(sf,"bvg")) + return NULL; + + meta_header_t h = {0}; + h.meta = meta_KVAG; + + h.stream_size = read_u32le(0x04, sf); + h.sample_rate = read_s32le(0x08, sf); + h.channels = read_s16le(0x0c, sf) + 1; + h.stream_offset = 0x0e; + + if (h.channels > 2) // 2ch is rare [Ben 10's Theme22ks] + return NULL; + + h.num_samples = ima_bytes_to_samples(h.stream_size, h.channels); + + h.coding = coding_DVI_IMA; + h.layout = layout_none; + h.open_stream = true; + h.sf = sf; + + return alloc_metastream(&h); +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mattel_hyperscan.c b/Frameworks/vgmstream/vgmstream/src/meta/mattel_hyperscan.c deleted file mode 100644 index 1601be8f0..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/mattel_hyperscan.c +++ /dev/null @@ -1,66 +0,0 @@ -#include "meta.h" -#include "../util.h" - -/* Mattel Hyperscan, -- Place all metas for this console here (there are just 5 games) */ -VGMSTREAM * init_vgmstream_hyperscan_kvag(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - int loop_flag = 0; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("bvg",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x4B564147) /* "KVAG" */ - goto fail; - - channel_count = 1; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0xE; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x8,streamFile); - vgmstream->coding_type = coding_DVI_IMA; - vgmstream->num_samples = read_32bitLE(0x4,streamFile)*2; - -#if 0 - if (loop_flag) { - vgmstream->loop_start_sample = (read_32bitLE(0x08,streamFile)-1)*28; - vgmstream->loop_end_sample = (read_32bitLE(0x0c,streamFile)-1)*28; - } -#endif - - vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_HYPERSCAN_KVAG; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/maxis_xa.c b/Frameworks/vgmstream/vgmstream/src/meta/maxis_xa.c index a3d421349..4e7fcdfed 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/maxis_xa.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/maxis_xa.c @@ -1,58 +1,54 @@ -#include "meta.h" -#include "../util.h" - -/* Maxis XA - found in Sim City 3000 (PC), The Sims 2 (PC) */ -VGMSTREAM * init_vgmstream_maxis_xa(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset; - int avg_byte_rate, channel_count, loop_flag, resolution, sample_align, sample_rate; - - /* check extension, case insensitive */ - if (!check_extensions(streamFile,"xa")) - goto fail; - - /* check header */ - if ((read_16bitBE(0x00,streamFile) != 0x5841)) /* "XA" */ - goto fail; - - /* check format tag */ - if ((read_16bitLE(0x08,streamFile) != 0x0001)) - goto fail; - - channel_count = read_16bitLE(0x0A,streamFile); - sample_rate = read_32bitLE(0x0C,streamFile); - avg_byte_rate = read_32bitLE(0x10,streamFile); - sample_align = read_16bitLE(0x14,streamFile); - resolution = read_16bitLE(0x16,streamFile); - - /* check alignment */ - if (sample_align != (resolution/8)*channel_count) - goto fail; - - /* check average byte rate */ - if (avg_byte_rate != sample_rate*sample_align) - goto fail; - - loop_flag = 0; - start_offset = 0x18; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - vgmstream->sample_rate = sample_rate; - vgmstream->num_samples = read_32bitLE(0x04,streamFile)/2/channel_count; - - vgmstream->meta_type = meta_MAXIS_XA; - vgmstream->coding_type = coding_MAXIS_XA; - vgmstream->layout_type = layout_none; - - /* open streams */ - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} +#include "meta.h" +#include "../util.h" + +/* Maxis XA - found in Sim City 3000 (PC), The Sims 2 (PC) */ +VGMSTREAM* init_vgmstream_maxis_xa(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + + /* checks */ + if ((read_u32be(0x00,sf) & 0xFFFF0000) != get_id32be("XA\0\0")) // 02: "I"/"J"/null (version?) + return NULL; + + uint32_t pcm_size = read_u32le(0x04,sf); + if (read_u16le(0x08,sf) != 0x0001) + return NULL; + + if (!check_extensions(sf,"xa")) + return NULL; + + int channels = read_s16le(0x0A,sf); + int sample_rate = read_s32le(0x0C,sf); + int avg_byte_rate = read_s32le(0x10,sf); + int sample_align = read_u16le(0x14,sf); + int resolution = read_u16le(0x16,sf); + + /* check alignment */ + if (sample_align != (resolution / 8) * channels) + return NULL; + + /* check average byte rate */ + if (avg_byte_rate != sample_rate * sample_align) + return NULL; + + off_t start_offset = 0x18; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, false); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = pcm_size / sizeof(short) / channels; + + vgmstream->meta_type = meta_MAXIS_XA; + vgmstream->coding_type = coding_MAXIS_XA; + vgmstream->layout_type = layout_none; + + /* open streams */ + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h index f503f1c81..668a37f2c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -701,7 +701,7 @@ VGMSTREAM * init_vgmstream_msb_msh(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_txtp(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_smc_smh(STREAMFILE * streamFile); +VGMSTREAM* init_vgmstream_smh_smc(STREAMFILE* sf); VGMSTREAM * init_vgmstream_ppst(STREAMFILE *streamFile); @@ -1035,4 +1035,8 @@ VGMSTREAM* init_vgmstream_swar(STREAMFILE* sf); VGMSTREAM* init_vgmstream_ivb(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_mhwk(STREAMFILE* sf); + +VGMSTREAM* init_vgmstream_srcd(STREAMFILE* sf); + #endif diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mhwk.c b/Frameworks/vgmstream/vgmstream/src/meta/mhwk.c new file mode 100644 index 000000000..f85f452db --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/mhwk.c @@ -0,0 +1,104 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* MHWK - Broderbund's Mohawk engine (.mhk) */ +VGMSTREAM* init_vgmstream_mhwk(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + off_t start_offset = 0; + int loop_flag = 0, channels = 0, sample_rate = 0, format = 0; + int32_t num_samples = 0, loop_start = 0, loop_end = 0; + off_t current_offset; + uint32_t chunk_id; + uint32_t chunk_size; + + /* Check for MHWK magic word */ + if (!is_id32be(0x00, sf, "MHWK")) + return NULL; + + if (!check_extensions(sf, "mhk")) + return NULL; + + /* Check for WAVE magic word, which follows the MHWK header */ + if (!is_id32be(0x08, sf, "WAVE")) + goto fail; + + current_offset = 0x0C; + + while (current_offset < get_streamfile_size(sf)) { + chunk_id = read_u32be(current_offset, sf); + chunk_size = read_u32be(current_offset + 0x04, sf); + current_offset += 0x08; + + if (chunk_id == get_id32be("Cue#")) { + current_offset += chunk_size; + continue; + } + else if (chunk_id == get_id32be("ADPC")) { + current_offset += chunk_size; + continue; + } + else if (chunk_id == get_id32be("Data")) { + break; + } + else { + goto fail; + } + } + + /* Data chunk header */ + + /* Header size is consistently 20 bytes from analysis */ + sample_rate = read_u16be(current_offset + 0x00, sf); + num_samples = read_u32be(current_offset + 0x02, sf); + /* 0x06: sample width (1 byte), 0x07: channels (1 byte) */ + channels = read_u8(current_offset + 0x07, sf); + format = read_u16be(current_offset + 0x08, sf); + + if (read_u16be(current_offset + 0x0A, sf) == 0xFFFF) { + loop_flag = 1; + loop_start = read_u32be(current_offset + 0x0C, sf); + loop_end = read_u32be(current_offset + 0x10, sf); + } + + /* The actual audio data starts after the header's 20 bytes not 28 bytes */ + start_offset = current_offset + 0x14; + + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) + goto fail; + + vgmstream->meta_type = meta_MHWK; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = num_samples; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; + + /* Determine coding type based on format ID */ + switch (format) { + + //Myst 1993 + case 0x0000: /* 8-bit unsigned PCM. Default */ + vgmstream->coding_type = coding_PCM8_U; + vgmstream->layout_type = layout_interleave; // Usually mono. + vgmstream->interleave_block_size = 0x01; + break; + + //Carmen Sandiego: Word Detective + case 0x0001: /* IMA ADPCM */ + vgmstream->coding_type = coding_IMA; + vgmstream->layout_type = layout_none; + break; + + default: /* Unknown format */ + goto fail; + } + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mp4_faac.c b/Frameworks/vgmstream/vgmstream/src/meta/mp4_faac.c index 2ba769d83..a22050d6c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/mp4_faac.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/mp4_faac.c @@ -7,37 +7,37 @@ static VGMSTREAM* init_vgmstream_mp4_aac_offset(STREAMFILE* sf, uint64_t start, uint64_t size); VGMSTREAM* init_vgmstream_mp4_aac(STREAMFILE* sf) { - return init_vgmstream_mp4_aac_offset( sf, 0x00, get_streamfile_size(sf)); + return init_vgmstream_mp4_aac_offset( sf, 0x00, get_streamfile_size(sf)); } static VGMSTREAM* init_vgmstream_mp4_aac_offset(STREAMFILE* sf, uint64_t start, uint64_t size) { - VGMSTREAM* vgmstream = NULL; - mp4_aac_codec_data* data = NULL; + VGMSTREAM* vgmstream = NULL; + mp4_aac_codec_data* data = NULL; - data = init_mp4_aac(sf); - if (!data) goto fail; + data = init_mp4_aac(sf); + if (!data) goto fail; - int channels = mp4_aac_get_channels(data); + int channels = mp4_aac_get_channels(data); - vgmstream = allocate_vgmstream(channels, 0); - if (!vgmstream) goto fail; + vgmstream = allocate_vgmstream(channels, 0); + if (!vgmstream) goto fail; - vgmstream->sample_rate = mp4_aac_get_sample_rate(data); - vgmstream->num_samples = mp4_aac_get_samples(data); + vgmstream->sample_rate = mp4_aac_get_sample_rate(data); + vgmstream->num_samples = mp4_aac_get_samples(data); - vgmstream->codec_data = data; - vgmstream->coding_type = coding_MP4_AAC; + vgmstream->codec_data = data; + vgmstream->coding_type = coding_MP4_AAC; - vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_MP4; + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_MP4; - return vgmstream; + return vgmstream; fail: free_mp4_aac(data); if (vgmstream) { vgmstream->codec_data = NULL; close_vgmstream(vgmstream); } - return NULL; + return NULL; } #endif diff --git a/Frameworks/vgmstream/vgmstream/src/meta/pc_mxst.c b/Frameworks/vgmstream/vgmstream/src/meta/pc_mxst.c index c33cfc268..c3699e497 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/pc_mxst.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/pc_mxst.c @@ -1,218 +1,218 @@ -//MxSt files ripped from Jukebox.si in Lego Island -#include "meta.h" -#include "../layout/layout.h" -#include "../util.h" - -VGMSTREAM * init_vgmstream_pc_mxst(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - int loop_flag=0; - int bits_per_sample; - int channel_count; - int sample_rate,bytes_per_second; - long sample_count; - int i; - off_t file_size; - off_t chunk_list_size=-1; - off_t start_offset; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("mxst",filename_extension(filename))) goto fail; - - /* looping info not found yet */ - //loop_flag = get_streamfile_size(streamFile) > 700000; - - /* check MxSt header */ - if (0x4d785374 != read_32bitBE(0, streamFile)) goto fail; - file_size = read_32bitLE(4, streamFile) + 8; - if (file_size != get_streamfile_size(streamFile)) goto fail; - - /* read chunks */ - { - off_t MxDa=-1; /* points inside the MxDa chunk */ - off_t MxCh=-1; /* point at start of the first MxCh chunk */ - off_t chunk_offset = 8; - uint32_t stream_id; - while (chunk_offset < file_size) - { - uint32_t chunk_size = (read_32bitLE(chunk_offset+4, streamFile)+1)/2*2; - switch (read_32bitBE(chunk_offset, streamFile)) - { - case 0x4d784f62: /* MxOb */ - /* not interesting for playback */ - break; - case 0x20574156: /* " WAV" */ - if (chunk_size == 1) - chunk_size = 8; - break; - case 0x4c495354: /* LIST */ - { - off_t first_item_offset = chunk_offset+0x14; - off_t list_chunk_offset = first_item_offset+ - read_32bitLE(chunk_offset+0x10,streamFile); - - if (read_32bitBE(chunk_offset+0x8,streamFile) == 0x4d784461) /* MxDa */ - MxDa = first_item_offset; - else - goto fail; - - if (read_32bitBE(chunk_offset+0xC,streamFile) == - 0x4d784368) /* MxCh */ - { - MxCh = list_chunk_offset; - chunk_list_size = chunk_size - (list_chunk_offset-(chunk_offset+8)); - } - else - goto fail; - - break; - } - default: - goto fail; - } - - chunk_offset += 8 + chunk_size; - if (chunk_offset > file_size) goto fail; - } - - if (MxDa == -1 || MxCh == -1 || chunk_list_size == -1) goto fail; - - /* parse MxDa */ - { - /* ??? */ - if (0 != read_16bitLE(MxDa+0x00,streamFile)) goto fail; - stream_id = read_32bitLE(MxDa+0x2,streamFile); - /* First sample (none in MxDa block) */ - if (-1 != read_32bitLE(MxDa+0x06,streamFile)) goto fail; - /* size of format data */ - if (0x18 != read_32bitLE(MxDa+0x0a,streamFile)) goto fail; - /* PCM */ - if (1 != read_16bitLE(MxDa+0x0e,streamFile)) goto fail; - /* channel count */ - channel_count = read_16bitLE(MxDa+0x10,streamFile); - /* only mono known */ - if (1 != channel_count) goto fail; - sample_rate = read_32bitLE(MxDa+0x12,streamFile); - bits_per_sample = read_16bitLE(MxDa+0x1c,streamFile); - /* bytes per second */ - bytes_per_second = read_32bitLE(MxDa+0x16,streamFile); - if (bits_per_sample/8*channel_count*sample_rate != bytes_per_second) goto fail; - /* block align */ - if (bits_per_sample/8*channel_count != - read_16bitLE(MxDa+0x1a,streamFile)) goto fail; - sample_count = read_32bitLE(MxDa+0x1e,streamFile)/(bits_per_sample/8)/channel_count; - /* 2c? data offset in normal RIFF WAVE? */ - if (0x2c != read_32bitLE(MxDa+0x22,streamFile)) goto fail; - } - - /* parse through all MxCh for consistency check */ - { - long samples = 0; - int split_frames_seen = 0; - off_t MxCh_offset = MxCh; - while (MxCh_offset < MxCh+chunk_list_size) - { - uint16_t flags; - if (read_32bitBE(MxCh_offset,streamFile)!=0x70616420) /*pad*/ - { - if (read_32bitBE(MxCh_offset,streamFile)!=0x4d784368) /*MxCh*/ - goto fail; - - flags = read_16bitLE(MxCh_offset+8+0,streamFile); - - if (read_32bitLE(MxCh_offset+8+2,streamFile)!=stream_id) - goto fail; - - if (flags & 0x10) - { - split_frames_seen ++; - if (split_frames_seen == 1) - { - if (read_32bitLE(MxCh_offset+8+6,streamFile)!=(samples*UINT64_C(1000)+sample_rate-1)/sample_rate) - goto fail; - } - else if (split_frames_seen == 2) - { - if ( read_32bitLE(MxCh_offset+8+0xa,streamFile)!= - read_32bitLE(MxCh_offset+4,streamFile)-0xe ) goto fail; - split_frames_seen = 0; - } - else goto fail; - } - - if (!(flags & 0x10)) - { - if (split_frames_seen != 0) - { - goto fail; - } - if (read_32bitLE(MxCh_offset+8+6,streamFile)!=(samples*UINT64_C(1000)+sample_rate-1)/sample_rate) - goto fail; - - if ( read_32bitLE(MxCh_offset+8+0xa,streamFile)!= - read_32bitLE(MxCh_offset+4,streamFile)-0xe ) goto fail; - } - samples += (read_32bitLE(MxCh_offset+4,streamFile)-0xe)/(bits_per_sample/8/channel_count); - - } - MxCh_offset += 8 + (read_32bitLE(MxCh_offset+4,streamFile)+1)/2*2; - if (MxCh_offset > MxCh+chunk_list_size) goto fail; - } - //printf("samples=%d sample_count=%d\n",samples,sample_count); - //samples = (samples * (bits_per_sample/8) * channel_count + 31)/32*32/(bits_per_sample/8)/channel_count; - if (samples < sample_count) - { - sample_count = samples; - } - if (samples != sample_count) goto fail; - } - - start_offset = MxCh; - } - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->channels = channel_count; - vgmstream->sample_rate = sample_rate; - vgmstream->layout_type = layout_blocked_mxch; - - vgmstream->meta_type = meta_PC_MXST; - if(bits_per_sample == 8) - { - vgmstream->coding_type = coding_PCM8_U; - } - else if (bits_per_sample == 16) - { - vgmstream->coding_type = coding_PCM16LE; - } - else goto fail; - vgmstream->num_samples = sample_count; - if(loop_flag) - { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample=vgmstream->num_samples; - } - /* open the file for reading by each channel */ - { - for (i=0;ich[i].streamfile = - streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - - if (!vgmstream->ch[i].streamfile) goto fail; - } - - } - block_update_mxch(start_offset, vgmstream); - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} +//MxSt files ripped from Jukebox.si in Lego Island +#include "meta.h" +#include "../layout/layout.h" +#include "../util.h" + +VGMSTREAM * init_vgmstream_pc_mxst(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[PATH_LIMIT]; + + int loop_flag=0; + int bits_per_sample; + int channel_count; + int sample_rate,bytes_per_second; + long sample_count; + int i; + off_t file_size; + off_t chunk_list_size=-1; + off_t start_offset; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("mxst",filename_extension(filename))) goto fail; + + /* looping info not found yet */ + //loop_flag = get_streamfile_size(streamFile) > 700000; + + /* check MxSt header */ + if (0x4d785374 != read_32bitBE(0, streamFile)) goto fail; + file_size = read_32bitLE(4, streamFile) + 8; + if (file_size != get_streamfile_size(streamFile)) goto fail; + + /* read chunks */ + { + off_t MxDa=-1; /* points inside the MxDa chunk */ + off_t MxCh=-1; /* point at start of the first MxCh chunk */ + off_t chunk_offset = 8; + uint32_t stream_id; + while (chunk_offset < file_size) + { + uint32_t chunk_size = (read_32bitLE(chunk_offset+4, streamFile)+1)/2*2; + switch (read_32bitBE(chunk_offset, streamFile)) + { + case 0x4d784f62: /* MxOb */ + /* not interesting for playback */ + break; + case 0x20574156: /* " WAV" */ + if (chunk_size == 1) + chunk_size = 8; + break; + case 0x4c495354: /* LIST */ + { + off_t first_item_offset = chunk_offset+0x14; + off_t list_chunk_offset = first_item_offset+ + read_32bitLE(chunk_offset+0x10,streamFile); + + if (read_32bitBE(chunk_offset+0x8,streamFile) == 0x4d784461) /* MxDa */ + MxDa = first_item_offset; + else + goto fail; + + if (read_32bitBE(chunk_offset+0xC,streamFile) == + 0x4d784368) /* MxCh */ + { + MxCh = list_chunk_offset; + chunk_list_size = chunk_size - (list_chunk_offset-(chunk_offset+8)); + } + else + goto fail; + + break; + } + default: + goto fail; + } + + chunk_offset += 8 + chunk_size; + if (chunk_offset > file_size) goto fail; + } + + if (MxDa == -1 || MxCh == -1 || chunk_list_size == -1) goto fail; + + /* parse MxDa */ + { + /* ??? */ + if (0 != read_16bitLE(MxDa+0x00,streamFile)) goto fail; + stream_id = read_32bitLE(MxDa+0x2,streamFile); + /* First sample (none in MxDa block) */ + if (-1 != read_32bitLE(MxDa+0x06,streamFile)) goto fail; + /* size of format data */ + if (0x18 != read_32bitLE(MxDa+0x0a,streamFile)) goto fail; + /* PCM */ + if (1 != read_16bitLE(MxDa+0x0e,streamFile)) goto fail; + /* channel count */ + channel_count = read_16bitLE(MxDa+0x10,streamFile); + /* only mono known */ + if (1 != channel_count) goto fail; + sample_rate = read_32bitLE(MxDa+0x12,streamFile); + bits_per_sample = read_16bitLE(MxDa+0x1c,streamFile); + /* bytes per second */ + bytes_per_second = read_32bitLE(MxDa+0x16,streamFile); + if (bits_per_sample/8*channel_count*sample_rate != bytes_per_second) goto fail; + /* block align */ + if (bits_per_sample/8*channel_count != + read_16bitLE(MxDa+0x1a,streamFile)) goto fail; + sample_count = read_32bitLE(MxDa+0x1e,streamFile)/(bits_per_sample/8)/channel_count; + /* 2c? data offset in normal RIFF WAVE? */ + if (0x2c != read_32bitLE(MxDa+0x22,streamFile)) goto fail; + } + + /* parse through all MxCh for consistency check */ + { + long samples = 0; + int split_frames_seen = 0; + off_t MxCh_offset = MxCh; + while (MxCh_offset < MxCh+chunk_list_size) + { + uint16_t flags; + if (read_32bitBE(MxCh_offset,streamFile)!=0x70616420) /*pad*/ + { + if (read_32bitBE(MxCh_offset,streamFile)!=0x4d784368) /*MxCh*/ + goto fail; + + flags = read_16bitLE(MxCh_offset+8+0,streamFile); + + if (read_32bitLE(MxCh_offset+8+2,streamFile)!=stream_id) + goto fail; + + if (flags & 0x10) + { + split_frames_seen ++; + if (split_frames_seen == 1) + { + if (read_32bitLE(MxCh_offset+8+6,streamFile)!=(samples*UINT64_C(1000)+sample_rate-1)/sample_rate) + goto fail; + } + else if (split_frames_seen == 2) + { + if ( read_32bitLE(MxCh_offset+8+0xa,streamFile)!= + read_32bitLE(MxCh_offset+4,streamFile)-0xe ) goto fail; + split_frames_seen = 0; + } + else goto fail; + } + + if (!(flags & 0x10)) + { + if (split_frames_seen != 0) + { + goto fail; + } + if (read_32bitLE(MxCh_offset+8+6,streamFile)!=(samples*UINT64_C(1000)+sample_rate-1)/sample_rate) + goto fail; + + if ( read_32bitLE(MxCh_offset+8+0xa,streamFile)!= + read_32bitLE(MxCh_offset+4,streamFile)-0xe ) goto fail; + } + samples += (read_32bitLE(MxCh_offset+4,streamFile)-0xe)/(bits_per_sample/8/channel_count); + + } + MxCh_offset += 8 + (read_32bitLE(MxCh_offset+4,streamFile)+1)/2*2; + if (MxCh_offset > MxCh+chunk_list_size) goto fail; + } + //printf("samples=%d sample_count=%d\n",samples,sample_count); + //samples = (samples * (bits_per_sample/8) * channel_count + 31)/32*32/(bits_per_sample/8)/channel_count; + if (samples < sample_count) + { + sample_count = samples; + } + if (samples != sample_count) goto fail; + } + + start_offset = MxCh; + } + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = sample_rate; + vgmstream->layout_type = layout_blocked_mxch; + + vgmstream->meta_type = meta_PC_MXST; + if(bits_per_sample == 8) + { + vgmstream->coding_type = coding_PCM8_U; + } + else if (bits_per_sample == 16) + { + vgmstream->coding_type = coding_PCM16LE; + } + else goto fail; + vgmstream->num_samples = sample_count; + if(loop_flag) + { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample=vgmstream->num_samples; + } + /* open the file for reading by each channel */ + { + for (i=0;ich[i].streamfile = + streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + + if (!vgmstream->ch[i].streamfile) goto fail; + } + + } + block_update_mxch(start_offset, vgmstream); + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps_headerless.c b/Frameworks/vgmstream/vgmstream/src/meta/ps_headerless.c index 1ba21a185..9849d2197 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps_headerless.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ps_headerless.c @@ -1,256 +1,256 @@ -#include "meta.h" -#include "../coding/coding.h" - - -/* Headerless PS-ADPCM - * Guesses interleave/channels/loops by testing data and using the file extension for sample rate. - * This is an ugly crutch for older sets, use TXTH to properly play headerless data instead. */ -VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset = 0x00; - char filename[PATH_LIMIT]; - - uint8_t mibBuffer[0x10]; - uint8_t testBuffer[0x10]; - - size_t fileLength; - off_t loopStart = 0; - off_t loopEnd = 0; - off_t interleave = 0; - - off_t readOffset = 0; - - off_t loopStartPoints[0x10] = {0}; - int loopStartPointsCount=0; - off_t loopEndPoints[0x10] = {0}; - int loopEndPointsCount=0; - int loopToEnd=0; - int forceNoLoop=0; - int gotEmptyLine=0; - - int i, channel_count=0; - - - /* checks - * .mib: common, but many ext-less files are renamed to this. - * .mi4: fake .mib to force another sample rate */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("mib",filename_extension(filename)) && - strcasecmp("mi4",filename_extension(filename))) - goto fail; - - /* test if raw PS-ADPCM */ - if (!ps_check_format(streamFile, 0x00, 0x2000)) - goto fail; - - - fileLength = get_streamfile_size(streamFile); - - /* Search for interleave value (checking channel starts) and loop points (using PS-ADPCM flags). - * Channel start will by 0x0000, 0x0002, 0x0006 followed by 12 zero values. - * Interleave value is the offset where those repeat, and channels the number of times. - * Loop flags in second byte are: 0x06 = start, 0x03 = end (per channel). - * Interleave can be large (up to 0x20000 found so far) and is always a 0x10 multiple value. */ - readOffset+=(off_t)read_streamfile(mibBuffer,0,0x10,streamFile); - mibBuffer[0]=0; - { - uint8_t doChannelUpdate=1; - uint8_t bDoUpdateInterleave=1; - - readOffset=0; - do { - readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); - // be sure to point to an interleave value - if(readOffset<(int32_t)(fileLength*0.5)) { - - if(memcmp(testBuffer+2, mibBuffer+2,0x0e)) { - if(doChannelUpdate) { - doChannelUpdate=0; - channel_count++; - } - if(channel_count<2) - bDoUpdateInterleave=1; - } - - testBuffer[0]=0; - if(!memcmp(testBuffer,mibBuffer,0x10)) { - gotEmptyLine=1; - - if(bDoUpdateInterleave) { - bDoUpdateInterleave=0; - interleave=readOffset-0x10; - } - if(readOffset-0x10 == channel_count*interleave) { - doChannelUpdate=1; - } - } - } - - // Loop Start ... - if(testBuffer[0x01]==0x06) { - if(loopStartPointsCount<0x10) { - loopStartPoints[loopStartPointsCount] = readOffset-0x10; - loopStartPointsCount++; - } - } - - // Loop End ... - if(testBuffer[0x01]==0x03 && testBuffer[0x03]!=0x77) { - if(loopEndPointsCount<0x10) { - loopEndPoints[loopEndPointsCount] = readOffset; - loopEndPointsCount++; - } - } - - if(testBuffer[0x01]==0x04) { - // 0x04 loop points flag can't be with a 0x03 loop points flag - if(loopStartPointsCount<0x10) { - loopStartPoints[loopStartPointsCount] = readOffset-0x10; - loopStartPointsCount++; - - // Loop end value is not set by flags ... - // go until end of file - loopToEnd=1; - } - } - - } while (readOffset<((int32_t)fileLength)); - } - - if(testBuffer[0]==0x0c && testBuffer[1]==0) - forceNoLoop=1; - - if(channel_count==0) - channel_count=1; - - // Calc Loop Points & Interleave ... - if(loopStartPointsCount>=2) { - // can't get more then 0x10 loop point ! - if(loopStartPointsCount<=0x0F) { - // Always took the first 2 loop points - interleave=loopStartPoints[1]-loopStartPoints[0]; - loopStart=loopStartPoints[1]; - - // Can't be one channel .mib with interleave values - if(interleave>0 && channel_count==1) - channel_count=2; - } else { - loopStart=0; - } - } - - if(loopEndPointsCount>=2) { - // can't get more then 0x10 loop point ! - if(loopEndPointsCount<=0x0F) { - // No need to recalculate interleave value ... - loopEnd=loopEndPoints[loopEndPointsCount-1]; - - // Can't be one channel .mib with interleave values - if(channel_count==1) - channel_count=2; - } else { - loopToEnd=0; - loopEnd=0; - } - } - - if (loopToEnd) - loopEnd=fileLength; - - if(forceNoLoop) - loopEnd=0; - - if(interleave>0x10 && channel_count==1) - channel_count=2; - - if(interleave==0) - interleave=0x10; - - // further check on channel_count ... - if(gotEmptyLine) { - int newChannelCount = 0; - - readOffset=0; - - /* count empty lines at interleave = channels */ - do { - newChannelCount++; - read_streamfile(testBuffer,readOffset,0x10,streamFile); - readOffset+=interleave; - } while(!memcmp(testBuffer,mibBuffer,16)); - - newChannelCount--; - if(newChannelCount>channel_count) - channel_count=newChannelCount; - } - - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,(loopEnd!=0)); - if (!vgmstream) goto fail; - - vgmstream->coding_type = coding_PSX; - vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave; - - vgmstream->interleave_block_size = interleave; - - if(!strcasecmp("mib",filename_extension(filename))) - vgmstream->sample_rate = 44100; - - if(!strcasecmp("mi4",filename_extension(filename))) - vgmstream->sample_rate = 48000; - - vgmstream->num_samples = (int32_t)(fileLength/16/channel_count*28); - - if(loopEnd!=0) { - if(vgmstream->channels==1) { - vgmstream->loop_start_sample = loopStart/16*18; //todo 18 instead of 28 probably a bug - vgmstream->loop_end_sample = loopEnd/16*28; - } else { - vgmstream->loop_start_sample = ((((loopStart/vgmstream->interleave_block_size)-1)*vgmstream->interleave_block_size)/16*14*channel_count)/channel_count; - if(loopStart%vgmstream->interleave_block_size) { - vgmstream->loop_start_sample += (((loopStart%vgmstream->interleave_block_size)-1)/16*14*channel_count); - } - - if(loopEnd==fileLength) { - vgmstream->loop_end_sample=(loopEnd/16*28)/channel_count; - } else { - vgmstream->loop_end_sample = ((((loopEnd/vgmstream->interleave_block_size)-1)*vgmstream->interleave_block_size)/16*14*channel_count)/channel_count; - if(loopEnd%vgmstream->interleave_block_size) { - vgmstream->loop_end_sample += (((loopEnd%vgmstream->interleave_block_size)-1)/16*14*channel_count); - } - } - } - } - - if(loopToEnd) { - // try to find if there's no empty line ... - int emptySamples=0; - - for(i=0; i<16;i++) { - mibBuffer[i]=0; //memset - } - - readOffset=fileLength-0x10; - do { - read_streamfile(testBuffer,readOffset,0x10,streamFile); - if(!memcmp(mibBuffer,testBuffer,16)) { - emptySamples+=28; - } - readOffset-=0x10; - } while(!memcmp(testBuffer,mibBuffer,16)); - - vgmstream->loop_end_sample-=(emptySamples*channel_count); - } - - vgmstream->meta_type = meta_PS_HEADERLESS; - vgmstream->allow_dual_stereo = 1; - - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} +#include "meta.h" +#include "../coding/coding.h" + + +/* Headerless PS-ADPCM + * Guesses interleave/channels/loops by testing data and using the file extension for sample rate. + * This is an ugly crutch for older sets, use TXTH to properly play headerless data instead. */ +VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset = 0x00; + char filename[PATH_LIMIT]; + + uint8_t mibBuffer[0x10]; + uint8_t testBuffer[0x10]; + + size_t fileLength; + off_t loopStart = 0; + off_t loopEnd = 0; + off_t interleave = 0; + + off_t readOffset = 0; + + off_t loopStartPoints[0x10] = {0}; + int loopStartPointsCount=0; + off_t loopEndPoints[0x10] = {0}; + int loopEndPointsCount=0; + int loopToEnd=0; + int forceNoLoop=0; + int gotEmptyLine=0; + + int i, channel_count=0; + + + /* checks + * .mib: common, but many ext-less files are renamed to this. + * .mi4: fake .mib to force another sample rate */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("mib",filename_extension(filename)) && + strcasecmp("mi4",filename_extension(filename))) + goto fail; + + /* test if raw PS-ADPCM */ + if (!ps_check_format(streamFile, 0x00, 0x2000)) + goto fail; + + + fileLength = get_streamfile_size(streamFile); + + /* Search for interleave value (checking channel starts) and loop points (using PS-ADPCM flags). + * Channel start will by 0x0000, 0x0002, 0x0006 followed by 12 zero values. + * Interleave value is the offset where those repeat, and channels the number of times. + * Loop flags in second byte are: 0x06 = start, 0x03 = end (per channel). + * Interleave can be large (up to 0x20000 found so far) and is always a 0x10 multiple value. */ + readOffset+=(off_t)read_streamfile(mibBuffer,0,0x10,streamFile); + mibBuffer[0]=0; + { + uint8_t doChannelUpdate=1; + uint8_t bDoUpdateInterleave=1; + + readOffset=0; + do { + readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); + // be sure to point to an interleave value + if(readOffset<(int32_t)(fileLength*0.5)) { + + if(memcmp(testBuffer+2, mibBuffer+2,0x0e)) { + if(doChannelUpdate) { + doChannelUpdate=0; + channel_count++; + } + if(channel_count<2) + bDoUpdateInterleave=1; + } + + testBuffer[0]=0; + if(!memcmp(testBuffer,mibBuffer,0x10)) { + gotEmptyLine=1; + + if(bDoUpdateInterleave) { + bDoUpdateInterleave=0; + interleave=readOffset-0x10; + } + if(readOffset-0x10 == channel_count*interleave) { + doChannelUpdate=1; + } + } + } + + // Loop Start ... + if(testBuffer[0x01]==0x06) { + if(loopStartPointsCount<0x10) { + loopStartPoints[loopStartPointsCount] = readOffset-0x10; + loopStartPointsCount++; + } + } + + // Loop End ... + if(testBuffer[0x01]==0x03 && testBuffer[0x03]!=0x77) { + if(loopEndPointsCount<0x10) { + loopEndPoints[loopEndPointsCount] = readOffset; + loopEndPointsCount++; + } + } + + if(testBuffer[0x01]==0x04) { + // 0x04 loop points flag can't be with a 0x03 loop points flag + if(loopStartPointsCount<0x10) { + loopStartPoints[loopStartPointsCount] = readOffset-0x10; + loopStartPointsCount++; + + // Loop end value is not set by flags ... + // go until end of file + loopToEnd=1; + } + } + + } while (readOffset<((int32_t)fileLength)); + } + + if(testBuffer[0]==0x0c && testBuffer[1]==0) + forceNoLoop=1; + + if(channel_count==0) + channel_count=1; + + // Calc Loop Points & Interleave ... + if(loopStartPointsCount>=2) { + // can't get more then 0x10 loop point ! + if(loopStartPointsCount<=0x0F) { + // Always took the first 2 loop points + interleave=loopStartPoints[1]-loopStartPoints[0]; + loopStart=loopStartPoints[1]; + + // Can't be one channel .mib with interleave values + if(interleave>0 && channel_count==1) + channel_count=2; + } else { + loopStart=0; + } + } + + if(loopEndPointsCount>=2) { + // can't get more then 0x10 loop point ! + if(loopEndPointsCount<=0x0F) { + // No need to recalculate interleave value ... + loopEnd=loopEndPoints[loopEndPointsCount-1]; + + // Can't be one channel .mib with interleave values + if(channel_count==1) + channel_count=2; + } else { + loopToEnd=0; + loopEnd=0; + } + } + + if (loopToEnd) + loopEnd=fileLength; + + if(forceNoLoop) + loopEnd=0; + + if(interleave>0x10 && channel_count==1) + channel_count=2; + + if(interleave==0) + interleave=0x10; + + // further check on channel_count ... + if(gotEmptyLine) { + int newChannelCount = 0; + + readOffset=0; + + /* count empty lines at interleave = channels */ + do { + newChannelCount++; + read_streamfile(testBuffer,readOffset,0x10,streamFile); + readOffset+=interleave; + } while(!memcmp(testBuffer,mibBuffer,16)); + + newChannelCount--; + if(newChannelCount>channel_count) + channel_count=newChannelCount; + } + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,(loopEnd!=0)); + if (!vgmstream) goto fail; + + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave; + + vgmstream->interleave_block_size = interleave; + + if(!strcasecmp("mib",filename_extension(filename))) + vgmstream->sample_rate = 44100; + + if(!strcasecmp("mi4",filename_extension(filename))) + vgmstream->sample_rate = 48000; + + vgmstream->num_samples = (int32_t)(fileLength/16/channel_count*28); + + if(loopEnd!=0) { + if(vgmstream->channels==1) { + vgmstream->loop_start_sample = loopStart/16*18; //todo 18 instead of 28 probably a bug + vgmstream->loop_end_sample = loopEnd/16*28; + } else { + vgmstream->loop_start_sample = ((((loopStart/vgmstream->interleave_block_size)-1)*vgmstream->interleave_block_size)/16*14*channel_count)/channel_count; + if(loopStart%vgmstream->interleave_block_size) { + vgmstream->loop_start_sample += (((loopStart%vgmstream->interleave_block_size)-1)/16*14*channel_count); + } + + if(loopEnd==fileLength) { + vgmstream->loop_end_sample=(loopEnd/16*28)/channel_count; + } else { + vgmstream->loop_end_sample = ((((loopEnd/vgmstream->interleave_block_size)-1)*vgmstream->interleave_block_size)/16*14*channel_count)/channel_count; + if(loopEnd%vgmstream->interleave_block_size) { + vgmstream->loop_end_sample += (((loopEnd%vgmstream->interleave_block_size)-1)/16*14*channel_count); + } + } + } + } + + if(loopToEnd) { + // try to find if there's no empty line ... + int emptySamples=0; + + for(i=0; i<16;i++) { + mibBuffer[i]=0; //memset + } + + readOffset=fileLength-0x10; + do { + read_streamfile(testBuffer,readOffset,0x10,streamFile); + if(!memcmp(mibBuffer,testBuffer,16)) { + emptySamples+=28; + } + readOffset-=0x10; + } while(!memcmp(testBuffer,mibBuffer,16)); + + vgmstream->loop_end_sample-=(emptySamples*channel_count); + } + + vgmstream->meta_type = meta_PS_HEADERLESS; + vgmstream->allow_dual_stereo = 1; + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/raw_pcm.c b/Frameworks/vgmstream/vgmstream/src/meta/raw_pcm.c index dbfda6391..2ea339aa5 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/raw_pcm.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/raw_pcm.c @@ -1,38 +1,38 @@ -#include "meta.h" -#include "../coding/coding.h" - -/* RAW - RAW format is native 44khz PCM file */ -VGMSTREAM * init_vgmstream_raw_pcm(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset; - int loop_flag, channel_count; - - - /* checks */ - if (!check_extensions(streamFile, "raw")) - goto fail; - - channel_count = 2; - loop_flag = 0; - start_offset = 0x00; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count, loop_flag); - if (!vgmstream) goto fail; - - vgmstream->meta_type = meta_RAW_PCM; - vgmstream->sample_rate = 44100; - vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(streamFile), channel_count, 16); - - vgmstream->coding_type = coding_PCM16LE; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x02; - - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} +#include "meta.h" +#include "../coding/coding.h" + +/* RAW - RAW format is native 44khz PCM file */ +VGMSTREAM * init_vgmstream_raw_pcm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag, channel_count; + + + /* checks */ + if (!check_extensions(streamFile, "raw")) + goto fail; + + channel_count = 2; + loop_flag = 0; + start_offset = 0x00; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_RAW_PCM; + vgmstream->sample_rate = 44100; + vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(streamFile), channel_count, 16); + + vgmstream->coding_type = coding_PCM16LE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x02; + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/raw_wavm.c b/Frameworks/vgmstream/vgmstream/src/meta/raw_wavm.c index 6be895304..742f2c7c7 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/raw_wavm.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/raw_wavm.c @@ -1,36 +1,36 @@ -#include "meta.h" -#include "../coding/coding.h" - -/* WAVM - headerless format which can be found on XBOX */ -VGMSTREAM * init_vgmstream_raw_wavm(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset = 0; - int loop_flag, channel_count; - - /* check extension */ - if (!check_extensions(streamFile,"wavm")) - goto fail; - - start_offset = 0; - loop_flag = 0; - channel_count = 2; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - vgmstream->meta_type = meta_RAW_WAVM; - vgmstream->sample_rate = 44100; - vgmstream->num_samples = xbox_ima_bytes_to_samples(get_streamfile_size(streamFile), vgmstream->channels); - - vgmstream->coding_type = coding_XBOX_IMA; - vgmstream->layout_type = layout_none; - - if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} +#include "meta.h" +#include "../coding/coding.h" + +/* WAVM - headerless format which can be found on XBOX */ +VGMSTREAM * init_vgmstream_raw_wavm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset = 0; + int loop_flag, channel_count; + + /* check extension */ + if (!check_extensions(streamFile,"wavm")) + goto fail; + + start_offset = 0; + loop_flag = 0; + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_RAW_WAVM; + vgmstream->sample_rate = 44100; + vgmstream->num_samples = xbox_ima_bytes_to_samples(get_streamfile_size(streamFile), vgmstream->channels); + + vgmstream->coding_type = coding_XBOX_IMA; + vgmstream->layout_type = layout_none; + + if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/seb.c b/Frameworks/vgmstream/vgmstream/src/meta/seb.c index 657a7352c..cce8dfd15 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/seb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/seb.c @@ -1,53 +1,54 @@ -#include "meta.h" - - -/* .seb - Game Arts games [Grandia (PS1), Grandia II/III/X (PS2)] */ -VGMSTREAM * init_vgmstream_seb(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset; - int loop_flag, channel_count; - - - /* checks */ - /* .seb: found in Grandia II (PS2) .idx */ - /* .gms: fake? (.stz+idx bigfile without names, except in Grandia II) */ - if (!check_extensions(streamFile, "seb,gms,")) - goto fail; - - channel_count = read_32bitLE(0x00,streamFile); - if (channel_count > 2) goto fail; /* mono or stereo */ - /* 0x08/0c: unknown count, possibly related to looping */ - - start_offset = 0x800; - - if (read_32bitLE(0x10,streamFile) > get_streamfile_size(streamFile) || /* loop start offset */ - read_32bitLE(0x18,streamFile) > get_streamfile_size(streamFile)) /* loop end offset */ - goto fail; - /* in Grandia III sometimes there is a value at 0x24/34 */ - - loop_flag = (read_32bitLE(0x20,streamFile) == 0); - - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - vgmstream->meta_type = meta_SEB; - vgmstream->sample_rate = read_32bitLE(0x04,streamFile); - - vgmstream->num_samples = read_32bitLE(0x1c,streamFile); - vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile); - vgmstream->loop_end_sample = read_32bitLE(0x1c,streamFile); - - vgmstream->coding_type = coding_PSX; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x800; - - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} +#include "meta.h" + + +/* .seb - Game Arts games [Grandia (PS1), Grandia II/III/X (PS2)] */ +VGMSTREAM* init_vgmstream_seb(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + off_t start_offset; + int loop_flag, channels; + + + /* checks */ + channels = read_32bitLE(0x00,sf); + if (channels > 2) + return NULL; + // 0x08/0c: unknown count, possibly related to looping + + /* .seb: found in Grandia II (PS2) .idx */ + /* .gms: fake? (.stz+idx bigfile without names, except in Grandia II) */ + if (!check_extensions(sf, "seb,gms,")) + return NULL; + + start_offset = 0x800; + + if (read_u32le(0x10,sf) > get_streamfile_size(sf) || // loop start offset + read_u32le(0x18,sf) > get_streamfile_size(sf)) // loop end offset + return NULL; + /* in Grandia III sometimes there is a value at 0x24/34 */ + + loop_flag = (read_s32le(0x20,sf) == 0); + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_SEB; + vgmstream->sample_rate = read_s32le(0x04,sf); + + vgmstream->num_samples = read_s32le(0x1c,sf); + vgmstream->loop_start_sample = read_s32le(0x14,sf); + vgmstream->loop_end_sample = read_s32le(0x1c,sf); + + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x800; + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/smc_smh.c b/Frameworks/vgmstream/vgmstream/src/meta/smc_smh.c deleted file mode 100644 index 9f65e45ff..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/smc_smh.c +++ /dev/null @@ -1,65 +0,0 @@ -#include "meta.h" -#include "../coding/coding.h" - -/* SMC+SMH - from Wangan Midnight 1/R (System246) */ -VGMSTREAM * init_vgmstream_smc_smh(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - STREAMFILE * streamHeader = NULL; - off_t start_offset, header_offset = 0; - size_t stream_size; - int loop_flag = 0, channel_count, sample_rate; - int total_subsongs, target_subsong = streamFile->stream_index; - - - /* checks */ - if (!check_extensions(streamFile, "smc")) - goto fail; - - streamHeader = open_streamfile_by_ext(streamFile, "smh"); - if (!streamHeader) goto fail; - - - total_subsongs = read_32bitLE(0x00,streamHeader); - if (target_subsong == 0) target_subsong = 1; - if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; - - if (total_subsongs*0x10 + 0x10 != get_streamfile_size(streamHeader)) - goto fail; - - header_offset = 0x10 + (target_subsong-1)*0x10; - - start_offset = read_32bitLE(header_offset+0x00, streamHeader); - stream_size = read_32bitLE(header_offset+0x04, streamHeader); - sample_rate = read_32bitLE(header_offset+0x08, streamHeader); - /* 0x0c(2): always 0x10, frame size? */ - channel_count = read_16bitLE(header_offset+0x0e, streamHeader); - loop_flag = 0; - - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - vgmstream->sample_rate = sample_rate; - vgmstream->num_samples = ps_bytes_to_samples(stream_size,channel_count); - - vgmstream->num_streams = total_subsongs; - vgmstream->stream_size = stream_size; - vgmstream->meta_type = meta_SMC_SMH; - - vgmstream->coding_type = coding_PSX; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0x04, streamHeader); - - - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) - goto fail; - - close_streamfile(streamHeader); - return vgmstream; - -fail: - close_streamfile(streamHeader); - close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/smh_smc.c b/Frameworks/vgmstream/vgmstream/src/meta/smh_smc.c new file mode 100644 index 000000000..15e4cc182 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/smh_smc.c @@ -0,0 +1,64 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* SMH+SMC - from Wangan Midnight 1/R (System246) */ +VGMSTREAM* init_vgmstream_smh_smc(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + STREAMFILE* sb = NULL; + off_t start_offset, header_offset = 0; + size_t stream_size; + int loop_flag = 0, channels, sample_rate; + int total_subsongs, target_subsong = sf->stream_index; + + + /* checks */ + if (!check_extensions(sf, "smh")) + return NULL; + + total_subsongs = read_s32le(0x00,sf); + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; + + if (total_subsongs * 0x10 + 0x10 != get_streamfile_size(sf)) + return NULL; + + sb = open_streamfile_by_ext(sf, "smc"); + if (!sb) goto fail; + + header_offset = 0x10 + (target_subsong - 1) * 0x10; + + start_offset = read_u32le(header_offset+0x00, sf); + stream_size = read_u32le(header_offset+0x04, sf); + sample_rate = read_u32le(header_offset+0x08, sf); + // 0x0c(2): always 0x10, frame size? + channels = read_u16le(header_offset+0x0e, sf); + loop_flag = 0; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = ps_bytes_to_samples(stream_size, channels); + + vgmstream->num_streams = total_subsongs; + vgmstream->stream_size = stream_size; + vgmstream->meta_type = meta_SMC_SMH; + + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0x04, sf); + + + if (!vgmstream_open_stream(vgmstream, sb, start_offset)) + goto fail; + + close_streamfile(sb); + return vgmstream; + +fail: + close_streamfile(sb); + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/srcd.c b/Frameworks/vgmstream/vgmstream/src/meta/srcd.c new file mode 100644 index 000000000..466936ceb --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/srcd.c @@ -0,0 +1,124 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* srcd - Capcom RE Engine */ +VGMSTREAM* init_vgmstream_srcd(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + STREAMFILE* subfile = NULL; + off_t start_offset = 0; + int loop_flag = 0; + int32_t loop_start_sample = 0, loop_end_sample = 0; + uint32_t container_type; + const char* extension = NULL; + VGMSTREAM* (*init_vgmstream_function)(STREAMFILE*) = NULL; + + if (!is_id32be(0x00, sf, "srcd")) + return NULL; + + if (!check_extensions(sf, "srcd,asrc,14,21,26,31")) + return NULL; + + { + enum versions { VERSION_31, VERSION_21_26, VERSION_14, VERSION_UNKNOWN }; + enum versions ver = VERSION_UNKNOWN; + + //v31 - AJ_AAT + if (read_u32le(0x18, sf) > 0x02) { + ver = VERSION_31; + } + //v21 - CAS2 + else if (read_u32le(0x41, sf) == 0x49) { + ver = VERSION_21_26; + } + //v26 - GTPD + else if (read_u32le(0x46, sf) == 0x4E) { + ver = VERSION_21_26; + } + //v14 - CAS + else if (read_u8(0x3A, sf) == 0x42) { + ver = VERSION_14; + } + + switch (ver) { + case VERSION_31: + loop_flag = read_u8(0x34, sf); + loop_start_sample = read_u32le(0x35, sf); + loop_end_sample = read_u32le(0x39, sf); + break; + + case VERSION_21_26: + loop_flag = read_u8(0x2C, sf); + loop_start_sample = read_u32le(0x2D, sf); + loop_end_sample = read_u32le(0x31, sf); + break; + + case VERSION_14: + loop_flag = read_u8(0x28, sf); + loop_start_sample = read_u32le(0x29, sf); + loop_end_sample = read_u32le(0x2D, sf); + break; + + default: + VGM_LOG("SRCD: Unknown version, disabling loop\n"); + loop_flag = 0; + break; + } + } + + container_type = read_u32be(0x0C, sf); + { + const off_t scan_start = 0x40; + const size_t scan_size = 0x100; //Should be small + off_t current_offset; + uint32_t magic_to_find = 0; + + if (container_type == get_id32be("wav ")) { + magic_to_find = get_id32be("RIFF"); + } else if (container_type == get_id32be("ogg ")) { + magic_to_find = get_id32be("OggS"); + } + + if (magic_to_find) { + for (current_offset = scan_start; current_offset < scan_start + scan_size; current_offset++) { + if (read_u32be(current_offset, sf) == magic_to_find) { + start_offset = current_offset; + break; + } + } + } + } + + if (start_offset == 0) + goto fail; + + + /* Select the appropriate init function and extension based on container type */ + if (container_type == get_id32be("wav ")) { + extension = "wav"; + init_vgmstream_function = init_vgmstream_riff; + } else if (container_type == get_id32be("ogg ")) { + extension = "ogg"; + init_vgmstream_function = init_vgmstream_ogg_vorbis; + } else { + VGM_LOG("SRCD: Codec not recognized"); + goto fail; + } + + subfile = setup_subfile_streamfile(sf, start_offset, get_streamfile_size(sf) - start_offset, extension); + if (!subfile) goto fail; + + vgmstream = init_vgmstream_function(subfile); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_SRCD; + + vgmstream_force_loop(vgmstream, loop_flag, loop_start_sample, loop_end_sample); + + close_streamfile(subfile); + return vgmstream; + +fail: + close_streamfile(subfile); + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wv6.c b/Frameworks/vgmstream/vgmstream/src/meta/wv6.c index bbbf62ec2..7bdfe19ab 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/wv6.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/wv6.c @@ -1,55 +1,55 @@ -#include "meta.h" -#include "../coding/coding.h" - -/* WV6 - Gorilla Systems PC games [Spy Kids: Mega Mission Zone (PC), Lilo & Stitch: Hawaiian Adventure (PC)] */ -VGMSTREAM * init_vgmstream_wv6(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset; - int loop_flag, channel_count; - - - /* checks */ - if (!check_extensions(streamFile, "wv6")) - goto fail; - - if (read_32bitLE(0x00,streamFile) != get_streamfile_size(streamFile)) - goto fail; - if (read_32bitBE(0x2c,streamFile) != 0x57563620 || /* "WV6 " */ - read_32bitBE(0x30,streamFile) != 0x494D415F) /* "IMA_" ("WV6 IMA_ADPCM COMPRESSED 16 BIT AUDIO") */ - goto fail; - - /* 0x54/58/5c/60/6c: unknown (reject to catch possible stereo files, but don't seem to exist) */ - if (read_32bitLE(0x54,streamFile) != 0x01 || - read_32bitLE(0x58,streamFile) != 0x01 || - read_32bitLE(0x5c,streamFile) != 0x10 || - read_32bitLE(0x68,streamFile) != 0x01 || - read_32bitLE(0x6c,streamFile) != 0x88) - goto fail; - /* 0x64: PCM size (samples*channels*2) */ - - channel_count = 1; - loop_flag = 0; - start_offset = 0x8c; - - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count, loop_flag); - if (!vgmstream) goto fail; - - vgmstream->sample_rate = read_32bitLE(0x60, streamFile); - vgmstream->num_samples = ima_bytes_to_samples(read_32bitLE(0x88,streamFile), channel_count); - - vgmstream->meta_type = meta_WV6; - vgmstream->coding_type = coding_WV6_IMA; - vgmstream->layout_type = layout_none; - - read_string(vgmstream->stream_name,0x1c+1, 0x04,streamFile); - - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} +#include "meta.h" +#include "../coding/coding.h" + +/* WV6 - Gorilla Systems PC games [Spy Kids: Mega Mission Zone (PC), Lilo & Stitch: Hawaiian Adventure (PC)] */ +VGMSTREAM* init_vgmstream_wv6(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + off_t start_offset; + int loop_flag, channels; + + + /* checks */ + if (read_u32le(0x00,sf) != get_streamfile_size(sf)) + return NULL; + // 04: filename + if (!is_id32be(0x2c,sf, "WV6 ") || !is_id32be(0x30,sf, "IMA_")) // "WV6 IMA_ADPCM COMPRESSED 16 BIT AUDIO" + return NULL; + + if (!check_extensions(sf, "wv6")) + return NULL; + + // 0x54/58/5c/60/6c: unknown (reject to catch possible stereo files, but don't seem to exist) + if (read_s32le(0x54,sf) != 0x01 || + read_s32le(0x58,sf) != 0x01 || + read_s32le(0x5c,sf) != 0x10 || + read_s32le(0x68,sf) != 0x01 || + read_s32le(0x6c,sf) != 0x88) + return NULL; + // 0x64: PCM size (samples * channels * 2) + + channels = 1; + loop_flag = 0; + start_offset = 0x8c; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = read_s32le(0x60, sf); + vgmstream->num_samples = ima_bytes_to_samples(read_u32le(0x88,sf), channels); + + vgmstream->meta_type = meta_WV6; + vgmstream->coding_type = coding_WV6_IMA; + vgmstream->layout_type = layout_none; + + read_string(vgmstream->stream_name, 0x1c + 1, 0x04,sf); + + if (!vgmstream_open_stream(vgmstream,sf,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/util/vgmstream_limits.h b/Frameworks/vgmstream/vgmstream/src/util/vgmstream_limits.h index a69c45586..2f210b057 100644 --- a/Frameworks/vgmstream/vgmstream/src/util/vgmstream_limits.h +++ b/Frameworks/vgmstream/vgmstream/src/util/vgmstream_limits.h @@ -12,7 +12,7 @@ enum { VGMSTREAM_MAX_CHANNELS = 64, /* +40ch multilayers */ VGMSTREAM_MIN_SAMPLE_RATE = 300, /* 300 is Wwise min */ VGMSTREAM_MAX_SAMPLE_RATE = 192000, /* found in some FSB5 */ - VGMSTREAM_MAX_SUBSONGS = 65535, /* +20000 isn't that uncommon */ + VGMSTREAM_MAX_SUBSONGS = 90000, /* +20000 isn't that uncommon, known max is 89734 in EA NHL 14 sbs+sbr */ VGMSTREAM_MAX_NUM_SAMPLES = 1000000000, /* no ~5h vgm hopefully */ }; diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream_init.c b/Frameworks/vgmstream/vgmstream/src/vgmstream_init.c index fdfe82b40..b98fc8b94 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream_init.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream_init.c @@ -317,7 +317,6 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_ubi_lyn_container, init_vgmstream_msb_msh, init_vgmstream_txtp, - init_vgmstream_smc_smh, init_vgmstream_ppst, init_vgmstream_sps_n1_segmented, init_vgmstream_ubi_bao_pk, @@ -330,7 +329,6 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_xmd, init_vgmstream_cks, init_vgmstream_ckb, - init_vgmstream_wv6, init_vgmstream_str_wav, init_vgmstream_wavebatch, init_vgmstream_hd3_bd3, @@ -368,8 +366,6 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_dsp_adpx, init_vgmstream_ogg_opus, init_vgmstream_nus3audio, - init_vgmstream_imc, - init_vgmstream_imc_container, init_vgmstream_smp, init_vgmstream_gin, init_vgmstream_dsf, @@ -512,6 +508,8 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_audiopkg, init_vgmstream_swar, init_vgmstream_ivb, + init_vgmstream_srcd, + init_vgmstream_mhwk, /* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */ init_vgmstream_agsc, @@ -539,6 +537,10 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_vai, init_vgmstream_ezw, init_vgmstream_vgs_old, + init_vgmstream_imc, + init_vgmstream_imc_container, + init_vgmstream_wv6, + init_vgmstream_smh_smc, /* need companion files */ init_vgmstream_pos, init_vgmstream_sli_loops, diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream_types.h b/Frameworks/vgmstream/vgmstream/src/vgmstream_types.h index 8ccd9fe78..0b23bb92d 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream_types.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream_types.h @@ -496,7 +496,7 @@ typedef enum { meta_LSF_N1NJ4N, /* .lsf n1nj4n Fastlane Street Racing (iPhone) */ meta_XWAV, meta_RAW_SNDS, - meta_HYPERSCAN_KVAG, /* Hyperscan KVAG/BVG */ + meta_KVAG, meta_PSND, meta_ADP_WILDFIRE, meta_QD_ADP, @@ -721,6 +721,8 @@ typedef enum { meta_AUDIOPKG, meta_SWAR, meta_IVB, + meta_SRCD, + meta_MHWK } meta_t; #endif