From bf95a58c021b8b240fb7bc98029702faea280a51 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Thu, 23 Apr 2020 00:09:41 -0700 Subject: [PATCH] Updated VGMStream to r1050-2930-g9a1b37d2 --- .../libvgmstream.xcodeproj/project.pbxproj | 4 + .../vgmstream/src/coding/coding_utils.c | 14 +- .../vgmstream/src/coding/relic_decoder.c | 26 +- Frameworks/vgmstream/vgmstream/src/formats.c | 2 + Frameworks/vgmstream/vgmstream/src/meta/adx.c | 4 +- .../vgmstream/vgmstream/src/meta/adx_keys.h | 7 +- .../vgmstream/vgmstream/src/meta/bkhd.c | 134 +++-- .../vgmstream/vgmstream/src/meta/diva.c | 45 ++ .../vgmstream/vgmstream/src/meta/ea_eaac.c | 498 +++++++++--------- .../vgmstream/vgmstream/src/meta/genh.c | 6 + Frameworks/vgmstream/vgmstream/src/meta/hca.c | 16 +- .../vgmstream/vgmstream/src/meta/meta.h | 2 + .../vgmstream/vgmstream/src/meta/nus3audio.c | 56 +- Frameworks/vgmstream/vgmstream/src/meta/rsd.c | 2 +- .../vgmstream/vgmstream/src/meta/wwise.c | 280 +++++----- .../vgmstream/vgmstream/src/meta/zsnd.c | 14 +- .../vgmstream/vgmstream/src/streamfile.c | 10 +- .../vgmstream/vgmstream/src/vgmstream.c | 1 + .../vgmstream/vgmstream/src/vgmstream.h | 1 + 19 files changed, 649 insertions(+), 473 deletions(-) create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/diva.c diff --git a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj index ffaa23a9a..6a00d9b7c 100644 --- a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj @@ -498,6 +498,7 @@ 837CEB0423487F2C00E62A4A /* jstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 837CEAEF23487F2C00E62A4A /* jstm.c */; }; 837CEB0523487F2C00E62A4A /* sqex_sead_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 837CEAF023487F2C00E62A4A /* sqex_sead_streamfile.h */; }; 837CEB072348809400E62A4A /* seb.c in Sources */ = {isa = PBXBuildFile; fileRef = 837CEB062348809400E62A4A /* seb.c */; }; + 8385D4E6245174C700FF8E67 /* diva.c in Sources */ = {isa = PBXBuildFile; fileRef = 8385D4E2245174C600FF8E67 /* diva.c */; }; 838BDB641D3AF08C0022CA6F /* libavcodec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB611D3AF08C0022CA6F /* libavcodec.a */; }; 838BDB651D3AF08C0022CA6F /* libavformat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB621D3AF08C0022CA6F /* libavformat.a */; }; 838BDB661D3AF08C0022CA6F /* libavutil.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB631D3AF08C0022CA6F /* libavutil.a */; }; @@ -1201,6 +1202,7 @@ 837CEAEF23487F2C00E62A4A /* jstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jstm.c; sourceTree = ""; }; 837CEAF023487F2C00E62A4A /* sqex_sead_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqex_sead_streamfile.h; sourceTree = ""; }; 837CEB062348809400E62A4A /* seb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = seb.c; sourceTree = ""; }; + 8385D4E2245174C600FF8E67 /* diva.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = diva.c; sourceTree = ""; }; 838BDB611D3AF08C0022CA6F /* libavcodec.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavcodec.a; path = ../../ThirdParty/ffmpeg/lib/libavcodec.a; sourceTree = ""; }; 838BDB621D3AF08C0022CA6F /* libavformat.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavformat.a; path = ../../ThirdParty/ffmpeg/lib/libavformat.a; sourceTree = ""; }; 838BDB631D3AF08C0022CA6F /* libavutil.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavutil.a; path = ../../ThirdParty/ffmpeg/lib/libavutil.a; sourceTree = ""; }; @@ -1664,6 +1666,7 @@ 8373341E23F60CDB00DE14DC /* deblock_streamfile.h */, 8349A8EE1FE6257C00E26435 /* dec.c */, 834FE0CD215C79E8000A5D3D /* derf.c */, + 8385D4E2245174C600FF8E67 /* diva.c */, 836F6E4318BDC2180095E648 /* dmsg_segh.c */, 8351F32C2212B57000A606E4 /* dsf.c */, 83299FCF1E7660C7003A3242 /* dsp_adx.c */, @@ -2663,6 +2666,7 @@ 8306B0B220984552000302D4 /* blocked_mxch.c in Sources */, 837CEAFA23487F2C00E62A4A /* xa_04sw.c in Sources */, 836F6F8618BDC2190095E648 /* excitebots.c in Sources */, + 8385D4E6245174C700FF8E67 /* diva.c in Sources */, 836F6FF418BDC2190095E648 /* rws.c in Sources */, 834FE100215C79ED000A5D3D /* svg.c in Sources */, 836F6F2518BDC2190095E648 /* g721_decoder.c in Sources */, diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c b/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c index fa83dbd85..f0e482431 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c @@ -19,7 +19,7 @@ * read num_bits (up to 25) from a bit offset. * 25 since we read a 32 bit int, and need to adjust up to 7 bits from the byte-rounded fseek (32-7=25) */ -static uint32_t read_bitsBE_b(off_t bit_offset, int num_bits, STREAMFILE *streamFile) { +static uint32_t read_bitsBE_b(int64_t bit_offset, int num_bits, STREAMFILE *streamFile) { uint32_t num, mask; if (num_bits > 25) return -1; //??? @@ -400,7 +400,7 @@ fail: /* XMA PARSING */ /* ******************************************** */ -static void ms_audio_parse_header(STREAMFILE *streamFile, int xma_version, off_t offset_b, int bits_frame_size, size_t *first_frame_b, size_t *packet_skip_count, size_t *header_size_b) { +static void ms_audio_parse_header(STREAMFILE *streamFile, int xma_version, int64_t offset_b, int bits_frame_size, size_t *first_frame_b, size_t *packet_skip_count, size_t *header_size_b) { if (xma_version == 1) { /* XMA1 */ //packet_sequence = read_bitsBE_b(offset_b+0, 4, streamFile); /* numbered from 0 to N */ //unknown = read_bitsBE_b(offset_b+4, 2, streamFile); /* packet_metadata? (always 2) */ @@ -431,11 +431,11 @@ static void ms_audio_parse_header(STREAMFILE *streamFile, int xma_version, off_t /* full packet skip, no new frames start in this packet (prev frames can end here) * standardized to some value */ if (*packet_skip_count == 0x7FF) { /* XMA1, 11b */ - VGM_LOG("MS_SAMPLES: XMA1 full packet_skip at 0x%x\n", (uint32_t)offset_b/8); + VGM_LOG("MS_SAMPLES: XMA1 full packet_skip\n");// at %"PRIx64"\n", offset_b/8); *packet_skip_count = 0x800; } else if (*packet_skip_count == 0xFF) { /* XMA2, 8b*/ - VGM_LOG("MS_SAMPLES: XMA2 full packet_skip at 0x%x\n", (uint32_t)offset_b/8); + VGM_LOG("MS_SAMPLES: XMA2 full packet_skip\n");// at %"PRIx64"\n", offset_b/8); *packet_skip_count = 0x800; } @@ -458,7 +458,7 @@ static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, i int frames = 0, samples = 0, loop_start_frame = 0, loop_end_frame = 0; size_t first_frame_b, packet_skip_count, header_size_b, frame_size_b; - off_t offset_b, packet_offset_b, frame_offset_b; + int64_t offset_b, packet_offset_b, frame_offset_b; size_t packet_size = bytes_per_packet; size_t packet_size_b = packet_size * 8; @@ -535,11 +535,11 @@ static void ms_audio_get_skips(STREAMFILE *streamFile, int xma_version, off_t da int start_skip = 0, end_skip = 0; size_t first_frame_b, packet_skip_count, header_size_b, frame_size_b; - off_t offset_b, packet_offset_b, frame_offset_b; + int64_t offset_b, packet_offset_b, frame_offset_b; size_t packet_size = bytes_per_packet; size_t packet_size_b = packet_size * 8; - off_t offset = data_offset; + int64_t offset = data_offset; /* read packet */ { diff --git a/Frameworks/vgmstream/vgmstream/src/coding/relic_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/relic_decoder.c index d10b421c9..63623e395 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/relic_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/relic_decoder.c @@ -1,3 +1,4 @@ +#include #include "coding.h" /* Relic Codec decoder, a fairly simple mono-interleave DCT-based codec. @@ -291,11 +292,16 @@ static uint32_t read_ubits(uint8_t bits, uint32_t offset, uint8_t *buf) { } static int read_sbits(uint8_t bits, uint32_t offset, uint8_t *buf) { uint32_t val = read_ubits(bits, offset, buf); + int outval; if (val >> (bits - 1) == 1) { /* upper bit = sign */ uint32_t mask = (1 << (bits - 1)) - 1; - return -(val & mask); + outval = (int)(val & mask); + outval = -outval; } - return val; + else { + outval = (int)val; + } + return outval; } static void init_dequantization(float* scales) { @@ -338,7 +344,7 @@ static void unpack_frame(uint8_t *buf, int buf_size, float *freq1, float *freq2, if (cb_bits > 0 && ev_bits > 0) { pos = 0; for (i = 0; i < RELIC_CRITICAL_BAND_COUNT - 1; i++) { - if (bit_offset >= 8*buf_size) + if (bit_offset >= 8u*buf_size) break; move = read_ubits(cb_bits, bit_offset, buf); @@ -360,7 +366,7 @@ static void unpack_frame(uint8_t *buf, int buf_size, float *freq1, float *freq2, /* read first part */ pos = 0; for (i = 0; i < RELIC_MAX_FREQ; i++) { - if (bit_offset >= 8*buf_size) + if (bit_offset >= 8u*buf_size) break; move = read_ubits(ei_bits, bit_offset, buf); @@ -384,7 +390,7 @@ static void unpack_frame(uint8_t *buf, int buf_size, float *freq1, float *freq2, else { pos = 0; for (i = 0; i < RELIC_MAX_FREQ; i++) { - if (bit_offset >= 8*buf_size) + if (bit_offset >= 8u*buf_size) break; move = read_ubits(ei_bits, bit_offset, buf); @@ -436,7 +442,7 @@ static void copy_samples(relic_codec_data* data, sample_t* outbuf, int32_t sampl for (ch = 0; ch < ichs; ch++) { for (s = 0; s < samples; s++) { double d64_sample = data->wave_cur[ch][skip + s]; - int pcm_sample = clamp16(d64_sample); + int pcm_sample = clamp16((int32_t)d64_sample); /* f32 in PCM 32767.0 .. -32768.0 format, original code * does some custom double-to-int rint() though */ @@ -453,12 +459,12 @@ static relic_codec_data* init_codec(int channels, int bitrate, int codec_rate) { if (channels > RELIC_MAX_CHANNELS) goto fail; - + data = calloc(1, sizeof(relic_codec_data)); if (!data) goto fail; - + data->channels = channels; - + /* dequantized freq1+2 size (separate from DCT) */ if (codec_rate < 22050) /* probably 11025 only */ data->freq_size = RELIC_SIZE_LOW; @@ -471,7 +477,7 @@ static relic_codec_data* init_codec(int channels, int bitrate, int codec_rate) { data->wave_size = RELIC_SIZE_HIGH; data->dct_mode = RELIC_SIZE_HIGH; data->samples_mode = RELIC_SIZE_HIGH; - + init_dct(data->dct, RELIC_SIZE_HIGH); init_window(data->window, RELIC_SIZE_HIGH); init_dequantization(data->scales); diff --git a/Frameworks/vgmstream/vgmstream/src/formats.c b/Frameworks/vgmstream/vgmstream/src/formats.c index 32319cb51..4e60da24a 100644 --- a/Frameworks/vgmstream/vgmstream/src/formats.c +++ b/Frameworks/vgmstream/vgmstream/src/formats.c @@ -145,6 +145,7 @@ static const char* extension_list[] = { "ddsp", "de2", "dec", + "diva", "dmsg", "ds2", //txth/reserved [Star Wars Bounty Hunter (GC)] "dsf", @@ -1285,6 +1286,7 @@ static const meta_info meta_info_list[] = { {meta_KWB, "Koei Tecmo WaveBank header"}, {meta_LRMD, "Sony LRMD header"}, {meta_WWISE_FX, "Audiokinetic Wwise FX header"}, + {meta_DIVA, "DIVA header"}, }; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/adx.c b/Frameworks/vgmstream/vgmstream/src/meta/adx.c index a42c26971..5b90087c5 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/adx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/adx.c @@ -261,11 +261,11 @@ static int find_adx_key(STREAMFILE *sf, uint8_t type, uint16_t *xor_start, uint1 /* try to find key in external file first */ { - uint8_t keybuf[0x20+1] = {0}; /* +1 extra null for keystrings */ + uint8_t keybuf[0x40+1] = {0}; /* known max ~0x30, +1 extra null for keystrings */ size_t key_size; /* handle type8 keystrings, key9 keycodes and derived keys too */ - key_size = read_key_file(keybuf,0x20, sf); + key_size = read_key_file(keybuf, sizeof(keybuf), sf); if (key_size > 0) { int i, is_ascii = 0; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/adx_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/adx_keys.h index b0c21704d..ea27d5426 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/adx_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/adx_keys.h @@ -193,6 +193,9 @@ static const adxkey_info adxkey8_list[] = { /* Katekyoo Hitman Reborn! Let's Ansatsu! Nerawareta 10-daime! (PS2) */ {0x5381,0x52E5,0x53E9, "REBHITMAN",0}, + /* 428: Fuusasareta Shibuya de (PS3) */ + {0x52ff,0x649f,0x448f, "hj1kviaqqdzUacryoacwmscfvwtlfkVbbbqpqmzqnbile2euljywazejgyxxvqlf",0}, + }; static const adxkey_info adxkey9_list[] = { @@ -234,8 +237,8 @@ static const adxkey_info adxkey9_list[] = { /* Detective Conan Runner / Case Closed Runner (Android) */ {0x0613,0x0e3d,0x6dff, NULL,1175268187653273344}, // 104f643098e3f700 - /* Persona 5 Royal (PS4)*/ - {0x0000,0x1c85,0x1043, NULL,29902882}, // guessed with VGAudio + /* Persona 5 Royal (PS4) */ + {0x0000,0x1c85,0x7043, NULL,29915170}, // 0000000001C87822 }; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bkhd.c b/Frameworks/vgmstream/vgmstream/src/meta/bkhd.c index 4788aad1f..7b5606c39 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/bkhd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/bkhd.c @@ -6,10 +6,10 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; STREAMFILE* temp_sf = NULL; - off_t subfile_offset, didx_offset, data_offset, offset; - size_t subfile_size, didx_size; - uint32_t subfile_id; - int big_endian; + off_t subfile_offset, base_offset = 0; + size_t subfile_size; + uint32_t subfile_id, header_id; + int big_endian, version, is_dummy = 0; uint32_t (*read_u32)(off_t,STREAMFILE*); int total_subsongs, target_subsong = sf->stream_index; @@ -17,47 +17,116 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) { /* checks */ if (!check_extensions(sf,"bnk")) goto fail; - if (read_u32be(0x00, sf) != 0x424B4844) /* "BKHD" */ + + if (read_u32be(0x00, sf) == 0x414B424B) /* "AKBK" [Shadowrun (X360)] */ + base_offset = 0x0c; + if (read_u32be(base_offset + 0x00, sf) != 0x424B4844) /* "BKHD" */ goto fail; - big_endian = guess_endianness32bit(0x04, sf); + big_endian = guess_endianness32bit(base_offset + 0x04, sf); read_u32 = big_endian ? read_u32be : read_u32le; + /* Wwise banks have event/track/sequence/etc info in the HIRC chunk, as well - * as other chunks, and may have a DIDX index to memory .wem in DATA. + * as other chunks, and may have a DATA/DIDX index to memory .wem in DATA. * We support the internal .wem mainly for quick tests, as the HIRC is - * complex and better handled with TXTP (some info from Nicknine's script) */ + * complex and better handled with TXTP (some info from Nicknine's script). + * unlike RIFF, first chunk follows chunk rules */ - /* unlike RIFF first chunk follows chunk rules */ - if (!find_chunk(sf, 0x44494458, 0x00,0, &didx_offset, &didx_size, big_endian, 0)) /* "DIDX" */ - goto fail; - if (!find_chunk(sf, 0x44415441, 0x00,0, &data_offset, NULL, big_endian, 0)) /* "DATA" */ - goto fail; + version = read_u32(base_offset + 0x08, sf); + if (version == 0 || version == 1) { /* early games */ + version = read_u32(base_offset + 0x10, sf); + } - total_subsongs = didx_size / 0x0c; - if (target_subsong == 0) target_subsong = 1; - if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; + if (version <= 26) { + off_t data_offset, data_start, offset; + if (!find_chunk(sf, 0x44415441, base_offset, 0, &data_offset, NULL, big_endian, 0)) /* "DATA" */ + goto fail; - offset = didx_offset + (target_subsong - 1) * 0x0c; - subfile_id = read_u32(offset + 0x00, sf); - subfile_offset = read_u32(offset + 0x04, sf) + data_offset; - subfile_size = read_u32(offset + 0x08, sf); + /* index: + * 00: entries + * 04: null + * 08: entries size + * 0c: padding size after entries + * 10: data size + * 14: size? + * 18: data start + * 1c: data size + * per entry: + * 00: always -1 + * 04: always 0 + * 08: index number or -1 + * 0c: 5 or -1? + * 0c: 5 or -1? + * 0c: 5 or -1? + * 10: stream offset (from data start) or -1 if none + * 14: stream size or 0 if none + */ - //;VGM_LOG("BKHD: %lx, %x\n", subfile_offset, subfile_size); - temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "wem"); - if (!temp_sf) goto fail; + total_subsongs = read_u32(data_offset + 0x00, sf); + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; - subfile_id = read_u32(0x00, temp_sf); - if (subfile_id == 0x52494646 || subfile_id == 0x52494658) { /* "RIFF" / "RIFX" */ - vgmstream = init_vgmstream_wwise(temp_sf); - if (!vgmstream) goto fail; + data_start = read_u32(data_offset + 0x18, sf); + offset = data_offset + 0x20 + (target_subsong - 1) * 0x18; + + subfile_id = read_u32(offset + 0x08, sf); + subfile_offset = read_u32(offset + 0x10, sf) + data_offset + 0x20 + data_start; + subfile_size = read_u32(offset + 0x14, sf); } else { - vgmstream = init_vgmstream_bkhd_fx(temp_sf); - if (!vgmstream) goto fail; + off_t didx_offset, data_offset, offset; + size_t didx_size; + if (!find_chunk(sf, 0x44494458, 0x00,0, &didx_offset, &didx_size, big_endian, 0)) /* "DIDX" */ + goto fail; + if (!find_chunk(sf, 0x44415441, 0x00,0, &data_offset, NULL, big_endian, 0)) /* "DATA" */ + goto fail; + + total_subsongs = didx_size / 0x0c; + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; + + offset = didx_offset + (target_subsong - 1) * 0x0c; + subfile_id = read_u32(offset + 0x00, sf); + subfile_offset = read_u32(offset + 0x04, sf) + data_offset; + subfile_size = read_u32(offset + 0x08, sf); } + /* some indexes don't have that, but for now leave a dummy song for easier HIRC mapping */ + if (subfile_offset <= 0 || subfile_size <= 0) { + //;VGM_LOG("BKHD: dummy entry"); + temp_sf = setup_subfile_streamfile(sf, 0x00, 0x10, "raw"); + if (!temp_sf) goto fail; + + //todo make some better silent entry + vgmstream = init_vgmstream_raw_pcm(temp_sf); + if (!vgmstream) goto fail; + + is_dummy = 1; + } + else { + //;VGM_LOG("BKHD: %lx, %x\n", subfile_offset, subfile_size); + /* could pass .wem but few files need memory .wem detection */ + temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, NULL); + if (!temp_sf) goto fail; + + header_id = read_u32be(0x00, temp_sf); + if (header_id == 0x52494646 || header_id == 0x52494658) { /* "RIFF" / "RIFX" */ + vgmstream = init_vgmstream_wwise(temp_sf); + if (!vgmstream) goto fail; + } + else { + vgmstream = init_vgmstream_bkhd_fx(temp_sf); + if (!vgmstream) goto fail; + } + } + + vgmstream->num_streams = total_subsongs; - snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%u", subfile_id); + + if (is_dummy) + snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%s", "dummy"); + else if (subfile_id != 0xFFFFFFFF) + snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%u", subfile_id); close_streamfile(temp_sf); return vgmstream; @@ -69,7 +138,7 @@ fail: } -/* BKHD mini format, probably from a generator plugin [Borderlands 2 (X360)] */ +/* BKHD mini format, probably from a FX generator plugin [Borderlands 2 (X360)] */ VGMSTREAM* init_vgmstream_bkhd_fx(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; off_t start_offset, data_size; @@ -93,8 +162,7 @@ VGMSTREAM* init_vgmstream_bkhd_fx(STREAMFILE* sf) { /* 0x14/18: some float? */ entries = read_u32(0x1c, sf); /* 0x20 data size / 0x10 */ - if (read_u8(0x24, sf) != 4) /* bps */ - goto fail; + /* 0x24 usually 4, sometimes higher values? */ /* 0x30: unknown table of 16b that goes up and down */ start_offset = 0x30 + align_size_to_block(entries * 0x02, 0x10); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/diva.c b/Frameworks/vgmstream/vgmstream/src/meta/diva.c new file mode 100644 index 000000000..2aca72431 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/diva.c @@ -0,0 +1,45 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* DIVA - Hatsune Miku: Project DIVA Arcade */ +VGMSTREAM * init_vgmstream_diva(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int channel_count; + int loop_end; + int loop_flag; + + /* checks */ + if (!check_extensions(streamFile, "diva")) + goto fail; + + if (read_32bitBE(0x00, streamFile) != 0x44495641) /* "DIVA" */ + goto fail; + + start_offset = 0x40; + channel_count = read_8bit(0x1C, streamFile); + loop_end = read_32bitLE(0x18, streamFile); + + loop_flag = (loop_end != 0); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = read_32bitLE(0x0C, streamFile); + vgmstream->num_samples = read_32bitLE(0x10, streamFile); + vgmstream->loop_start_sample = read_32bitLE(0x14, streamFile); + vgmstream->loop_end_sample = loop_end; + vgmstream->meta_type = meta_DIVA; + vgmstream->layout_type = layout_none; + vgmstream->coding_type = coding_DVI_IMA; + + if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) + goto fail; + + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} \ No newline at end of file diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c index 3f9c80277..6d63aae7f 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c @@ -9,7 +9,7 @@ #define EAAC_VERSION_V0 0x00 /* SNR/SNS */ #define EAAC_VERSION_V1 0x01 /* SPS */ -#define EAAC_CODEC_NONE 0x00 /* XAS v0? */ +#define EAAC_CODEC_NONE 0x00 #define EAAC_CODEC_RESERVED 0x01 /* EALAYER3 V1a? MP30/P6L0/P2B0/P2L0/P8S0/P8U0/PFN0? */ #define EAAC_CODEC_PCM16BE 0x02 #define EAAC_CODEC_EAXMA 0x03 @@ -34,43 +34,43 @@ #define EAAC_BLOCKID1_DATA 0x44 /* 'D' */ #define EAAC_BLOCKID1_END 0x45 /* 'E' */ -static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type, int standalone); -static VGMSTREAM *parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint16_t target_index, off_t ast_offset); -VGMSTREAM * init_vgmstream_gin_header(STREAMFILE *streamFile, off_t offset); +static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMFILE* sf_data, off_t header_offset, off_t start_offset, meta_t meta_type, int standalone); +static VGMSTREAM *parse_s10a_header(STREAMFILE* sf, off_t offset, uint16_t target_index, off_t ast_offset); +VGMSTREAM * init_vgmstream_gin_header(STREAMFILE* sf, off_t offset); /* .SNR+SNS - from EA latest games (~2005-2010), v0 header */ -VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile) { +VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE* sf) { /* check extension, case insensitive */ - if (!check_extensions(streamFile,"snr")) + if (!check_extensions(sf,"snr")) goto fail; - return init_vgmstream_eaaudiocore_header(streamFile, NULL, 0x00, 0x00, meta_EA_SNR_SNS, 1); + return init_vgmstream_eaaudiocore_header(sf, NULL, 0x00, 0x00, meta_EA_SNR_SNS, 1); fail: return NULL; } /* .SPS - from EA latest games (~2010~present), v1 header */ -VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE * streamFile) { +VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE* sf) { /* check extension, case insensitive */ - if (!check_extensions(streamFile,"sps")) + if (!check_extensions(sf,"sps")) goto fail; - return init_vgmstream_eaaudiocore_header(streamFile, NULL, 0x00, 0x00, meta_EA_SPS, 1); + return init_vgmstream_eaaudiocore_header(sf, NULL, 0x00, 0x00, meta_EA_SPS, 1); fail: return NULL; } /* .SNU - from EA Redwood Shores/Visceral games (Dead Space, Dante's Inferno, The Godfather 2), v0 header */ -VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { +VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *sf) { VGMSTREAM * vgmstream = NULL; off_t start_offset, header_offset; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; /* check extension, case insensitive */ - if (!check_extensions(streamFile,"snu")) + if (!check_extensions(sf,"snu")) goto fail; /* EA SNU header (BE/LE depending on platform) */ @@ -83,16 +83,16 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { * 0x0c(4): some sub-offset? (0x20, found when @0x01 is set) */ /* use start_offset as endianness flag */ - if (guess_endianness32bit(0x08,streamFile)) { + if (guess_endianness32bit(0x08,sf)) { read_32bit = read_32bitBE; } else { read_32bit = read_32bitLE; } header_offset = 0x10; /* SNR header */ - start_offset = read_32bit(0x08,streamFile); /* SNS blocks */ + start_offset = read_32bit(0x08,sf); /* SNS blocks */ - vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, header_offset, start_offset, meta_EA_SNU, 0); + vgmstream = init_vgmstream_eaaudiocore_header(sf, sf, header_offset, start_offset, meta_EA_SNU, 0); if (!vgmstream) goto fail; return vgmstream; @@ -103,8 +103,8 @@ fail: } /* EA ABK - ABK header seems to be same as in the old games but the sound table is different and it contains SNR/SNS sounds instead */ -VGMSTREAM * init_vgmstream_ea_abk_eaac(STREAMFILE *streamFile) { - int is_dupe, total_sounds = 0, target_stream = streamFile->stream_index; +VGMSTREAM * init_vgmstream_ea_abk_eaac(STREAMFILE* sf) { + int is_dupe, total_sounds = 0, target_stream = sf->stream_index; off_t bnk_offset, header_table_offset, base_offset, unk_struct_offset, table_offset, snd_entry_offset, ast_offset; off_t num_entries_off, base_offset_off, entries_off, sound_table_offset_off; uint32_t i, j, k, num_sounds, total_sound_tables; @@ -116,14 +116,14 @@ VGMSTREAM * init_vgmstream_ea_abk_eaac(STREAMFILE *streamFile) { int16_t(*read_16bit)(off_t, STREAMFILE*); /* check extension */ - if (!check_extensions(streamFile, "abk")) + if (!check_extensions(sf, "abk")) goto fail; - if (read_32bitBE(0x00, streamFile) != 0x41424B43) /* "ABKC" */ + if (read_32bitBE(0x00, sf) != 0x41424B43) /* "ABKC" */ goto fail; /* use table offset to check endianness */ - if (guess_endianness32bit(0x1C, streamFile)) { + if (guess_endianness32bit(0x1C, sf)) { read_32bit = read_32bitBE; read_16bit = read_16bitBE; } else { @@ -135,14 +135,14 @@ VGMSTREAM * init_vgmstream_ea_abk_eaac(STREAMFILE *streamFile) { if (target_stream < 0) goto fail; - num_tables = read_16bit(0x0A, streamFile); - header_table_offset = read_32bit(0x1C, streamFile); - bnk_offset = read_32bit(0x20, streamFile); + num_tables = read_16bit(0x0A, sf); + header_table_offset = read_32bit(0x1C, sf); + bnk_offset = read_32bit(0x20, sf); total_sound_tables = 0; bnk_target_index = 0xFFFF; ast_offset = 0; - if (!bnk_offset || read_32bitBE(bnk_offset, streamFile) != 0x53313041) /* "S10A" */ + if (!bnk_offset || read_32bitBE(bnk_offset, sf) != 0x53313041) /* "S10A" */ goto fail; /* set up some common values */ @@ -163,14 +163,14 @@ VGMSTREAM * init_vgmstream_ea_abk_eaac(STREAMFILE *streamFile) { } for (i = 0; i < num_tables; i++) { - num_entries = read_8bit(header_table_offset + num_entries_off, streamFile); - extra_entries = read_8bit(header_table_offset + num_entries_off + 0x03, streamFile); - base_offset = read_32bit(header_table_offset + base_offset_off, streamFile); + num_entries = read_8bit(header_table_offset + num_entries_off, sf); + extra_entries = read_8bit(header_table_offset + num_entries_off + 0x03, sf); + base_offset = read_32bit(header_table_offset + base_offset_off, sf); if (num_entries == 0xff) goto fail; /* EOF read */ for (j = 0; j < num_entries; j++) { - unk_struct_offset = read_32bit(header_table_offset + entries_off + 0x04 * j, streamFile); - table_offset = read_32bit(base_offset + unk_struct_offset + sound_table_offset_off, streamFile); + unk_struct_offset = read_32bit(header_table_offset + entries_off + 0x04 * j, sf); + table_offset = read_32bit(base_offset + unk_struct_offset + sound_table_offset_off, sf); /* For some reason, there are duplicate entries pointing at the same sound tables */ is_dupe = 0; @@ -185,7 +185,7 @@ VGMSTREAM * init_vgmstream_ea_abk_eaac(STREAMFILE *streamFile) { continue; sound_table_offsets[total_sound_tables++] = table_offset; - num_sounds = read_32bit(table_offset, streamFile); + num_sounds = read_32bit(table_offset, sf); if (num_sounds == 0xffffffff) goto fail; /* EOF read */ for (k = 0; k < num_sounds; k++) { @@ -194,7 +194,7 @@ VGMSTREAM * init_vgmstream_ea_abk_eaac(STREAMFILE *streamFile) { /* 0x04: ??? */ /* 0x08: streamed data offset */ snd_entry_offset = table_offset + 0x04 + 0x0C * k; - bnk_index = read_16bit(snd_entry_offset + 0x00, streamFile); + bnk_index = read_16bit(snd_entry_offset + 0x00, sf); /* some of these are dummies */ if (bnk_index == 0xFFFF) @@ -203,7 +203,7 @@ VGMSTREAM * init_vgmstream_ea_abk_eaac(STREAMFILE *streamFile) { total_sounds++; if (target_stream == total_sounds) { bnk_target_index = bnk_index; - ast_offset = read_32bit(snd_entry_offset + 0x08, streamFile); + ast_offset = read_32bit(snd_entry_offset + 0x08, sf); } } } @@ -214,7 +214,7 @@ VGMSTREAM * init_vgmstream_ea_abk_eaac(STREAMFILE *streamFile) { if (bnk_target_index == 0xFFFF || ast_offset == 0) goto fail; - vgmstream = parse_s10a_header(streamFile, bnk_offset, bnk_target_index, ast_offset); + vgmstream = parse_s10a_header(sf, bnk_offset, bnk_target_index, ast_offset); if (!vgmstream) goto fail; @@ -226,7 +226,7 @@ fail: } /* EA S10A header - seen inside new ABK files. Putting it here in case it's encountered stand-alone. */ -static VGMSTREAM * parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint16_t target_index, off_t sns_offset) { +static VGMSTREAM * parse_s10a_header(STREAMFILE* sf, off_t offset, uint16_t target_index, off_t sns_offset) { uint32_t num_sounds; off_t snr_offset; STREAMFILE *astFile = NULL; @@ -237,24 +237,24 @@ static VGMSTREAM * parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint1 /* 0x04: zero */ /* 0x08: number of files */ /* 0x0C: offsets table */ - if (read_32bitBE(offset + 0x00, streamFile) != 0x53313041) /* "S10A" */ + if (read_32bitBE(offset + 0x00, sf) != 0x53313041) /* "S10A" */ goto fail; - num_sounds = read_32bitBE(offset + 0x08, streamFile); + num_sounds = read_32bitBE(offset + 0x08, sf); if (num_sounds == 0 || target_index >= num_sounds) goto fail; - snr_offset = offset + read_32bitBE(offset + 0x0C + 0x04 * target_index, streamFile); + snr_offset = offset + read_32bitBE(offset + 0x0C + 0x04 * target_index, sf); if (sns_offset == 0xFFFFFFFF) { /* RAM asset */ //;VGM_LOG("EA S10A: RAM at snr=%lx", snr_offset); - vgmstream = init_vgmstream_eaaudiocore_header(streamFile, NULL, snr_offset, 0x00, meta_EA_SNR_SNS, 0); + vgmstream = init_vgmstream_eaaudiocore_header(sf, NULL, snr_offset, 0x00, meta_EA_SNR_SNS, 0); if (!vgmstream) goto fail; } else { /* streamed asset */ - astFile = open_streamfile_by_ext(streamFile, "ast"); + astFile = open_streamfile_by_ext(sf, "ast"); if (!astFile) goto fail; @@ -262,7 +262,7 @@ static VGMSTREAM * parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint1 goto fail; //;VGM_LOG("EA S10A: stream at snr=%lx, sns=%lx\n", snr_offset, sns_offset); - vgmstream = init_vgmstream_eaaudiocore_header(streamFile, astFile, snr_offset, sns_offset, meta_EA_SNR_SNS, 0); + vgmstream = init_vgmstream_eaaudiocore_header(sf, astFile, snr_offset, sns_offset, meta_EA_SNR_SNS, 0); if (!vgmstream) goto fail; @@ -277,49 +277,49 @@ fail: } /* EA SBR/SBS - used in older 7th gen games for storing SFX */ -VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE *streamFile) { +VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE* sf) { uint32_t i, num_sounds, type_desc; uint16_t num_metas, meta_type; off_t table_offset, types_offset, entry_offset, metas_offset, data_offset, snr_offset, sns_offset; STREAMFILE *sbsFile = NULL; VGMSTREAM *vgmstream = NULL; - int target_stream = streamFile->stream_index; + int target_stream = sf->stream_index; - if (!check_extensions(streamFile, "sbr")) + if (!check_extensions(sf, "sbr")) goto fail; - if (read_32bitBE(0x00, streamFile) != 0x53424B52) /* "SBKR" */ + if (read_32bitBE(0x00, sf) != 0x53424B52) /* "SBKR" */ goto fail; /* SBR files are always big endian */ - num_sounds = read_32bitBE(0x1c, streamFile); - table_offset = read_32bitBE(0x24, streamFile); - types_offset = read_32bitBE(0x28, streamFile); + num_sounds = read_32bitBE(0x1c, sf); + table_offset = read_32bitBE(0x24, sf); + types_offset = read_32bitBE(0x28, sf); if (target_stream == 0) target_stream = 1; if (target_stream < 0 || num_sounds == 0 || target_stream > num_sounds) goto fail; entry_offset = table_offset + 0x0a * (target_stream - 1); - num_metas = read_16bitBE(entry_offset + 0x04, streamFile); - metas_offset = read_32bitBE(entry_offset + 0x06, streamFile); + num_metas = read_16bitBE(entry_offset + 0x04, sf); + metas_offset = read_32bitBE(entry_offset + 0x06, sf); snr_offset = 0; sns_offset = 0; for (i = 0; i < num_metas; i++) { entry_offset = metas_offset + 0x06 * i; - meta_type = read_16bitBE(entry_offset + 0x00, streamFile); - data_offset = read_32bitBE(entry_offset + 0x02, streamFile); + meta_type = read_16bitBE(entry_offset + 0x00, sf); + data_offset = read_32bitBE(entry_offset + 0x02, sf); - type_desc = read_32bitBE(types_offset + 0x06 * meta_type, streamFile); + type_desc = read_32bitBE(types_offset + 0x06 * meta_type, sf); switch (type_desc) { case 0x534E5231: /* "SNR1" */ snr_offset = data_offset; break; case 0x534E5331: /* "SNS1" */ - sns_offset = read_32bitBE(data_offset, streamFile); + sns_offset = read_32bitBE(data_offset, sf); break; default: break; @@ -331,7 +331,7 @@ VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE *streamFile) { if (snr_offset == 0) { /* SPS file */ - sbsFile = open_streamfile_by_ext(streamFile, "sbs"); + sbsFile = open_streamfile_by_ext(sf, "sbs"); if (!sbsFile) goto fail; @@ -343,19 +343,19 @@ VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE *streamFile) { goto fail; } else if (sns_offset == 0) { /* RAM asset */ - vgmstream = init_vgmstream_eaaudiocore_header(streamFile, NULL, snr_offset, 0x00, meta_EA_SNR_SNS, 0); + vgmstream = init_vgmstream_eaaudiocore_header(sf, NULL, snr_offset, 0x00, meta_EA_SNR_SNS, 0); if (!vgmstream) goto fail; } else { /* streamed asset */ - sbsFile = open_streamfile_by_ext(streamFile, "sbs"); + sbsFile = open_streamfile_by_ext(sf, "sbs"); if (!sbsFile) goto fail; if (read_32bitBE(0x00, sbsFile) != 0x53424B53) /* "SBKS" */ goto fail; - vgmstream = init_vgmstream_eaaudiocore_header(streamFile, sbsFile, snr_offset, sns_offset, meta_EA_SNR_SNS, 0); + vgmstream = init_vgmstream_eaaudiocore_header(sf, sbsFile, snr_offset, sns_offset, meta_EA_SNR_SNS, 0); if (!vgmstream) goto fail; } @@ -370,8 +370,8 @@ fail: } /* EA HDR/STH/DAT - seen in older 7th gen games, used for storing speech */ -VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) { - int target_stream = streamFile->stream_index; +VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE* sf) { + int target_stream = sf->stream_index; uint8_t userdata_size, total_sounds, block_id; off_t snr_offset, sns_offset, sth_offset, sth_offset2; size_t dat_size, block_size; @@ -389,24 +389,24 @@ VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) { /* 0x0C: zero */ /* 0x10: table start */ - if (!check_extensions(streamFile, "hdr")) + if (!check_extensions(sf, "hdr")) goto fail; - if (read_8bit(0x09, streamFile) != 0) + if (read_8bit(0x09, sf) != 0) goto fail; - if (read_32bitBE(0x0c, streamFile) != 0) + if (read_32bitBE(0x0c, sf) != 0) goto fail; /* first offset is always zero */ - if (read_16bitBE(0x10, streamFile) != 0) + if (read_16bitBE(0x10, sf) != 0) goto fail; - sthFile = open_streamfile_by_ext(streamFile, "sth"); + sthFile = open_streamfile_by_ext(sf, "sth"); if (!sthFile) goto fail; - datFile = open_streamfile_by_ext(streamFile, "dat"); + datFile = open_streamfile_by_ext(sf, "dat"); if (!datFile) goto fail; @@ -420,10 +420,10 @@ VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) { if (block_id != EAAC_BLOCKID0_DATA && block_id != EAAC_BLOCKID0_END) goto fail; - userdata_size = read_8bit(0x02, streamFile); - total_sounds = read_8bit(0x03, streamFile); + userdata_size = read_8bit(0x02, sf); + total_sounds = read_8bit(0x03, sf); - if (read_8bit(0x08, streamFile) > total_sounds) + if (read_8bit(0x08, sf) > total_sounds) goto fail; if (target_stream == 0) target_stream = 1; @@ -431,7 +431,7 @@ VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) { goto fail; /* offsets in HDR are always big endian */ - sth_offset = (uint16_t)read_16bitBE(0x10 + (0x02 + userdata_size) * (target_stream - 1), streamFile); + sth_offset = (uint16_t)read_16bitBE(0x10 + (0x02 + userdata_size) * (target_stream - 1), sf); #if 0 snr_offset = sth_offset + 0x04; @@ -466,7 +466,7 @@ VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) { break; } - sth_offset2 = (uint16_t)read_16bitBE(0x10 + (0x02 + userdata_size) * 1, streamFile); + sth_offset2 = (uint16_t)read_16bitBE(0x10 + (0x02 + userdata_size) * 1, sf); if (sns_offset == read_32bitBE(sth_offset2, sthFile)) { read_32bit = read_32bitBE; } else if (sns_offset == read_32bitLE(sth_offset2, sthFile)) { @@ -500,7 +500,7 @@ fail: } /* open map/mpf+mus pairs that aren't exact pairs, since EA's games can load any combo */ -static STREAMFILE *open_mapfile_pair(STREAMFILE *streamFile, int track, int num_tracks) { +static STREAMFILE *open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) { static const char *const mapfile_pairs[][2] = { /* standard cases, replace map part with mus part (from the end to preserve prefixes) */ {"FreSkate.mpf", "track.mus,ram.mus"}, /* Skate It */ @@ -527,11 +527,11 @@ static STREAMFILE *open_mapfile_pair(STREAMFILE *streamFile, int track, int num_ /* if loading the first track, try opening MUS with the same name first (most common scenario) */ if (track == 0) { - musFile = open_streamfile_by_ext(streamFile, "mus"); + musFile = open_streamfile_by_ext(sf, "mus"); if (musFile) return musFile; } - get_streamfile_filename(streamFile, file_name, PATH_LIMIT); + get_streamfile_filename(sf, file_name, PATH_LIMIT); file_len = strlen(file_name); for (i = 0; i < pair_count; i++) { @@ -572,10 +572,10 @@ static STREAMFILE *open_mapfile_pair(STREAMFILE *streamFile, int track, int num_ strncpy(file_name, pch, PATH_LIMIT - 1); } - musFile = open_streamfile_by_filename(streamFile, file_name); + musFile = open_streamfile_by_filename(sf, file_name); if (musFile) return musFile; - get_streamfile_filename(streamFile, file_name, PATH_LIMIT); /* reset for next loop */ + get_streamfile_filename(sf, file_name, PATH_LIMIT); /* reset for next loop */ } /* hack when when multiple maps point to the same mus, uses name before "+" @@ -584,7 +584,7 @@ static STREAMFILE *open_mapfile_pair(STREAMFILE *streamFile, int track, int num_ char *mod_name = strchr(file_name, '+'); if (mod_name) { mod_name[0] = '\0'; - musFile = open_streamfile_by_filename(streamFile, file_name); + musFile = open_streamfile_by_filename(sf, file_name); if (musFile) return musFile; } } @@ -594,7 +594,7 @@ static STREAMFILE *open_mapfile_pair(STREAMFILE *streamFile, int track, int num_ } /* EA MPF/MUS combo - used in older 7th gen games for storing interactive music */ -VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) { +VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE* sf) { uint32_t num_tracks, track_start, track_hash, mus_sounds, mus_stream = 0; uint8_t version, sub_version; off_t tracks_table, samples_table, eof_offset, table_offset, entry_offset, snr_offset, sns_offset; @@ -602,30 +602,30 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) { STREAMFILE *musFile = NULL; VGMSTREAM *vgmstream = NULL; int i; - int target_stream = streamFile->stream_index, total_streams, is_ram = 0; + int target_stream = sf->stream_index, total_streams, is_ram = 0; /* check extension */ - if (!check_extensions(streamFile, "mpf")) + if (!check_extensions(sf, "mpf")) goto fail; /* detect endianness */ - if (read_32bitBE(0x00, streamFile) == 0x50464478) { /* "PFDx" */ + if (read_32bitBE(0x00, sf) == 0x50464478) { /* "PFDx" */ read_32bit = read_32bitBE; - } else if (read_32bitLE(0x00, streamFile) == 0x50464478) { /* "xDFP" */ + } else if (read_32bitLE(0x00, sf) == 0x50464478) { /* "xDFP" */ read_32bit = read_32bitLE; } else { goto fail; } - version = read_8bit(0x04, streamFile); - sub_version = read_8bit(0x05, streamFile); + version = read_8bit(0x04, sf); + sub_version = read_8bit(0x05, sf); if (version != 5 || sub_version < 2 || sub_version > 3) goto fail; - num_tracks = read_8bit(0x0d, streamFile); + num_tracks = read_8bit(0x0d, sf); - tracks_table = read_32bit(0x2c, streamFile); - samples_table = read_32bit(0x34, streamFile); - eof_offset = read_32bit(0x38, streamFile); + tracks_table = read_32bit(0x2c, sf); + samples_table = read_32bit(0x34, sf); + eof_offset = read_32bit(0x38, sf); total_streams = (eof_offset - samples_table) / 0x08; if (target_stream == 0) target_stream = 1; @@ -633,23 +633,23 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) { goto fail; for (i = num_tracks - 1; i >= 0; i--) { - entry_offset = read_32bit(tracks_table + i * 0x04, streamFile) * 0x04; - track_start = read_32bit(entry_offset + 0x00, streamFile); + entry_offset = read_32bit(tracks_table + i * 0x04, sf) * 0x04; + track_start = read_32bit(entry_offset + 0x00, sf); if (track_start <= target_stream - 1) { - track_hash = read_32bitBE(entry_offset + 0x08, streamFile); + track_hash = read_32bitBE(entry_offset + 0x08, sf); is_ram = (track_hash == 0xF1F1F1F1); /* checks to distinguish it from older versions */ if (is_ram) { - if (read_32bitBE(entry_offset + 0x0c, streamFile) != 0x00) + if (read_32bitBE(entry_offset + 0x0c, sf) != 0x00) goto fail; - track_hash = read_32bitBE(entry_offset + 0x14, streamFile); + track_hash = read_32bitBE(entry_offset + 0x14, sf); if (track_hash == 0xF1F1F1F1) continue; /* empty track */ } else { - if (read_32bitBE(entry_offset + 0x0c, streamFile) == 0x00) + if (read_32bitBE(entry_offset + 0x0c, sf) == 0x00) goto fail; } @@ -659,7 +659,7 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) { } /* open MUS file that matches this track */ - musFile = open_mapfile_pair(streamFile, i, num_tracks); + musFile = open_mapfile_pair(sf, i, num_tracks); if (!musFile) goto fail; @@ -726,38 +726,38 @@ fail: } /* EA TMX - used for engine sounds in NFS games (2007-present) */ -VGMSTREAM * init_vgmstream_ea_tmx(STREAMFILE *streamFile) { +VGMSTREAM * init_vgmstream_ea_tmx(STREAMFILE* sf) { uint32_t num_sounds, sound_type; off_t table_offset, data_offset, entry_offset, sound_offset; VGMSTREAM *vgmstream = NULL; - int target_stream = streamFile->stream_index; + int target_stream = sf->stream_index; - if (!check_extensions(streamFile, "tmx")) + if (!check_extensions(sf, "tmx")) goto fail; /* always little endian */ - if (read_32bitLE(0x0c, streamFile) != 0x30303031) /* "0001" */ + if (read_32bitLE(0x0c, sf) != 0x30303031) /* "0001" */ goto fail; - num_sounds = read_32bitLE(0x20, streamFile); - table_offset = read_32bitLE(0x58, streamFile); - data_offset = read_32bitLE(0x5c, streamFile); + num_sounds = read_32bitLE(0x20, sf); + table_offset = read_32bitLE(0x58, sf); + data_offset = read_32bitLE(0x5c, sf); if (target_stream == 0) target_stream = 1; if (target_stream < 0 || num_sounds == 0 || target_stream > num_sounds) goto fail; entry_offset = table_offset + (target_stream - 1) * 0x24; - sound_type = read_32bitLE(entry_offset + 0x00, streamFile); - sound_offset = read_32bitLE(entry_offset + 0x08, streamFile) + data_offset; + sound_type = read_32bitLE(entry_offset + 0x00, sf); + sound_offset = read_32bitLE(entry_offset + 0x08, sf) + data_offset; switch (sound_type) { case 0x47494E20: /* "GIN " */ - vgmstream = init_vgmstream_gin_header(streamFile, sound_offset); + vgmstream = init_vgmstream_gin_header(sf, sound_offset); if (!vgmstream) goto fail; break; case 0x534E5220: /* "SNR " */ - vgmstream = init_vgmstream_eaaudiocore_header(streamFile, NULL, sound_offset, 0x00, meta_EA_SNR_SNS, 0); + vgmstream = init_vgmstream_eaaudiocore_header(sf, NULL, sound_offset, 0x00, meta_EA_SNR_SNS, 0); if (!vgmstream) goto fail; break; default: @@ -772,27 +772,27 @@ fail: } /* EA Harmony Sample Bank - used in 8th gen EA Sports games */ -VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE *streamFile) { +VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE *sf) { uint32_t num_dsets, set_sounds, chunk_id, data_offset, table_offset, dset_offset, base_offset, sound_table_offset, sound_offset; uint32_t i, j; uint8_t set_type, flag, offset_size; char sound_name[STREAM_NAME_SIZE]; - STREAMFILE *sbsFile = NULL, *streamData = NULL; + STREAMFILE *sbsFile = NULL, *sf_data = NULL; VGMSTREAM *vgmstream = NULL; - int target_stream = streamFile->stream_index, total_sounds, local_target, is_streamed = 0; + int target_stream = sf->stream_index, total_sounds, local_target, is_streamed = 0; uint32_t(*read_u32)(off_t, STREAMFILE*); uint16_t(*read_u16)(off_t, STREAMFILE*); - if (!check_extensions(streamFile, "sbr")) + if (!check_extensions(sf, "sbr")) goto fail; /* Logically, big endian version starts with SBbe. However, this format is * only used on 8th gen systems so far so big endian version probably doesn't exist. */ - if (read_32bitBE(0x00, streamFile) == 0x53426C65) { /* "SBle" */ + if (read_32bitBE(0x00, sf) == 0x53426C65) { /* "SBle" */ read_u32 = read_u32le; read_u16 = read_u16le; #if 0 - } else if (read_32bitBE(0x00, streamFile) == 0x53426265) { /* "SBbe" */ + } else if (read_32bitBE(0x00, sf) == 0x53426265) { /* "SBbe" */ read_32bit = read_u32be; read_16bit = read_u16be; #endif @@ -800,9 +800,9 @@ VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE *streamFile) { goto fail; } - num_dsets = read_u16(0x0a, streamFile); - data_offset = read_u32(0x20, streamFile); - table_offset = read_u32(0x24, streamFile); + num_dsets = read_u16(0x0a, sf); + data_offset = read_u32(0x20, sf); + table_offset = read_u32(0x24, sf); if (target_stream == 0) target_stream = 1; if (target_stream < 0) @@ -814,17 +814,17 @@ VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE *streamFile) { /* The bank is split into DSET sections each of which references one or multiple sounds. */ /* Each set can contain RAM sounds (stored in SBR in data section) or streamed sounds (stored separately in SBS file). */ for (i = 0; i < num_dsets; i++) { - dset_offset = read_u32(table_offset + 0x08 * i, streamFile); - if (read_u32(dset_offset, streamFile) != 0x44534554) /* "DSET" */ + dset_offset = read_u32(table_offset + 0x08 * i, sf); + if (read_u32(dset_offset, sf) != 0x44534554) /* "DSET" */ goto fail; - set_sounds = read_u32(dset_offset + 0x38, streamFile); + set_sounds = read_u32(dset_offset + 0x38, sf); local_target = target_stream - total_sounds - 1; dset_offset += 0x48; /* Find RAM or OFF chunk */ while(1) { - chunk_id = read_u32(dset_offset, streamFile); + chunk_id = read_u32(dset_offset, sf); if (chunk_id == 0x2E52414D) { /* ".RAM" */ break; } else if (chunk_id == 0x2E4F4646) { /* ".OFF" */ @@ -840,70 +840,70 @@ VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE *streamFile) { } /* Different set types store offsets differently */ - set_type = read_u8(dset_offset + 0x05, streamFile); + set_type = read_u8(dset_offset + 0x05, sf); if (set_type == 0x00) { total_sounds++; if (local_target < 0 || local_target > 0) continue; - sound_offset = read_u32(dset_offset + 0x08, streamFile); + sound_offset = read_u32(dset_offset + 0x08, sf); } else if (set_type == 0x01) { total_sounds += 2; if (local_target < 0 || local_target > 1) continue; - base_offset = read_u32(dset_offset + 0x08, streamFile); + base_offset = read_u32(dset_offset + 0x08, sf); if (local_target == 0) { sound_offset = base_offset; } else { - sound_offset = base_offset + read_u16(dset_offset + 0x06, streamFile); + sound_offset = base_offset + read_u16(dset_offset + 0x06, sf); } } else if (set_type == 0x02) { - flag = read_u8(dset_offset + 0x06, streamFile); - offset_size = read_u8(dset_offset + 0x07, streamFile); - base_offset = read_u32(dset_offset + 0x08, streamFile); - sound_table_offset = read_u32(dset_offset + 0x10, streamFile); + flag = read_u8(dset_offset + 0x06, sf); + offset_size = read_u8(dset_offset + 0x07, sf); + base_offset = read_u32(dset_offset + 0x08, sf); + sound_table_offset = read_u32(dset_offset + 0x10, sf); total_sounds += set_sounds; if (local_target < 0 || local_target >= set_sounds) continue; if (offset_size == 0x01) { - sound_offset = read_u8(sound_table_offset + 0x01 * local_target, streamFile); + sound_offset = read_u8(sound_table_offset + 0x01 * local_target, sf); for (j = 0; j < flag; j++) sound_offset *= 2; } else if (offset_size == 0x02) { - sound_offset = read_u16(sound_table_offset + 0x02 * local_target, streamFile); + sound_offset = read_u16(sound_table_offset + 0x02 * local_target, sf); for (j = 0; j < flag; j++) sound_offset *= 2; } else if (offset_size == 0x04) { - sound_offset = read_u32(sound_table_offset + 0x04 * local_target, streamFile); + sound_offset = read_u32(sound_table_offset + 0x04 * local_target, sf); } sound_offset += base_offset; } else if (set_type == 0x03) { - offset_size = read_u8(dset_offset + 0x07, streamFile); - set_sounds = read_u32(dset_offset + 0x08, streamFile); - sound_table_offset = read_u32(dset_offset + 0x10, streamFile); + offset_size = read_u8(dset_offset + 0x07, sf); + set_sounds = read_u32(dset_offset + 0x08, sf); + sound_table_offset = read_u32(dset_offset + 0x10, sf); total_sounds += set_sounds; if (local_target < 0 || local_target >= set_sounds) continue; if (offset_size == 0x01) { - sound_offset = read_u8(sound_table_offset + 0x01 * local_target, streamFile); + sound_offset = read_u8(sound_table_offset + 0x01 * local_target, sf); } else if (offset_size == 0x02) { - sound_offset = read_u16(sound_table_offset + 0x02 * local_target, streamFile); + sound_offset = read_u16(sound_table_offset + 0x02 * local_target, sf); } else if (offset_size == 0x04) { - sound_offset = read_u32(sound_table_offset + 0x04 * local_target, streamFile); + sound_offset = read_u32(sound_table_offset + 0x04 * local_target, sf); } } else if (set_type == 0x04) { total_sounds += set_sounds; if (local_target < 0 || local_target >= set_sounds) continue; - sound_table_offset = read_u32(dset_offset + 0x10, streamFile); - sound_offset = read_u32(sound_table_offset + 0x08 * local_target, streamFile); + sound_table_offset = read_u32(dset_offset + 0x10, sf); + sound_offset = read_u32(sound_table_offset + 0x08 * local_target, sf); } else { goto fail; } @@ -922,29 +922,29 @@ VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE *streamFile) { if (!is_streamed) { /* RAM asset */ - if (read_32bitBE(data_offset, streamFile) != 0x64617461) /* "data" */ + if (read_32bitBE(data_offset, sf) != 0x64617461) /* "data" */ goto fail; - streamData = streamFile; + sf_data = sf; sound_offset += data_offset; } else { /* streamed asset */ - sbsFile = open_streamfile_by_ext(streamFile, "sbs"); + sbsFile = open_streamfile_by_ext(sf, "sbs"); if (!sbsFile) goto fail; if (read_32bitBE(0x00, sbsFile) != 0x64617461) /* "data" */ goto fail; - streamData = sbsFile; + sf_data = sbsFile; - if (read_32bitBE(sound_offset, streamData) == 0x736C6F74) { + if (read_32bitBE(sound_offset, sf_data) == 0x736C6F74) { /* skip "slot" section */ sound_offset += 0x30; } } - vgmstream = init_vgmstream_eaaudiocore_header(streamData, NULL, sound_offset, 0x00, meta_EA_SPS, 0); + vgmstream = init_vgmstream_eaaudiocore_header(sf_data, NULL, sound_offset, 0x00, meta_EA_SPS, 0); if (!vgmstream) goto fail; @@ -982,24 +982,24 @@ typedef struct { } eaac_header; static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf_data, eaac_header *eaac); -static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *streamFile, eaac_header *eaac, off_t start_offset); -static STREAMFILE *setup_eaac_streamfile(eaac_header *ea, STREAMFILE *streamHead, STREAMFILE *streamData); -static size_t calculate_eaac_size(STREAMFILE *streamFile, eaac_header *ea, uint32_t num_samples, off_t start_offset, int is_ram); +static layered_layout_data* build_layered_eaaudiocore(STREAMFILE* sf, eaac_header *eaac, off_t start_offset); +static STREAMFILE *setup_eaac_streamfile(eaac_header *ea, STREAMFILE* sf_head, STREAMFILE* sf_data); +static size_t calculate_eaac_size(STREAMFILE* sf, eaac_header *ea, uint32_t num_samples, off_t start_offset, int is_ram); /* EA newest header from RwAudioCore (RenderWare?) / EAAudioCore library (still generated by sx.exe). * Audio "assets" come in separate RAM headers (.SNR/SPH) and raw blocked streams (.SNS/SPS), * or together in pseudoformats (.SNU, .SBR+.SBS banks, .AEMS, .MUS, etc). * Some .SNR include stream data, while .SPS have headers so .SPH is optional. */ -static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type, int standalone) { +static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMFILE* sf_data, off_t header_offset, off_t start_offset, meta_t meta_type, int standalone) { VGMSTREAM * vgmstream = NULL; - STREAMFILE* temp_streamFile = NULL, *streamFile = NULL, *snsFile = NULL; + STREAMFILE *temp_sf = NULL, *sf = NULL, *snsFile = NULL; uint32_t header1, header2, header_block_size = 0, header_size; uint8_t header_block_id; eaac_header eaac = {0}; if (meta_type == meta_EA_SPS) { - header_block_id = read_8bit(header_offset, streamHead); - header_block_size = read_32bitBE(header_offset, streamHead) & 0x00FFFFFF; + header_block_id = read_8bit(header_offset, sf_head); + header_block_size = read_32bitBE(header_offset, sf_head) & 0x00FFFFFF; if (header_block_id != EAAC_BLOCKID1_HEADER) goto fail; @@ -1007,8 +1007,8 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST } /* EA SNR/SPH header */ - header1 = (uint32_t)read_32bitBE(header_offset + 0x00, streamHead); - header2 = (uint32_t)read_32bitBE(header_offset + 0x04, streamHead); + header1 = (uint32_t)read_32bitBE(header_offset + 0x00, sf_head); + header2 = (uint32_t)read_32bitBE(header_offset + 0x04, sf_head); eaac.version = (header1 >> 28) & 0x0F; /* 4 bits */ eaac.codec = (header1 >> 24) & 0x0F; /* 4 bits */ eaac.channel_config = (header1 >> 18) & 0x3F; /* 6 bits */ @@ -1053,15 +1053,9 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST header_size = 0x08; if (eaac.loop_flag) { header_size += 0x04; - eaac.loop_start = read_32bitBE(header_offset + 0x08, streamHead); + eaac.loop_start = read_32bitBE(header_offset + 0x08, sf_head); eaac.loop_end = eaac.num_samples; - /* TODO: EATrax has extra values in header, which would coexist with loop values */ - if (eaac.codec == EAAC_CODEC_EATRAX) { - VGM_LOG("EA EAAC: unknown loop header for EATrax\n"); - goto fail; - } - /* TODO: need more cases to test how layout/streamfiles react */ if (eaac.loop_start > 0 && !( eaac.codec == EAAC_CODEC_EALAYER3_V1 || @@ -1080,7 +1074,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST case EAAC_TYPE_STREAM: if (eaac.loop_flag) { header_size += 0x04; - eaac.loop_offset = read_32bitBE(header_offset + 0x0c, streamHead); + eaac.loop_offset = read_32bitBE(header_offset + 0x0c, sf_head); } break; case EAAC_TYPE_GIGASAMPLE: /* rarely seen [Def Jam Icon (X360)] */ @@ -1089,7 +1083,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST goto fail; } header_size += 0x04; - eaac.prefetch_samples = read_32bitBE(header_offset + 0x08, streamHead); + eaac.prefetch_samples = read_32bitBE(header_offset + 0x08, sf_head); break; } @@ -1123,7 +1117,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST } else if (eaac.loop_start > 0) { /* RAM assets have two blocks in case of actual loops */ /* find the second block by getting the first block size */ - eaac.loop_offset = read_32bitBE(eaac.stream_offset, streamHead) & 0x00FFFFFF; + eaac.loop_offset = read_32bitBE(eaac.stream_offset, sf_head) & 0x00FFFFFF; } else { /* RAM assets have only one block in case of full loops */ eaac.loop_offset = 0x00; /* implicit */ @@ -1133,15 +1127,15 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST if (eaac.version == EAAC_VERSION_V0 && eaac.streamed) { /* open SNS file if needed */ if (standalone) { - snsFile = open_streamfile_by_ext(streamHead, "sns"); - streamData = snsFile; + snsFile = open_streamfile_by_ext(sf_head, "sns"); + sf_data = snsFile; } - if (!streamData) goto fail; + if (!sf_data) goto fail; } /* build streamfile with audio data */ - streamFile = setup_eaac_streamfile(&eaac, streamHead, streamData); - if (!streamFile) goto fail; + sf = setup_eaac_streamfile(&eaac, sf_head, sf_data); + if (!sf) goto fail; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(eaac.channels,eaac.loop_flag); @@ -1152,7 +1146,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST vgmstream->loop_start_sample = eaac.loop_start; vgmstream->loop_end_sample = eaac.loop_end; vgmstream->meta_type = meta_type; - vgmstream->stream_size = get_streamfile_size(streamFile); + vgmstream->stream_size = get_streamfile_size(sf); /* EA decoder list and known internal FourCCs */ switch(eaac.codec) { @@ -1168,14 +1162,14 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST /* special (if hacky) loop handling, see comments */ if (eaac.loop_start > 0) { - segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamFile, &eaac); + segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, &eaac); if (!data) goto fail; vgmstream->layout_data = data; vgmstream->coding_type = data->segments[0]->coding_type; vgmstream->layout_type = layout_segmented; } else { - vgmstream->layout_data = build_layered_eaaudiocore(streamFile, &eaac, 0x00); + vgmstream->layout_data = build_layered_eaaudiocore(sf, &eaac, 0x00); if (!vgmstream->layout_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_layered; @@ -1189,7 +1183,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST /* special (if hacky) loop handling, see comments */ if (eaac.loop_start > 0) { - segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamFile, &eaac); + segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, &eaac); if (!data) goto fail; vgmstream->layout_data = data; vgmstream->coding_type = data->segments[0]->coding_type; @@ -1198,7 +1192,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST vgmstream->coding_type = coding_EA_XAS_V1; vgmstream->layout_type = layout_blocked_ea_sns; } - + break; #ifdef VGM_USE_MPEG @@ -1214,17 +1208,17 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST /* special (if hacky) loop handling, see comments */ if (eaac.loop_start > 0) { - segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamFile, &eaac); + segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, &eaac); if (!data) goto fail; vgmstream->layout_data = data; vgmstream->coding_type = data->segments[0]->coding_type; vgmstream->layout_type = layout_segmented; } else { - temp_streamFile = setup_eaac_audio_streamfile(streamFile, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00); - if (!temp_streamFile) goto fail; + temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00); + if (!temp_sf) goto fail; - vgmstream->codec_data = init_mpeg_custom(temp_streamFile, 0x00, &vgmstream->coding_type, vgmstream->channels, type, &cfg); + vgmstream->codec_data = init_mpeg_custom(temp_sf, 0x00, &vgmstream->coding_type, vgmstream->channels, type, &cfg); if (!vgmstream->codec_data) goto fail; vgmstream->layout_type = layout_none; } @@ -1246,18 +1240,18 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST /* EATrax is "buffered" ATRAC9, uses custom IO since it's kind of complex to add to the decoder */ cfg.channels = eaac.channels; - cfg.config_data = read_32bitBE(header_offset + 0x08,streamHead); - /* 0x10: frame size? (same as config data?) */ - /* actual data size without blocks, LE b/c why make sense (but don't use it in case of truncated files) */ - //total_size = read_32bitLE(header_offset + 0x0c,streamHead); + /* sub-header after normal header */ + cfg.config_data = read_32bitBE(header_offset + header_size + 0x00,sf_head); + /* 0x04: data size without blocks, LE b/c why make sense (but don't use it in case of truncated files) */ + /* 0x08: 16b frame size (same as config data) */ vgmstream->codec_data = init_atrac9(&cfg); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_ATRAC9; vgmstream->layout_type = layout_none; - temp_streamFile = setup_eaac_audio_streamfile(streamFile, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00); - if (!temp_streamFile) goto fail; + temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00); + if (!temp_sf) goto fail; break; } @@ -1268,10 +1262,10 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST case EAAC_CODEC_EAMP3: { /* "EM30"?: EAMP3 [Need for Speed 2015 (PS4)] */ mpeg_custom_config cfg = {0}; - temp_streamFile = setup_eaac_audio_streamfile(streamFile, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00); - if (!temp_streamFile) goto fail; + temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00); + if (!temp_sf) goto fail; - vgmstream->codec_data = init_mpeg_custom(temp_streamFile, 0x00, &vgmstream->coding_type, vgmstream->channels, MPEG_EAMP3, &cfg); + vgmstream->codec_data = init_mpeg_custom(temp_sf, 0x00, &vgmstream->coding_type, vgmstream->channels, MPEG_EAMP3, &cfg); if (!vgmstream->codec_data) goto fail; vgmstream->layout_type = layout_none; @@ -1282,7 +1276,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST #ifdef VGM_USE_FFMPEG case EAAC_CODEC_EAOPUS: { /* "Eop0"? : EAOpus [FIFA 17 (PC), FIFA 19 (Switch)]*/ - vgmstream->layout_data = build_layered_eaaudiocore(streamFile, &eaac, 0x00); + vgmstream->layout_data = build_layered_eaaudiocore(sf, &eaac, 0x00); if (!vgmstream->layout_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_layered; @@ -1296,37 +1290,37 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST goto fail; } - if (!vgmstream_open_stream(vgmstream, temp_streamFile ? temp_streamFile : streamFile, 0x00)) + if (!vgmstream_open_stream(vgmstream, temp_sf ? temp_sf : sf, 0x00)) goto fail; - close_streamfile(streamFile); + close_streamfile(sf); close_streamfile(snsFile); - close_streamfile(temp_streamFile); + close_streamfile(temp_sf); return vgmstream; fail: - close_streamfile(streamFile); + close_streamfile(sf); close_streamfile(snsFile); - close_streamfile(temp_streamFile); + close_streamfile(temp_sf); close_vgmstream(vgmstream); return NULL; } -static size_t calculate_eaac_size(STREAMFILE *streamFile, eaac_header *ea, uint32_t num_samples, off_t start_offset, int is_ram) { +static size_t calculate_eaac_size(STREAMFILE *sf, eaac_header *ea, uint32_t num_samples, off_t start_offset, int is_ram) { uint32_t block_size; uint8_t block_id; size_t stream_size, file_size; off_t block_offset; int looped; - file_size = get_streamfile_size(streamFile); + file_size = get_streamfile_size(sf); block_offset = start_offset; stream_size = 0; looped = 0; while (block_offset < file_size) { - block_id = read_8bit(block_offset, streamFile); - block_size = read_32bitBE(block_offset, streamFile) & 0x00FFFFFF; + block_id = read_8bit(block_offset, sf); + block_size = read_32bitBE(block_offset, sf) & 0x00FFFFFF; /* stop when we reach the end marker */ if (ea->version == EAAC_VERSION_V0) { @@ -1343,17 +1337,13 @@ static size_t calculate_eaac_size(STREAMFILE *streamFile, eaac_header *ea, uint3 stream_size += block_size; block_offset += block_size; - /* RAM data only consists of one block */ - if (is_ram) - break; - - if (ea->version == EAAC_VERSION_V0 && block_id == EAAC_BLOCKID0_END) { - if (ea->loop_offset > 0) { - if (!looped) looped = 1; - else break; - } else { - break; - } + if (is_ram) { + /* RAM data only consists of one block (two for looped sounds) */ + if (ea->loop_start > 0 && !looped) looped = 1; + else break; + } else if (ea->version == EAAC_VERSION_V0 && block_id == EAAC_BLOCKID0_END) { + if (ea->loop_offset > 0 && !looped) looped = 1; + else break; } } @@ -1364,71 +1354,71 @@ fail: } -static STREAMFILE *setup_eaac_streamfile(eaac_header *ea, STREAMFILE *streamHead, STREAMFILE *streamData) { +static STREAMFILE *setup_eaac_streamfile(eaac_header *ea, STREAMFILE* sf_head, STREAMFILE* sf_data) { size_t data_size; - STREAMFILE *new_streamFile = NULL; - STREAMFILE *temp_streamFile = NULL; - STREAMFILE *stream_segments[2] = { 0 }; + STREAMFILE *new_sf = NULL; + STREAMFILE *temp_sf = NULL; + STREAMFILE *sf_segments[2] = { 0 }; if (ea->version == EAAC_VERSION_V0) { switch (ea->type) { case EAAC_TYPE_RAM: /* both header and data in SNR */ - data_size = calculate_eaac_size(streamHead, ea, ea->num_samples, ea->stream_offset, 1); + data_size = calculate_eaac_size(sf_head, ea, ea->num_samples, ea->stream_offset, 1); if (data_size == 0) goto fail; - new_streamFile = open_wrap_streamfile(streamHead); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; + new_sf = open_wrap_streamfile(sf_head); + if (!new_sf) goto fail; + temp_sf = new_sf; - new_streamFile = open_clamp_streamfile(temp_streamFile, ea->stream_offset, data_size); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; + new_sf = open_clamp_streamfile(temp_sf, ea->stream_offset, data_size); + if (!new_sf) goto fail; + temp_sf = new_sf; break; case EAAC_TYPE_STREAM: /* header in SNR, data in SNS */ - data_size = calculate_eaac_size(streamData, ea, ea->num_samples, ea->stream_offset, 0); + data_size = calculate_eaac_size(sf_data, ea, ea->num_samples, ea->stream_offset, 0); if (data_size == 0) goto fail; - new_streamFile = open_wrap_streamfile(streamData); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; + new_sf = open_wrap_streamfile(sf_data); + if (!new_sf) goto fail; + temp_sf = new_sf; - new_streamFile = open_clamp_streamfile(temp_streamFile, ea->stream_offset, data_size); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; + new_sf = open_clamp_streamfile(temp_sf, ea->stream_offset, data_size); + if (!new_sf) goto fail; + temp_sf = new_sf; break; case EAAC_TYPE_GIGASAMPLE: /* header and prefetched data in SNR, rest of data in SNS */ /* open prefetched data */ - data_size = calculate_eaac_size(streamHead, ea, ea->prefetch_samples, ea->prefetch_offset, 1); + data_size = calculate_eaac_size(sf_head, ea, ea->prefetch_samples, ea->prefetch_offset, 1); if (data_size == 0) goto fail; - new_streamFile = open_wrap_streamfile(streamHead); - if (!new_streamFile) goto fail; - stream_segments[0] = new_streamFile; + new_sf = open_wrap_streamfile(sf_head); + if (!new_sf) goto fail; + sf_segments[0] = new_sf; - new_streamFile = open_clamp_streamfile(stream_segments[0], ea->prefetch_offset, data_size); - if (!new_streamFile) goto fail; - stream_segments[0] = new_streamFile; + new_sf = open_clamp_streamfile(sf_segments[0], ea->prefetch_offset, data_size); + if (!new_sf) goto fail; + sf_segments[0] = new_sf; /* open main data */ - data_size = calculate_eaac_size(streamData, ea, ea->num_samples - ea->prefetch_samples, ea->stream_offset, 0); + data_size = calculate_eaac_size(sf_data, ea, ea->num_samples - ea->prefetch_samples, ea->stream_offset, 0); if (data_size == 0) goto fail; - new_streamFile = open_wrap_streamfile(streamData); - if (!new_streamFile) goto fail; - stream_segments[1] = new_streamFile; + new_sf = open_wrap_streamfile(sf_data); + if (!new_sf) goto fail; + sf_segments[1] = new_sf; - new_streamFile = open_clamp_streamfile(stream_segments[1], ea->stream_offset, data_size); - if (!new_streamFile) goto fail; - stream_segments[1] = new_streamFile; + new_sf = open_clamp_streamfile(sf_segments[1], ea->stream_offset, data_size); + if (!new_sf) goto fail; + sf_segments[1] = new_sf; - new_streamFile = open_multifile_streamfile(stream_segments, 2); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; - stream_segments[0] = NULL; - stream_segments[1] = NULL; + new_sf = open_multifile_streamfile(sf_segments, 2); + if (!new_sf) goto fail; + temp_sf = new_sf; + sf_segments[0] = NULL; + sf_segments[1] = NULL; break; } } else { @@ -1438,24 +1428,24 @@ static STREAMFILE *setup_eaac_streamfile(eaac_header *ea, STREAMFILE *streamHead goto fail; } - data_size = calculate_eaac_size(streamHead, ea, ea->num_samples, ea->stream_offset, ea->type == EAAC_TYPE_RAM); + data_size = calculate_eaac_size(sf_head, ea, ea->num_samples, ea->stream_offset, ea->type == EAAC_TYPE_RAM); if (data_size == 0) goto fail; - new_streamFile = open_wrap_streamfile(streamHead); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; + new_sf = open_wrap_streamfile(sf_head); + if (!new_sf) goto fail; + temp_sf = new_sf; - new_streamFile = open_clamp_streamfile(temp_streamFile, ea->stream_offset, data_size); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; + new_sf = open_clamp_streamfile(temp_sf, ea->stream_offset, data_size); + if (!new_sf) goto fail; + temp_sf = new_sf; } - return temp_streamFile; + return temp_sf; fail: - close_streamfile(stream_segments[0]); - close_streamfile(stream_segments[1]); - close_streamfile(temp_streamFile); + close_streamfile(sf_segments[0]); + close_streamfile(sf_segments[1]); + close_streamfile(temp_sf); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/genh.c b/Frameworks/vgmstream/vgmstream/src/meta/genh.c index 20a74194e..eb8a6f0a6 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/genh.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/genh.c @@ -454,6 +454,12 @@ static int parse_genh(STREAMFILE * streamFile, genh_header * genh) { genh->num_samples = genh->num_samples > 0 ? genh->num_samples : genh->loop_end_sample; genh->loop_flag = genh->loop_start_sample != -1; + /* fix for buggy GENHs that used to work before interleaved XBOX-IMA was added + * (could do check for other cases, but maybe it's better to give bad sound on nonsense values) */ + if (genh->codec == XBOX && genh->interleave < 0x24) { /* found as 0x2 */ + genh->interleave = 0; + } + return 1; fail: diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca.c b/Frameworks/vgmstream/vgmstream/src/meta/hca.c index 50080a538..d4d032436 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca.c @@ -6,7 +6,7 @@ #ifdef HCA_BRUTEFORCE static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* out_keycode, uint16_t subkey); #endif -static void find_hca_key(hca_codec_data * hca_data, unsigned long long * out_keycode, uint16_t subkey); +static void find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t subkey); /* CRI HCA - streamed audio from CRI ADX2/Atom middleware */ @@ -17,7 +17,6 @@ VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile) { VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE *streamFile, uint16_t subkey) { VGMSTREAM * vgmstream = NULL; hca_codec_data * hca_data = NULL; - unsigned long long keycode = 0; /* checks */ @@ -32,6 +31,7 @@ VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE *streamFile, uint16_t subkey) { /* find decryption key in external file or preloaded list */ if (hca_data->info.encryptionEnabled) { + uint64_t keycode = 0; uint8_t keybuf[0x08+0x02]; size_t keysize; @@ -56,7 +56,7 @@ VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE *streamFile, uint16_t subkey) { find_hca_key(hca_data, &keycode, subkey); } - clHCA_SetKey(hca_data->handle, keycode); //maybe should be done through hca_decoder.c? + clHCA_SetKey(hca_data->handle, (unsigned long long)keycode); //maybe should be done through hca_decoder.c? } @@ -139,25 +139,25 @@ static inline void test_key(hca_codec_data * hca_data, uint64_t key, uint16_t su } /* try to find the decryption key from a list. */ -static void find_hca_key(hca_codec_data* hca_data, unsigned long long* out_keycode, uint16_t subkey) { +static void find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t subkey) { const size_t keys_length = sizeof(hcakey_list) / sizeof(hcakey_info); int best_score = -1; int i,j; - *out_keycode = 0xCC55463930DBE1AB; /* defaults to PSO2 key, most common */ + *p_keycode = 0xCC55463930DBE1AB; /* defaults to PSO2 key, most common */ for (i = 0; i < keys_length; i++) { uint64_t key = hcakey_list[i].key; size_t subkeys_size = hcakey_list[i].subkeys_size; const uint16_t *subkeys = hcakey_list[i].subkeys; - test_key(hca_data, key, subkey, &best_score, out_keycode); + test_key(hca_data, key, subkey, &best_score, p_keycode); if (best_score == 1) goto done; if (subkeys_size > 0 && subkey == 0) { for (j = 0; j < subkeys_size; j++) { - test_key(hca_data, key, subkeys[j], &best_score, out_keycode); + test_key(hca_data, key, subkeys[j], &best_score, p_keycode); if (best_score == 1) goto done; } @@ -166,7 +166,7 @@ static void find_hca_key(hca_codec_data* hca_data, unsigned long long* out_keyco done: VGM_ASSERT(best_score > 1, "HCA: best key=%08x%08x (score=%i)\n", - (uint32_t)((*out_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*out_keycode & 0xFFFFFFFF), best_score); + (uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), best_score); VGM_ASSERT(best_score < 0, "HCA: key not found\n"); } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h index 2a88778da..bc3e32cf4 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -893,4 +893,6 @@ VGMSTREAM* init_vgmstream_bkhd_fx(STREAMFILE* sf); VGMSTREAM* init_vgmstream_encrypted(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_diva(STREAMFILE* sf); + #endif /*_META_H*/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/nus3audio.c b/Frameworks/vgmstream/vgmstream/src/meta/nus3audio.c index 60299b792..043a832ec 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/nus3audio.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/nus3audio.c @@ -1,56 +1,56 @@ #include "meta.h" #include "../coding/coding.h" -typedef enum { IDSP, OPUS, } nus3audio_codec; +typedef enum { IDSP, OPUS, RIFF, } nus3audio_codec; /* .nus3audio - Namco's newest newest audio container [Super Smash Bros. Ultimate (Switch)] */ -VGMSTREAM * init_vgmstream_nus3audio(STREAMFILE *streamFile) { - VGMSTREAM *vgmstream = NULL; - STREAMFILE *temp_streamFile = NULL; +VGMSTREAM* init_vgmstream_nus3audio(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + STREAMFILE* temp_sf = NULL; off_t subfile_offset = 0, name_offset = 0; size_t subfile_size = 0; nus3audio_codec codec; const char* fake_ext = NULL; - int total_subsongs, target_subsong = streamFile->stream_index; + int total_subsongs, target_subsong = sf->stream_index; /* checks */ - if (!check_extensions(streamFile, "nus3audio")) + if (!check_extensions(sf, "nus3audio")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x4E555333) /* "NUS3" */ + if (read_u32be(0x00,sf) != 0x4E555333) /* "NUS3" */ goto fail; - if (read_32bitLE(0x04,streamFile) + 0x08 != get_streamfile_size(streamFile)) + if (read_u32le(0x04,sf) + 0x08 != get_streamfile_size(sf)) goto fail; - if (read_32bitBE(0x08,streamFile) != 0x41554449) /* "AUDI" */ + if (read_u32be(0x08,sf) != 0x41554449) /* "AUDI" */ goto fail; /* parse existing chunks */ { off_t offset = 0x0c; - size_t file_size = get_streamfile_size(streamFile); + size_t file_size = get_streamfile_size(sf); uint32_t codec_id = 0; total_subsongs = 0; while (offset < file_size) { - uint32_t chunk_id = (uint32_t)read_32bitBE(offset+0x00, streamFile); - size_t chunk_size = (size_t)read_32bitLE(offset+0x04, streamFile); + uint32_t chunk_id = read_u32be(offset+0x00, sf); + size_t chunk_size = read_u32le(offset+0x04, sf); switch(chunk_id) { case 0x494E4458: /* "INDX": audio index */ - total_subsongs = read_32bitLE(offset+0x08 + 0x00,streamFile); + total_subsongs = read_u32le(offset+0x08 + 0x00,sf); if (target_subsong == 0) target_subsong = 1; if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; break; case 0x4E4D4F46: /* "NMOF": name offsets (absolute, inside TNNM) */ - name_offset = read_32bitLE(offset+0x08 + 0x04*(target_subsong-1),streamFile); + name_offset = read_u32le(offset+0x08 + 0x04*(target_subsong-1),sf); break; case 0x41444F46: /* "ADOF": audio offsets (absolute, inside PACK) */ - subfile_offset = read_32bitLE(offset+0x08 + 0x08*(target_subsong-1) + 0x00,streamFile); - subfile_size = read_32bitLE(offset+0x08 + 0x08*(target_subsong-1) + 0x04,streamFile); + subfile_offset = read_u32le(offset+0x08 + 0x08*(target_subsong-1) + 0x00,sf); + subfile_size = read_u32le(offset+0x08 + 0x08*(target_subsong-1) + 0x04,sf); break; case 0x544E4944: /* "TNID": tone ids? */ @@ -69,7 +69,7 @@ VGMSTREAM * init_vgmstream_nus3audio(STREAMFILE *streamFile) { goto fail; } - codec_id = read_32bitBE(subfile_offset, streamFile); + codec_id = read_u32be(subfile_offset, sf); switch(codec_id) { case 0x49445350: /* "IDSP" */ codec = IDSP; @@ -79,6 +79,10 @@ VGMSTREAM * init_vgmstream_nus3audio(STREAMFILE *streamFile) { codec = OPUS; fake_ext = "opus"; break; + case 0x52494646: /* "RIFF" [Gundam Versus (PS4)] */ + codec = RIFF; + fake_ext = "wav"; + break; default: VGM_LOG("NUS3AUDIO: unknown codec %x\n", codec_id); goto fail; @@ -86,17 +90,21 @@ VGMSTREAM * init_vgmstream_nus3audio(STREAMFILE *streamFile) { } - temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, fake_ext); - if (!temp_streamFile) goto fail; + temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, fake_ext); + if (!temp_sf) goto fail; /* init the VGMSTREAM */ switch(codec) { case IDSP: - vgmstream = init_vgmstream_idsp_namco(temp_streamFile); + vgmstream = init_vgmstream_idsp_namco(temp_sf); if (!vgmstream) goto fail; break; case OPUS: - vgmstream = init_vgmstream_opus_nus3(temp_streamFile); + vgmstream = init_vgmstream_opus_nus3(temp_sf); + if (!vgmstream) goto fail; + break; + case RIFF: + vgmstream = init_vgmstream_riff(temp_sf); if (!vgmstream) goto fail; break; default: @@ -105,13 +113,13 @@ VGMSTREAM * init_vgmstream_nus3audio(STREAMFILE *streamFile) { vgmstream->num_streams = total_subsongs; if (name_offset) /* null-terminated */ - read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamFile); + read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,sf); - close_streamfile(temp_streamFile); + close_streamfile(temp_sf); return vgmstream; fail: - close_streamfile(temp_streamFile); + close_streamfile(temp_sf); close_vgmstream(vgmstream); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/rsd.c b/Frameworks/vgmstream/vgmstream/src/meta/rsd.c index 96a8947d3..d1c8502b4 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/rsd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/rsd.c @@ -20,7 +20,7 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *streamFile) { loop_flag = 0; - codec = read_32bitBE(0x04,streamFile); + codec = (uint32_t)read_32bitBE(0x04,streamFile); channel_count = read_32bitLE(0x08, streamFile); /* 0x0c: always 16? */ sample_rate = read_32bitLE(0x10, streamFile); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c index ba55da073..f7ea4fb07 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c @@ -38,29 +38,34 @@ typedef struct { int32_t loop_end_sample; } wwise_header; +static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_offset); + /* Wwise - Audiokinetic Wwise (Wave Works Interactive Sound Engine) middleware */ -VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { +VGMSTREAM * init_vgmstream_wwise(STREAMFILE* sf) { VGMSTREAM * vgmstream = NULL; wwise_header ww = {0}; off_t start_offset, first_offset = 0xc; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL; - /* basic checks */ - /* .wem (Wwise Encoded Media) is "newer Wwise", used after the 2011.2 SDK (~july) - * .wav (ex. Shadowrun X360) and .ogg (ex. KOF XII X360), .xma (ex. Tron Evolution X360) are used in older Wwise */ - if (!check_extensions(streamFile,"wem,wav,lwav,ogg,logg,xma")) goto fail; - - if ((read_32bitBE(0x00,streamFile) != 0x52494646) && /* "RIFF" (LE) */ - (read_32bitBE(0x00,streamFile) != 0x52494658)) /* "RIFX" (BE) */ - goto fail; - if ((read_32bitBE(0x08,streamFile) != 0x57415645) && /* "WAVE" */ - (read_32bitBE(0x08,streamFile) != 0x58574D41)) /* "XWMA" */ + /* checks */ + /* .wem: newer "Wwise Encoded Media" used after the 2011.2 SDK (~july 2011) + * .wav: older ADPCM files [Punch Out!! (Wii)] + * .xma: older XMA files [Too Human (X360), Tron Evolution (X360)] + * .ogg: older Vorbis files [The King of Fighters XII (X360)] + * .bnk: Wwise banks for memory .wem detection */ + if (!check_extensions(sf,"wem,wav,lwav,ogg,logg,xma,bnk")) goto fail; + if (read_32bitBE(0x00,sf) != 0x52494646 && /* "RIFF" (LE) */ + read_32bitBE(0x00,sf) != 0x52494658) /* "RIFX" (BE) */ + goto fail; + if (read_32bitBE(0x08,sf) != 0x57415645 && /* "WAVE" */ + read_32bitBE(0x08,sf) != 0x58574D41) /* "XWMA" */ + goto fail; - ww.big_endian = read_32bitBE(0x00,streamFile) == 0x52494658;/* RIFX */ + ww.big_endian = read_32bitBE(0x00,sf) == 0x52494658; /* RIFX */ if (ww.big_endian) { /* Wwise honors machine's endianness (PC=RIFF, X360=RIFX --unlike XMA) */ read_32bit = read_32bitBE; read_16bit = read_16bitBE; @@ -69,7 +74,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { read_16bit = read_16bitLE; } - ww.file_size = streamFile->get_size(streamFile); + ww.file_size = sf->get_size(sf); #if 0 /* Wwise's RIFF size is often wonky, seemingly depending on codec: @@ -80,8 +85,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { * - some RIFX have LE size * (later we'll validate "data" which fortunately is correct) */ - if (read_32bit(0x04,streamFile)+0x04+0x04 != ww.file_size) { - VGM_LOG("WWISE: bad riff size (real=0x%x vs riff=0x%x)\n", read_32bit(0x04,streamFile)+0x04+0x04, ww.file_size); + if (read_32bit(0x04,sf)+0x04+0x04 != ww.file_size) { + VGM_LOG("WWISE: bad riff size (real=0x%x vs riff=0x%x)\n", read_32bit(0x04,sf)+0x04+0x04, ww.file_size); goto fail; } #endif @@ -91,44 +96,50 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { off_t fact_offset; size_t fact_size; - if (find_chunk(streamFile, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */ - if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, streamFile) == 0x4C794E20) /* "LyN " */ + if (find_chunk(sf, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */ + if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, sf) == 0x4C794E20) /* "LyN " */ goto fail; /* parsed elsewhere */ - /* Wwise doesn't use "fact", though */ } + /* Wwise doesn't use "fact", though */ } - /* parse format (roughly spec-compliant but some massaging is needed) */ { off_t loop_offset; size_t loop_size; /* find basic chunks */ - if (!find_chunk(streamFile, 0x666d7420,first_offset,0, &ww.fmt_offset,&ww.fmt_size, ww.big_endian, 0)) goto fail; /*"fmt "*/ - if (!find_chunk(streamFile, 0x64617461,first_offset,0, &ww.data_offset,&ww.data_size, ww.big_endian, 0)) goto fail; /*"data"*/ - - /* base fmt */ - if (ww.fmt_size < 0x12) goto fail; - ww.format = (uint16_t)read_16bit(ww.fmt_offset+0x00,streamFile); - - if (ww.format == 0x0165) { /* pseudo-XMA2WAVEFORMAT (always "fmt"+"XMA2", unlike .xma that may only have "XMA2") */ - if (!find_chunk(streamFile, 0x584D4132,first_offset,0, &ww.chunk_offset,NULL, ww.big_endian, 0)) - goto fail; - xma2_parse_xma2_chunk(streamFile, ww.chunk_offset,&ww.channels,&ww.sample_rate, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample); + if (read_32bitBE(0x0c, sf) == 0x584D4132) { /* "XMA2" with no "fmt" [Too Human (X360)] */ + ww.format = 0x0165; /* signal for below */ } - else { /* pseudo-WAVEFORMATEX */ - ww.channels = read_16bit(ww.fmt_offset+0x02,streamFile); - ww.sample_rate = read_32bit(ww.fmt_offset+0x04,streamFile); - ww.average_bps = read_32bit(ww.fmt_offset+0x08,streamFile);/* bytes per sec */ - ww.block_align = (uint16_t)read_16bit(ww.fmt_offset+0x0c,streamFile); - ww.bits_per_sample = (uint16_t)read_16bit(ww.fmt_offset+0x0e,streamFile); + else { + if (!find_chunk(sf, 0x666d7420,first_offset,0, &ww.fmt_offset,&ww.fmt_size, ww.big_endian, 0)) /* "fmt " */ + goto fail; + if (ww.fmt_size < 0x12) + goto fail; + ww.format = (uint16_t)read_16bit(ww.fmt_offset+0x00,sf); + } + + + if (ww.format == 0x0165) { + /* pseudo-XMA2WAVEFORMAT ("fmt"+"XMA2" or just "XMA2) */ + if (!find_chunk(sf, 0x584D4132,first_offset,0, &ww.chunk_offset,NULL, ww.big_endian, 0)) /* "XMA2" */ + goto fail; + xma2_parse_xma2_chunk(sf, ww.chunk_offset,&ww.channels,&ww.sample_rate, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample); + } + else { + /* pseudo-WAVEFORMATEX */ + ww.channels = read_16bit(ww.fmt_offset+0x02,sf); + ww.sample_rate = read_32bit(ww.fmt_offset+0x04,sf); + ww.average_bps = read_32bit(ww.fmt_offset+0x08,sf);/* bytes per sec */ + ww.block_align = (uint16_t)read_16bit(ww.fmt_offset+0x0c,sf); + ww.bits_per_sample = (uint16_t)read_16bit(ww.fmt_offset+0x0e,sf); if (ww.fmt_size > 0x10 && ww.format != 0x0165 && ww.format != 0x0166) /* ignore XMAWAVEFORMAT */ - ww.extra_size = (uint16_t)read_16bit(ww.fmt_offset+0x10,streamFile); + ww.extra_size = (uint16_t)read_16bit(ww.fmt_offset+0x10,sf); if (ww.extra_size >= 0x06) { /* always present (actual RIFFs only have it in WAVEFORMATEXTENSIBLE) */ /* mostly WAVEFORMATEXTENSIBLE's bitmask (see AkSpeakerConfig.h) */ - ww.channel_layout = read_32bit(ww.fmt_offset+0x14,streamFile); - /* latest games have a pseudo-format instead to handle more cases: + ww.channel_layout = read_32bit(ww.fmt_offset+0x14,sf); + /* later games (+2018?) have a pseudo-format instead to handle more cases: * - 8b: uNumChannels * - 4b: eConfigType (0=none, 1=standard, 2=ambisonic) * - 19b: uChannelMask */ @@ -138,40 +149,42 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { } } - /* find loop info */ - if (ww.format == 0x0166) { /* XMA2WAVEFORMATEX */ + /* find loop info ("XMA2" chunks already read them) */ + if (ww.format == 0x0166) { /* XMA2WAVEFORMATEX in fmt */ ww.chunk_offset = ww.fmt_offset; - xma2_parse_fmt_chunk_extra(streamFile, ww.chunk_offset, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample, ww.big_endian); + xma2_parse_fmt_chunk_extra(sf, ww.chunk_offset, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample, ww.big_endian); } - else if (find_chunk(streamFile, 0x736D706C,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"smpl", common */ + else if (find_chunk(sf, 0x736D706C,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /* "smpl", common */ if (loop_size >= 0x34 - && read_32bit(loop_offset+0x1c, streamFile)==1 /*loop count*/ - && read_32bit(loop_offset+0x24+4, streamFile)==0) { + && read_32bit(loop_offset+0x1c, sf)==1 /* loop count */ + && read_32bit(loop_offset+0x24+4, sf)==0) { ww.loop_flag = 1; - ww.loop_start_sample = read_32bit(loop_offset+0x24+0x8, streamFile); - ww.loop_end_sample = read_32bit(loop_offset+0x24+0xc,streamFile); - //todo fix repeat looping + ww.loop_start_sample = read_32bit(loop_offset+0x24+0x8, sf); + ww.loop_end_sample = read_32bit(loop_offset+0x24+0xc, sf) + 1; /* like standard RIFF */ } } - //else if (find_chunk(streamFile, 0x4C495354,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"LIST", common */ + //else if (find_chunk(sf, 0x4C495354,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"LIST", common */ // /* usually contains "cue"s with sample positions for events (ex. Platinum Games) but no real looping info */ //} - /* other Wwise specific: */ - //"JUNK": optional padding for aligment (0-size JUNK exists too) - //"akd ": seem to store extra info for Wwise editor (wave peaks/loudness/HDR envelope?) + /* other Wwise specific chunks: + * "JUNK": optional padding for aligment (0-size JUNK exists too) + * "akd ": seem to store extra info for Wwise editor (wave peaks/loudness/HDR envelope?) + */ + + if (!find_chunk(sf, 0x64617461,first_offset,0, &ww.data_offset,&ww.data_size, ww.big_endian, 0)) /* "data" */ + goto fail; } /* format to codec */ switch(ww.format) { case 0x0001: ww.codec = PCM; break; /* older Wwise */ case 0x0002: ww.codec = IMA; break; /* newer Wwise (conflicts with MSADPCM, probably means "platform's ADPCM") */ - //case 0x0011: ww.codec = IMA; break; /* older Wwise (used?) */ - case 0x0069: ww.codec = IMA; break; /* older Wwise (Spiderman Web of Shadows X360, LotR Conquest PC) */ + case 0x0069: ww.codec = IMA; break; /* older Wwise [Spiderman Web of Shadows (X360), LotR Conquest (PC)] */ case 0x0161: ww.codec = XWMA; break; /* WMAv2 */ case 0x0162: ww.codec = XWMA; break; /* WMAPro */ - case 0x0165: ww.codec = XMA2; break; /* always with the "XMA2" chunk, Wwise doesn't use XMA1 */ - case 0x0166: ww.codec = XMA2; break; + case 0x0165: ww.codec = XMA2; break; /* XMA2-chunk XMA (Wwise doesn't use XMA1) */ + case 0x0166: ww.codec = XMA2; break; /* fmt-chunk XMA */ case 0xAAC0: ww.codec = AAC; break; case 0xFFF0: ww.codec = DSP; break; case 0xFFFB: ww.codec = HEVAG; break; @@ -180,9 +193,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { case 0xFFFF: ww.codec = VORBIS; break; case 0x3039: ww.codec = OPUSNX; break; /* later renamed from "OPUS" */ case 0x3040: ww.codec = OPUS; break; -#if 0 - case 0x8311: ww.codec = PTADPCM; break; -#endif + case 0x8311: ww.codec = PTADPCM; break; /* newer, rare [Genshin Impact (PC)] */ default: goto fail; } @@ -192,7 +203,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { if (ww.extra_size == 0x0c + ww.channels * 0x2e) { /* newer Wwise DSP with coefs [Epic Mickey 2 (Wii), Batman Arkham Origins Blackgate (3DS)] */ ww.codec = DSP; - } else if (ww.extra_size == 0x0a && find_chunk(streamFile, 0x57696948, first_offset,0, NULL,NULL, ww.big_endian, 0)) { /* WiiH */ + } else if (ww.extra_size == 0x0a && find_chunk(sf, 0x57696948, first_offset,0, NULL,NULL, ww.big_endian, 0)) { /* WiiH */ /* few older Wwise DSP with num_samples in extra_size [Tony Hawk: Shred (Wii)] */ ww.codec = DSP; } else if (ww.block_align == 0x104 * ww.channels) { @@ -201,19 +212,20 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { } - /* Some Wwise files (ex. Oddworld PSV, Bayonetta 2 WiiU, often in BGM.bnk) are truncated mirrors of another file. - * They come in RAM banks, prefetch to play the beginning while the rest of the real stream loads. - * We'll add basic support to avoid complaints of this or that .wem not playing */ + /* Some Wwise .bnk (RAM) files have truncated, prefetch mirrors of another file, that + * play while the rest of the real stream loads. We'll add basic support to avoid + * complaints of this or that .wem not playing */ if (ww.data_offset + ww.data_size > ww.file_size) { //VGM_LOG("WWISE: truncated data size (prefetch): (real=0x%x > riff=0x%x)\n", ww.data_size, ww.file_size); - /* catch wrong rips as truncated tracks' file_size should be much smaller than data_size */ - if (ww.data_offset + ww.data_size - ww.file_size < 0x5000) { + /* catch wrong rips as truncated tracks' file_size should be much smaller than data_size, + * but it's possible to pre-fetch small files too [Punch Out!! (Wii)] */ + if (ww.data_offset + ww.data_size - ww.file_size < 0x5000 && ww.file_size > 0x10000) { VGM_LOG("WWISE: wrong expected data_size\n"); goto fail; } - if (ww.codec == PCM || ww.codec == IMA || ww.codec == VORBIS || ww.codec == XMA2 || ww.codec == OPUSNX || ww.codec == OPUS) { + if (ww.codec == PCM || ww.codec == IMA || ww.codec == DSP || ww.codec == VORBIS || ww.codec == XMA2 || ww.codec == OPUSNX || ww.codec == OPUS) { ww.truncated = 1; /* only seen those, probably all exist */ } else { VGM_LOG("WWISE: wrong size, maybe truncated\n"); @@ -264,7 +276,6 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { vgmstream->interleave_block_size = ww.block_align / ww.channels; vgmstream->codec_endian = ww.big_endian; - /* enough to get real samples */ if (ww.truncated) { ww.data_size = ww.file_size - ww.data_offset; } @@ -286,12 +297,12 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail; /* always 0 for Worbis */ /* autodetect format (fields are mostly common, see the end of the file) */ - if (find_chunk(streamFile, 0x766F7262,first_offset,0, &vorb_offset,&vorb_size, ww.big_endian, 0)) { /*"vorb"*/ + if (find_chunk(sf, 0x766F7262,first_offset,0, &vorb_offset,&vorb_size, ww.big_endian, 0)) { /* "vorb" */ /* older Wwise (~<2012) */ switch(vorb_size) { - case 0x2C: /* earliest (~2009), [UFC Undisputed 2009 (PS3), some EVE Online Apocrypha (PC)?] */ - case 0x28: /* early (~2009) [The Lord of the Rings: Conquest (PC)] */ + case 0x2C: /* earliest (~2009) [The Lord of the Rings: Conquest (PC)] */ + case 0x28: /* early (~2009) [UFC Undisputed 2009 (PS3), some EVE Online Apocrypha (PC)] */ data_offsets = 0x18; block_offsets = 0; /* no need, full headers are present */ cfg.header_type = WWV_TYPE_8; @@ -299,8 +310,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { cfg.setup_type = WWV_HEADER_TRIAD; break; - case 0x34: /* common (2010~2011) */ - case 0x32: /* very rare (mid 2011) [Saints Row the 3rd (PC)] */ + case 0x34: /* common (2010~2011) [The King of Fighters XII (PS3), Assassin's Creed II (X360)] */ + case 0x32: /* rare (mid 2011) [Saints Row the 3rd (PC)] */ data_offsets = 0x18; block_offsets = 0x30; cfg.header_type = WWV_TYPE_6; @@ -321,12 +332,12 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { goto fail; } - vgmstream->num_samples = read_32bit(vorb_offset + 0x00, streamFile); - setup_offset = read_32bit(vorb_offset + data_offsets + 0x00, streamFile); /* within data (0 = no seek table) */ - audio_offset = read_32bit(vorb_offset + data_offsets + 0x04, streamFile); /* within data */ + vgmstream->num_samples = read_32bit(vorb_offset + 0x00, sf); + setup_offset = read_32bit(vorb_offset + data_offsets + 0x00, sf); /* within data (0 = no seek table) */ + audio_offset = read_32bit(vorb_offset + data_offsets + 0x04, sf); /* within data */ if (block_offsets) { - cfg.blocksize_1_exp = read_8bit(vorb_offset + block_offsets + 0x00, streamFile); /* small */ - cfg.blocksize_0_exp = read_8bit(vorb_offset + block_offsets + 0x01, streamFile); /* big */ + cfg.blocksize_1_exp = read_8bit(vorb_offset + block_offsets + 0x00, sf); /* small */ + cfg.blocksize_0_exp = read_8bit(vorb_offset + block_offsets + 0x01, sf); /* big */ } ww.data_size -= audio_offset; @@ -343,8 +354,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { * - trimmed inline: ~2010, ex. Army of Two: 40 days (X360) some multiplayer files * - external: ~2010, ex. Assassin's Creed Brotherhood (X360), Dead Nation (X360) */ if (vorb_size == 0x34) { - size_t setup_size = (uint16_t)read_16bit(start_offset + setup_offset, streamFile); - uint32_t id = (uint32_t)read_32bitBE(start_offset + setup_offset + 0x06, streamFile); + size_t setup_size = (uint16_t)read_16bit(start_offset + setup_offset, sf); + uint32_t id = (uint32_t)read_32bitBE(start_offset + setup_offset + 0x06, sf); /* if the setup after header starts with "(data)BCV" it's an inline codebook) */ if ((id & 0x00FFFFFF) == 0x00424356) { /* 0"BCV" */ @@ -356,13 +367,13 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { } } - vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg); + vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg); if (!vgmstream->codec_data) goto fail; } else { /* newer Wwise (>2012) */ off_t extra_offset = ww.fmt_offset + 0x18; /* after flag + channels */ - int is_wem = check_extensions(streamFile,"wem"); + int is_wem = check_extensions(sf,"wem"); switch(ww.extra_size) { case 0x30: @@ -377,18 +388,16 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { cfg.setup_type = is_wem ? WWV_AOTUV603_CODEBOOKS : WWV_EXTERNAL_CODEBOOKS; /* aoTuV came along .wem */ break; - //case 0x2a: /* Rocksmith 2011 (X360)? */ - //non mod packets? TYPE_06? (possibly detectable by checking setup's granule, should be 0) default: VGM_LOG("WWISE: unknown extra size 0x%x\n", vorb_size); goto fail; } - vgmstream->num_samples = read_32bit(extra_offset + 0x00, streamFile); - setup_offset = read_32bit(extra_offset + data_offsets + 0x00, streamFile); /* within data */ - audio_offset = read_32bit(extra_offset + data_offsets + 0x04, streamFile); /* within data */ - cfg.blocksize_1_exp = read_8bit(extra_offset + block_offsets + 0x00, streamFile); /* small */ - cfg.blocksize_0_exp = read_8bit(extra_offset + block_offsets + 0x01, streamFile); /* big */ + vgmstream->num_samples = read_32bit(extra_offset + 0x00, sf); + setup_offset = read_32bit(extra_offset + data_offsets + 0x00, sf); /* within data */ + audio_offset = read_32bit(extra_offset + data_offsets + 0x04, sf); /* within data */ + cfg.blocksize_1_exp = read_8bit(extra_offset + block_offsets + 0x00, sf); /* small */ + cfg.blocksize_0_exp = read_8bit(extra_offset + block_offsets + 0x01, sf); /* big */ ww.data_size -= audio_offset; /* detect normal packets */ @@ -399,11 +408,11 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { } /* try with the selected codebooks */ - vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg); + vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg); if (!vgmstream->codec_data) { /* codebooks failed: try again with the other type */ cfg.setup_type = is_wem ? WWV_EXTERNAL_CODEBOOKS : WWV_AOTUV603_CODEBOOKS; - vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg); + vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg); if (!vgmstream->codec_data) goto fail; } } @@ -436,12 +445,15 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { vgmstream->interleave_block_size = 0x08; /* ww.block_align = 0x8 in older Wwise, samples per block in newer Wwise */ /* find coef position */ - if (find_chunk(streamFile, 0x57696948,first_offset,0, &wiih_offset,&wiih_size, ww.big_endian, 0)) { /*"WiiH", older Wwise */ + if (find_chunk(sf, 0x57696948,first_offset,0, &wiih_offset,&wiih_size, ww.big_endian, 0)) { /*"WiiH", older Wwise */ vgmstream->num_samples = dsp_bytes_to_samples(ww.data_size, ww.channels); if (wiih_size != 0x2e * ww.channels) goto fail; + + if (is_dsp_full_interleave(sf, &ww, wiih_offset)) + vgmstream->interleave_block_size = ww.data_size / 2; } else if (ww.extra_size == 0x0c + ww.channels * 0x2e) { /* newer Wwise */ - vgmstream->num_samples = read_32bit(ww.fmt_offset + 0x18, streamFile); + vgmstream->num_samples = read_32bit(ww.fmt_offset + 0x18, sf); wiih_offset = ww.fmt_offset + 0x1c; wiih_size = 0x2e * ww.channels; } @@ -449,6 +461,11 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { goto fail; } + if (ww.truncated) { + ww.data_size = ww.file_size - ww.data_offset; + vgmstream->num_samples = dsp_bytes_to_samples(ww.data_size, ww.channels); + } + /* for some reason all(?) DSP .wem do full loops (even mono/jingles/etc) but * several tracks do loop like this, so disable it for short-ish tracks */ if (ww.loop_flag && vgmstream->loop_start_sample == 0 && @@ -456,14 +473,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { vgmstream->loop_flag = 0; } - - - /* get coefs and default history */ - dsp_read_coefs(vgmstream,streamFile,wiih_offset, 0x2e, ww.big_endian); - for (i=0; i < ww.channels; i++) { - vgmstream->ch[i].adpcm_history1_16 = read_16bitBE(wiih_offset + i * 0x2e + 0x24,streamFile); - vgmstream->ch[i].adpcm_history2_16 = read_16bitBE(wiih_offset + i * 0x2e + 0x26,streamFile); - } + dsp_read_coefs(vgmstream,sf,wiih_offset + 0x00, 0x2e, ww.big_endian); + dsp_read_hist (vgmstream,sf,wiih_offset + 0x24, 0x2e, ww.big_endian); break; } @@ -479,13 +490,13 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { //if (ww.fmt_size != ...) goto fail; /* XMA1 0x20, XMA2old: 0x34, XMA2new: 0x40, XMA2 Guitar Hero Live/padded: 0x64, etc */ if (!ww.big_endian) goto fail; /* must be Wwise (real XMA are LE and parsed elsewhere) */ - if (find_chunk(streamFile, 0x584D4132,first_offset,0, &xma2_offset,&xma2_size, ww.big_endian, 0)) { /*"XMA2"*/ /* older Wwise */ - bytes = ffmpeg_make_riff_xma2_from_xma2_chunk(buf,0x100, xma2_offset, xma2_size, ww.data_size, streamFile); + if (find_chunk(sf, 0x584D4132,first_offset,0, &xma2_offset,&xma2_size, ww.big_endian, 0)) { /*"XMA2"*/ /* older Wwise */ + bytes = ffmpeg_make_riff_xma2_from_xma2_chunk(buf,0x100, xma2_offset, xma2_size, ww.data_size, sf); } else { /* newer Wwise */ - bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, ww.fmt_offset, ww.fmt_size, ww.data_size, streamFile, ww.big_endian); + bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, ww.fmt_offset, ww.fmt_size, ww.data_size, sf, ww.big_endian); } - vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, ww.data_offset,ww.data_size); + vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, ww.data_offset,ww.data_size); if ( !vgmstream->codec_data ) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; @@ -493,11 +504,11 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { vgmstream->num_samples = ww.num_samples; /* set while parsing XMAWAVEFORMATs */ /* Wwise loops are always pre-adjusted (old or new) and only num_samples is off */ - xma_fix_raw_samples(vgmstream, streamFile, ww.data_offset,ww.data_size, ww.chunk_offset, 1,0); + xma_fix_raw_samples(vgmstream, sf, ww.data_offset,ww.data_size, ww.chunk_offset, 1,0); /* "XMAc": rare Wwise extension, XMA2 physical loop regions (loop_start_b, loop_end_b, loop_subframe_data) * Can appear even in the file doesn't loop, maybe it's meant to be the playable physical region */ - //VGM_ASSERT(find_chunk(streamFile, 0x584D4163,first_offset,0, NULL,NULL, ww.big_endian, 0), "WWISE: XMAc chunk found\n"); + //VGM_ASSERT(find_chunk(sf, 0x584D4163,first_offset,0, NULL,NULL, ww.big_endian, 0), "WWISE: XMAc chunk found\n"); /* other chunks: "seek", regular XMA2 seek table */ /* XMA is VBR so this is very approximate percent, meh */ @@ -518,7 +529,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { if (!ww.big_endian) goto fail; /* must be from Wwise X360 (PC LE XWMA is parsed elsewhere) */ bytes = ffmpeg_make_riff_xwma(buf,0x100, ww.format, ww.data_size, vgmstream->channels, vgmstream->sample_rate, ww.average_bps, ww.block_align); - ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, ww.data_offset,ww.data_size); + ffmpeg_data = init_ffmpeg_header_offset(sf, buf,bytes, ww.data_offset,ww.data_size); if ( !ffmpeg_data ) goto fail; vgmstream->codec_data = ffmpeg_data; vgmstream->coding_type = coding_FFmpeg; @@ -534,9 +545,9 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { msd.data_size = ww.data_size; if (ww.format == 0x0162) - wmapro_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x00E0); + wmapro_get_samples(&msd, sf, ww.block_align, ww.sample_rate,0x00E0); else - wma_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x001F); + wma_get_samples(&msd, sf, ww.block_align, ww.sample_rate,0x001F); vgmstream->num_samples = msd.num_samples; if (!vgmstream->num_samples) @@ -555,7 +566,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { /* extra: size 0x12, unknown values */ - ffmpeg_data = init_ffmpeg_offset(streamFile, ww.data_offset,ww.data_size); + ffmpeg_data = init_ffmpeg_offset(sf, ww.data_offset,ww.data_size); if (!ffmpeg_data) goto fail; vgmstream->codec_data = ffmpeg_data; vgmstream->coding_type = coding_FFmpeg; @@ -572,9 +583,9 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { if (ww.fmt_size == 0x28) { size_t seek_size; - vgmstream->num_samples += read_32bit(ww.fmt_offset + 0x18, streamFile); + vgmstream->num_samples += read_32bit(ww.fmt_offset + 0x18, sf); /* 0x1c: null? 0x20: data_size without seek_size */ - seek_size = read_32bit(ww.fmt_offset + 0x24, streamFile); + seek_size = read_32bit(ww.fmt_offset + 0x24, sf); start_offset += seek_size; ww.data_size -= seek_size; @@ -583,7 +594,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { goto fail; } - skip = switch_opus_get_encoder_delay(start_offset, streamFile); /* should be 120 */ + skip = switch_opus_get_encoder_delay(start_offset, sf); /* should be 120 */ /* OPUS is VBR so this is very approximate percent, meh */ if (ww.truncated) { @@ -592,7 +603,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { ww.data_size = ww.file_size - start_offset; } - vgmstream->codec_data = init_ffmpeg_switch_opus(streamFile, start_offset,ww.data_size, vgmstream->channels, skip, vgmstream->sample_rate); + vgmstream->codec_data = init_ffmpeg_switch_opus(sf, start_offset,ww.data_size, vgmstream->channels, skip, vgmstream->sample_rate); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; @@ -603,7 +614,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail; /* extra: size 0x12 */ - vgmstream->num_samples = read_32bit(ww.fmt_offset + 0x18, streamFile); + vgmstream->num_samples = read_32bit(ww.fmt_offset + 0x18, sf); /* 0x1c: stream size without OggS? */ /* 0x20: full samples (without encoder delay) */ @@ -614,7 +625,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { ww.data_size = ww.file_size - start_offset; } - vgmstream->codec_data = init_ffmpeg_offset(streamFile, ww.data_offset,ww.data_size); + vgmstream->codec_data = init_ffmpeg_offset(sf, ww.data_offset,ww.data_size); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; @@ -648,15 +659,15 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { if (ww.extra_size != 0x12) goto fail; cfg.channels = vgmstream->channels; - cfg.config_data = read_32bitBE(ww.fmt_offset+0x18,streamFile); - cfg.encoder_delay = read_32bit(ww.fmt_offset+0x20,streamFile); + cfg.config_data = read_32bitBE(ww.fmt_offset+0x18,sf); + cfg.encoder_delay = read_32bit(ww.fmt_offset+0x20,sf); vgmstream->codec_data = init_atrac9(&cfg); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_ATRAC9; vgmstream->layout_type = layout_none; - vgmstream->num_samples = read_32bit(ww.fmt_offset+0x1c,streamFile); + vgmstream->num_samples = read_32bit(ww.fmt_offset+0x1c,sf); break; } #endif @@ -678,7 +689,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { - if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) ) + if ( !vgmstream_open_stream(vgmstream,sf,start_offset) ) goto fail; return vgmstream; @@ -687,6 +698,35 @@ fail: return NULL; } +static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_offset) { + /* older (only?) Wwise use full interleave for memory (in .bnk) files, but + * detection from the .wem side is problematic [Punch Out!! (Wii)] + * - truncated point to streams = normal + * - .bnk would be memory banks = full + * - otherwise small-ish sizes, stereo, with initial predictors for the + * second channel matching half size = full + * some files aren't detectable like this though, when predictors are 0 + * (but since memory wem aren't that used this shouldn't be too common) */ + + if (ww->truncated) + return 0; + + if (check_extensions(sf,"bnk")) + return 1; + + if (ww->channels == 2 && ww->data_size <= 0x30000) { + uint16_t head_ps2 = read_u16be(coef_offset + 1 * 0x2e + 0x22, sf); /* ch2's initial predictor */ + uint16_t init_ps2 = read_u8(ww->data_offset + 0x08, sf); /* at normal interleave */ + uint16_t half_ps2 = read_u8(ww->data_offset + ww->data_size / 2, sf); /* at full interleave */ + //;VGM_LOG("WWISE: DSP head2=%x, init2=%x, half2=%x\n", head_ps2, init_ps2, half_ps2); + if (head_ps2 != init_ps2 && head_ps2 == half_ps2) { + return 1; + } + } + + return 0; +} + /* VORBIS FORMAT RESEARCH */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/zsnd.c b/Frameworks/vgmstream/vgmstream/src/meta/zsnd.c index 72c990aed..a1c96d84a 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/zsnd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/zsnd.c @@ -195,16 +195,10 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) { name_offset = 0; name_size = 0; - //TODO: possibly pitch: sample_rate = round10(pitch * 44100 / 4096); - switch(sample_rate) { - case 0x0800: sample_rate = 22050; break; - case 0x0687: sample_rate = 18000; break; - case 0x05ce: sample_rate = 16000; break; - case 0x0400: sample_rate = 11025; break; - default: - VGM_LOG("ZSND: unknown sample_rate %x at %x\n", sample_rate, (uint32_t)header2_offset); - goto fail; - } + /* pitch value, with 0x1000=44100 (voices vary quite a bit, ex. X-Men Legends 2) */ + sample_rate = round10(sample_rate * 44100.0 / 4096.0); + /* there may be some rounding for lower values, ex 0x45A = 11993.99 ~= 12000, though not all: + * 0x1000 = 44100, 0x0800 = 22050, 0x0687 ~= 18000, 0x05ce ~= 16000, 0x045a ~= 12000, 0x0400 = 11025 */ break; case 0x47435542: /* "GCUB" (also for Wii) */ diff --git a/Frameworks/vgmstream/vgmstream/src/streamfile.c b/Frameworks/vgmstream/vgmstream/src/streamfile.c index 3be097199..6ce0626a0 100644 --- a/Frameworks/vgmstream/vgmstream/src/streamfile.c +++ b/Frameworks/vgmstream/vgmstream/src/streamfile.c @@ -77,7 +77,8 @@ static size_t read_stdio(STDIO_STREAMFILE *streamfile, uint8_t *dst, off_t offse /* Workaround a bug that appears when compiling with MSVC (later versions). * This bug is deterministic and seemingly appears randomly after seeking. * It results in fread returning data from the wrong area of the file. - * HPS is one format that is almost always affected by this. */ + * HPS is one format that is almost always affected by this. + * May be related/same as open_stdio's bug when using dup() */ fseek(streamfile->infile, ftell(streamfile->infile), SEEK_SET); #endif @@ -132,7 +133,12 @@ static STREAMFILE* open_stdio(STDIO_STREAMFILE *streamfile, const char * const f if (!filename) return NULL; -#if !defined (__ANDROID__) +#if !defined (__ANDROID__) && !defined (_MSC_VER) + /* when enabling this for MSVC it'll seemingly work, but there are issues possibly related to underlying + * IO buffers when using dup(), noticeable by re-opening the same streamfile with small buffer sizes + * (reads garbage). fseek bug in line 81 may be related/same thing and may be removed. + * this reportedly this causes issues in Android too */ + /* if same name, duplicate the file descriptor we already have open */ if (streamfile->infile && !strcmp(streamfile->name,filename)) { int new_fd; diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c index 455ea3478..8e236b5fa 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c @@ -492,6 +492,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_lrmd, init_vgmstream_bkhd, init_vgmstream_bkhd_fx, + init_vgmstream_diva, /* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */ diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.h b/Frameworks/vgmstream/vgmstream/src/vgmstream.h index f4dcc5039..a7a452435 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.h @@ -735,6 +735,7 @@ typedef enum { meta_KWB, meta_LRMD, meta_WWISE_FX, + meta_DIVA, } meta_t; /* standard WAVEFORMATEXTENSIBLE speaker positions */