From 943ab00766ab7e93e182b0fdff2fc40b088dbf3c Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 22 Apr 2020 00:21:13 +0200 Subject: [PATCH 1/3] Add ADX key [428 (PS3)] --- src/meta/adx.c | 4 ++-- src/meta/adx_keys.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/meta/adx.c b/src/meta/adx.c index a42c2697..5b90087c 100644 --- a/src/meta/adx.c +++ b/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/src/meta/adx_keys.h b/src/meta/adx_keys.h index 13ccdd6e..ea27d542 100644 --- a/src/meta/adx_keys.h +++ b/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[] = { From 4e55391be1dea9edafd36c6f50ff92c6250aef37 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 22 Apr 2020 00:26:19 +0200 Subject: [PATCH 2/3] Fix full loops in EAAC ATRAC9 + renames [NFS Most Wanted (Vita)] --- src/meta/ea_eaac.c | 480 ++++++++++++++++++++++----------------------- 1 file changed, 237 insertions(+), 243 deletions(-) diff --git a/src/meta/ea_eaac.c b/src/meta/ea_eaac.c index bc78df23..6d63aae7 100644 --- a/src/meta/ea_eaac.c +++ b/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) { @@ -1360,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 { @@ -1434,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; } From b24116b0c767259dcc332ac1a1a6f7e4f840ab42 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 22 Apr 2020 00:34:49 +0200 Subject: [PATCH 3/3] Fix Wwise DSP memory interleave + renames [Punch Out!! (Wii)] --- src/meta/bkhd.c | 3 +- src/meta/wwise.c | 201 +++++++++++++++++++++++++++-------------------- 2 files changed, 118 insertions(+), 86 deletions(-) diff --git a/src/meta/bkhd.c b/src/meta/bkhd.c index 9f07000d..7b5606c3 100644 --- a/src/meta/bkhd.c +++ b/src/meta/bkhd.c @@ -105,7 +105,8 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) { } else { //;VGM_LOG("BKHD: %lx, %x\n", subfile_offset, subfile_size); - temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "wem"); + /* 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); diff --git a/src/meta/wwise.c b/src/meta/wwise.c index 48e8fa4e..f7ea4fb0 100644 --- a/src/meta/wwise.c +++ b/src/meta/wwise.c @@ -38,9 +38,11 @@ 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; @@ -51,18 +53,19 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { /* .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)] */ - if (!check_extensions(streamFile,"wem,wav,lwav,ogg,logg,xma")) + * .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,streamFile) != 0x52494646 && /* "RIFF" (LE) */ - read_32bitBE(0x00,streamFile) != 0x52494658) /* "RIFX" (BE) */ + if (read_32bitBE(0x00,sf) != 0x52494646 && /* "RIFF" (LE) */ + read_32bitBE(0x00,sf) != 0x52494658) /* "RIFX" (BE) */ goto fail; - if (read_32bitBE(0x08,streamFile) != 0x57415645 && /* "WAVE" */ - read_32bitBE(0x08,streamFile) != 0x58574D41) /* "XWMA" */ + 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; @@ -71,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: @@ -82,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 @@ -93,8 +96,8 @@ 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 */ @@ -106,36 +109,36 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { size_t loop_size; /* find basic chunks */ - if (read_32bitBE(0x0c, streamFile) == 0x584D4132) { /* "XMA2" with no "fmt" [Too Human (X360)] */ + if (read_32bitBE(0x0c, sf) == 0x584D4132) { /* "XMA2" with no "fmt" [Too Human (X360)] */ ww.format = 0x0165; /* signal for below */ } else { - if (!find_chunk(streamFile, 0x666d7420,first_offset,0, &ww.fmt_offset,&ww.fmt_size, ww.big_endian, 0)) /* "fmt " */ + 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,streamFile); + 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(streamFile, 0x584D4132,first_offset,0, &ww.chunk_offset,NULL, ww.big_endian, 0)) /* "XMA2" */ + if (!find_chunk(sf, 0x584D4132,first_offset,0, &ww.chunk_offset,NULL, ww.big_endian, 0)) /* "XMA2" */ 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); + 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,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); + 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); + 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) @@ -149,18 +152,18 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { /* 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) + 1; /* like standard RIFF */ + 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 */ //} @@ -169,7 +172,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { * "akd ": seem to store extra info for Wwise editor (wave peaks/loudness/HDR envelope?) */ - if (!find_chunk(streamFile, 0x64617461,first_offset,0, &ww.data_offset,&ww.data_size, ww.big_endian, 0)) /* "data" */ + if (!find_chunk(sf, 0x64617461,first_offset,0, &ww.data_offset,&ww.data_size, ww.big_endian, 0)) /* "data" */ goto fail; } @@ -200,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) { @@ -209,14 +212,15 @@ 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; } @@ -293,7 +297,7 @@ 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) { @@ -328,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; @@ -350,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" */ @@ -363,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: @@ -389,11 +393,11 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { 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 */ @@ -404,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; } } @@ -441,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; } @@ -466,13 +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; } @@ -488,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; @@ -502,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 */ @@ -527,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; @@ -543,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) @@ -564,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; @@ -581,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; @@ -592,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) { @@ -601,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; @@ -612,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) */ @@ -623,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; @@ -657,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 @@ -687,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; @@ -696,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 */