From 9b3c2ca8f7e9de0f96e4058e4d1c4550084273d0 Mon Sep 17 00:00:00 2001 From: NicknineTheEagle Date: Sun, 29 Jul 2018 09:21:44 +0300 Subject: [PATCH 1/2] Added a missing version stamp to ABK --- src/meta/ea_schl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/meta/ea_schl.c b/src/meta/ea_schl.c index 38cd49e4..d511a197 100644 --- a/src/meta/ea_schl.c +++ b/src/meta/ea_schl.c @@ -157,6 +157,7 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) { version = read_32bitBE(0x04, streamFile); if (version != 0x01010000 && version != 0x01010100 && + version != 0x02010000 && version != 0x02010100 && version != 0x02010202) goto fail; From baaec69a4683cc9dfc6a02befd727c5d3f485433 Mon Sep 17 00:00:00 2001 From: NicknineTheEagle Date: Tue, 31 Jul 2018 10:26:55 +0300 Subject: [PATCH 2/2] Added macros for some common constants in EA parsers --- src/meta/ea_eaac.c | 282 ++++++++++++++++++++++++--------------------- src/meta/ea_schl.c | 98 ++++++++++------ 2 files changed, 213 insertions(+), 167 deletions(-) diff --git a/src/meta/ea_eaac.c b/src/meta/ea_eaac.c index e0016aa4..d9b82306 100644 --- a/src/meta/ea_eaac.c +++ b/src/meta/ea_eaac.c @@ -5,6 +5,33 @@ /* EAAudioCore formats, EA's current audio middleware */ +#define EAAC_VERSION_V0 0x00 /* SNR/SNS */ +#define EAAC_VERSION_V1 0x01 /* SPS */ + +#define EAAC_CODEC_NONE 0x00 /* internal 'codec not set' flag */ +#define EAAC_CODEC_RESERVED 0x01 /* not used/reserved? /MP30/P6L0/P2B0/P2L0/P8S0/P8U0/PFN0? */ +#define EAAC_CODEC_PCM 0x02 +#define EAAC_CODEC_EAXMA 0x03 +#define EAAC_CODEC_XAS 0x04 +#define EAAC_CODEC_EALAYER3_V1 0x05 +#define EAAC_CODEC_EALAYER3_V2_PCM 0x06 +#define EAAC_CODEC_EALAYER3_V2_SPIKE 0x07 +#define EAAC_CODEC_DSP 0x08 +#define EAAC_CODEC_EASPEEX 0x09 +#define EAAC_CODEC_EATRAX 0x0a +#define EAAC_CODEC_EAOPUS 0x0c + +#define EAAC_FLAG_NONE 0x00 +#define EAAC_FLAG_LOOPED 0x02 +#define EAAC_FLAG_STREAMED 0x04 + +#define EAAC_BLOCKID0_DATA 0x00 +#define EAAC_BLOCKID0_END 0x80 + +#define EAAC_BLOCKID1_HEADER 0x48 /* 'H' */ +#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); static size_t get_snr_size(STREAMFILE *streamFile, off_t offset); static VGMSTREAM *parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint16_t target_index, off_t ast_offset); @@ -50,7 +77,7 @@ VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE * streamFile) { goto fail; /* SPS block start: 0x00(1): block flag (header=0x48); 0x01(3): block size (usually 0x0c-0x14) */ - if (read_8bit(0x00, streamFile) != 0x48) + if (read_8bit(0x00, streamFile) != EAAC_BLOCKID1_HEADER) goto fail; start_offset = read_32bitBE(0x00, streamFile) & 0x00FFFFFF; @@ -150,111 +177,10 @@ fail: return NULL; } -/* EA HDR/STH/DAT - seen in early 7th-gen games, used for storing speech */ -VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) { - int target_stream = streamFile->stream_index; - uint8_t userdata_size, total_sounds, block_id; - uint8_t i; - off_t snr_offset, sns_offset; - size_t file_size, block_size; - STREAMFILE *datFile = NULL, *sthFile = NULL; - VGMSTREAM *vgmstream; - - /* 0x00: ID */ - /* 0x02: userdata size */ - /* 0x03: number of files */ - /* 0x04: sub-ID (used for different police voices in NFS games) */ - /* 0x08: alt number of files? */ - /* 0x09: zero */ - /* 0x0A: ??? */ - /* 0x0C: zero */ - /* 0x10: table start */ - - sthFile = open_streamfile_by_ext(streamFile, "sth"); - if (!sthFile) - goto fail; - - datFile = open_streamfile_by_ext(streamFile, "dat"); - if (!datFile) - goto fail; - - /* STH always starts with the first offset of zero */ - sns_offset = read_32bitLE(0x00, sthFile); - if (sns_offset != 0) - goto fail; - - /* check if DAT starts with a correct SNS block */ - block_id = read_8bit(0x00, datFile); - if (block_id != 0x00 && block_id != 0x80) - goto fail; - - userdata_size = read_8bit(0x02, streamFile); - total_sounds = read_8bit(0x03, streamFile); - if (read_8bit(0x08, streamFile) > total_sounds) - goto fail; - - if (target_stream == 0) target_stream = 1; - if (target_stream < 0 || total_sounds == 0 || target_stream > total_sounds) - goto fail; - - /* offsets in HDR are always big endian */ - //snr_offset = (off_t)read_16bitBE(0x10 + (0x02+userdata_size) * (target_stream-1), streamFile) + 0x04; - //sns_offset = read_32bit(snr_offset, sthFile); - - /* we can't reliably detect byte endianness so we're going to find the sound the hacky way */ - /* go through blocks until we reach the goal sound */ - file_size = get_streamfile_size(datFile); - snr_offset = 0; - sns_offset = 0; - - for (i = 0; i < total_sounds; i++) { - snr_offset = (off_t)read_16bitBE(0x10 + (0x02+userdata_size) * i, streamFile) + 0x04; - - if (i == target_stream - 1) - break; - - while (1) { - if (sns_offset >= file_size) - goto fail; - - block_id = read_8bit(sns_offset, datFile); - block_size = read_32bitBE(sns_offset, datFile) & 0x00FFFFFF; - if (block_size == 0) - goto fail; - - if (block_id != 0x00 && block_id != 0x80) - goto fail; - - sns_offset += block_size; - - if (block_id == 0x80) - break; - } - } - - block_id = read_8bit(sns_offset, datFile); - if (block_id != 0x00 && block_id != 0x80) - goto fail; - - vgmstream = init_vgmstream_eaaudiocore_header(sthFile, datFile, snr_offset, sns_offset, meta_EA_SNR_SNS); - if (!vgmstream) - goto fail; - - vgmstream->num_streams = total_sounds; - close_streamfile(sthFile); - close_streamfile(datFile); - return vgmstream; - -fail: - close_streamfile(sthFile); - close_streamfile(datFile); - return NULL; -} - /* 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_new(STREAMFILE *streamFile) { int is_dupe, total_sounds = 0, target_stream = streamFile->stream_index; - off_t bnk_offset, header_table_offset, base_offset, unk_struct_offset, table_offset, snd_entry_offset, ast_offset = 0; + 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, version, num_sounds, total_sound_tables; uint16_t num_tables, bnk_index, bnk_target_index; @@ -293,6 +219,7 @@ VGMSTREAM * init_vgmstream_ea_abk_new(STREAMFILE *streamFile) { bnk_offset = read_32bit(0x20, streamFile); total_sound_tables = 0; bnk_target_index = 0xFFFF; + ast_offset = 0; /* set up some common values */ if (header_table_offset == 0x5C) { @@ -431,6 +358,107 @@ fail: return NULL; } +/* EA HDR/STH/DAT - seen in early 7th-gen games, used for storing speech */ +VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) { + int target_stream = streamFile->stream_index; + uint32_t i; + uint8_t userdata_size, total_sounds, block_id; + off_t snr_offset, sns_offset; + size_t file_size, block_size; + STREAMFILE *datFile = NULL, *sthFile = NULL; + VGMSTREAM *vgmstream; + + /* 0x00: ID */ + /* 0x02: userdata size */ + /* 0x03: number of files */ + /* 0x04: sub-ID (used for different police voices in NFS games) */ + /* 0x08: alt number of files? */ + /* 0x09: zero */ + /* 0x0A: ??? */ + /* 0x0C: zero */ + /* 0x10: table start */ + + sthFile = open_streamfile_by_ext(streamFile, "sth"); + if (!sthFile) + goto fail; + + datFile = open_streamfile_by_ext(streamFile, "dat"); + if (!datFile) + goto fail; + + /* STH always starts with the first offset of zero */ + sns_offset = read_32bitLE(0x00, sthFile); + if (sns_offset != 0) + goto fail; + + /* check if DAT starts with a correct SNS block */ + block_id = read_8bit(0x00, datFile); + 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); + if (read_8bit(0x08, streamFile) > total_sounds) + goto fail; + + if (target_stream == 0) target_stream = 1; + if (target_stream < 0 || total_sounds == 0 || target_stream > total_sounds) + goto fail; + + /* offsets in HDR are always big endian */ + //snr_offset = (off_t)read_16bitBE(0x10 + (0x02+userdata_size) * (target_stream-1), streamFile) + 0x04; + //sns_offset = read_32bit(snr_offset, sthFile); + + /* we can't reliably detect byte endianness so we're going to find the sound the hacky way */ + /* go through blocks until we reach the goal sound */ + file_size = get_streamfile_size(datFile); + snr_offset = 0; + sns_offset = 0; + + for (i = 0; i < total_sounds; i++) { + snr_offset = (off_t)read_16bitBE(0x10 + (0x02+userdata_size) * i, streamFile) + 0x04; + + if (i == target_stream - 1) + break; + + while (1) { + if (sns_offset >= file_size) + goto fail; + + block_id = read_8bit(sns_offset, datFile); + block_size = read_32bitBE(sns_offset, datFile) & 0x00FFFFFF; + if (block_size == 0) + goto fail; + + if (block_id != EAAC_BLOCKID0_DATA && block_id != EAAC_BLOCKID0_END) + goto fail; + + sns_offset += block_size; + + if (block_id == EAAC_BLOCKID0_END) + break; + } + } + + block_id = read_8bit(sns_offset, datFile); + if (block_id != EAAC_BLOCKID0_DATA && block_id != EAAC_BLOCKID0_END) + goto fail; + + vgmstream = init_vgmstream_eaaudiocore_header(sthFile, datFile, snr_offset, sns_offset, meta_EA_SNR_SNS); + if (!vgmstream) + goto fail; + + vgmstream->num_streams = total_sounds; + close_streamfile(sthFile); + close_streamfile(datFile); + return vgmstream; + +fail: + close_streamfile(sthFile); + close_streamfile(datFile); + return NULL; +} + /* 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). @@ -454,32 +482,32 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST codec = (header1 >> 24) & 0x0F; channel_config = (header1 >> 18) & 0x3F; sample_rate = (header1 & 0x03FFFF); /* some Dead Space 2 (PC) uses 96000 */ - flags = (header2 >> 28) & 0x0F; // TODO: maybe even 3 bits and not 4? + flags = (header2 >> 28) & 0x0F; /* TODO: maybe even 3 bits and not 4? */ num_samples = (header2 & 0x0FFFFFFF); /* rest is optional, depends on flags header used (ex. SNU and SPS may have bigger headers): */ /* 0x02: loop start sample, 0x00/04: nothing, 0x06: loop start sample and loop start block offset */ /* V0: SNR+SNS, V1: SPR+SPS (no apparent differences, other than the block flags used) */ - if (version != 0 && version != 1) { + if (version != EAAC_VERSION_V0 && version != EAAC_VERSION_V1) { VGM_LOG("EA SNS/SPS: unknown version\n"); goto fail; } - /* 0x04: stream asset, 0x02: full loop, 0x00: default/RAM asset */ - if (flags != 0x06 && flags != 0x04 && flags != 0x02 && flags != 0x00) { - VGM_LOG("EA SNS/SPS: unknown flag 0x%02x\n", flags); + if (flags != EAAC_FLAG_NONE && + !(flags & (EAAC_FLAG_LOOPED | EAAC_FLAG_STREAMED))) { + VGM_LOG("EA SNS/SPS: unknown flags 0x%02x\n", flags); goto fail; } /* TODO: Properly implement looping, needed for Need for Speed: World (PC) */ - if (flags & 0x02) { + if (flags & EAAC_FLAG_LOOPED) { loop_flag = 1; loop_start = 0; loop_end = num_samples; } /* Non-streamed sounds are stored as a single block */ - streamed = (flags & 0x04) != 0; + streamed = (flags & EAAC_FLAG_STREAMED) != 0; /* accepted channel configs only seem to be mono/stereo/quad/5.1/7.1 */ /* fail with unknown values just in case */ @@ -508,14 +536,14 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST /* EA decoder list and known internal FourCCs */ switch(codec) { - case 0x02: /* "P6B0": PCM16BE [NBA Jam (Wii)] */ + case EAAC_CODEC_PCM: /* "P6B0": PCM16BE [NBA Jam (Wii)] */ vgmstream->coding_type = coding_PCM16_int; vgmstream->codec_endian = 1; vgmstream->layout_type = layout_blocked_ea_sns; break; #ifdef VGM_USE_FFMPEG - case 0x03: { /* "EXm0": EA-XMA [Dante's Inferno (X360)] */ + case EAAC_CODEC_EAXMA: { /* "EXm0": EA-XMA [Dante's Inferno (X360)] */ uint8_t buf[0x100]; int bytes, block_size, block_count; size_t stream_size, virtual_size; @@ -542,15 +570,15 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST } #endif - case 0x04: /* "Xas1": EA-XAS [Dead Space (PC/PS3)] */ + case EAAC_CODEC_XAS: /* "Xas1": EA-XAS [Dead Space (PC/PS3)] */ vgmstream->coding_type = coding_EA_XAS; vgmstream->layout_type = layout_blocked_ea_sns; break; #ifdef VGM_USE_MPEG - case 0x05: /* "EL31": EALayer3 v1 [Need for Speed: Hot Pursuit (PS3)] */ - case 0x06: /* "L32P": EALayer3 v2 "PCM" [Battlefield 1943 (PS3)] */ - case 0x07: { /* "L32S": EALayer3 v2 "Spike" [Dante's Inferno (PS3)] */ + case EAAC_CODEC_EALAYER3_V1: /* "EL31": EALayer3 v1 [Need for Speed: Hot Pursuit (PS3)] */ + case EAAC_CODEC_EALAYER3_V2_PCM: /* "L32P": EALayer3 v2 "PCM" [Battlefield 1943 (PS3)] */ + case EAAC_CODEC_EALAYER3_V2_SPIKE: { /* "L32S": EALayer3 v2 "Spike" [Dante's Inferno (PS3)] */ mpeg_custom_config cfg = {0}; mpeg_custom_t type = (codec == 0x05 ? MPEG_EAL31b : (codec == 0x06) ? MPEG_EAL32P : MPEG_EAL32S); @@ -570,14 +598,14 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST } #endif - case 0x08: /* "Gca0"?: DSP [Need for Speed: Nitro sfx (Wii)] */ + case EAAC_CODEC_DSP: /* "Gca0"?: DSP [Need for Speed: Nitro sfx (Wii)] */ vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_blocked_ea_sns; /* DSP coefs are read in the blocks */ break; #ifdef VGM_USE_ATRAC9 - case 0x0a: { /* EATrax */ + case EAAC_CODEC_EATRAX: { /* EATrax */ atrac9_config cfg = {0}; size_t total_size; @@ -600,14 +628,10 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST } #endif - case 0x00: /* "NONE" (internal 'codec not set' flag) */ - case 0x01: /* not used/reserved? /MP30/P6L0/P2B0/P2L0/P8S0/P8U0/PFN0? */ - case 0x09: /* EASpeex (libspeex variant, base versions vary: 1.0.5, 1.2beta3) */ - case 0x0b: /* ? */ - case 0x0c: /* EAOpus (inside each SNS/SPS block is 16b frame size + standard? Opus packet) */ - case 0x0d: /* ? */ - case 0x0e: /* ? */ - case 0x0f: /* ? */ + case EAAC_CODEC_EASPEEX: /* EASpeex (libspeex variant, base versions vary: 1.0.5, 1.2beta3) */ + /* TODO */ + case EAAC_CODEC_EAOPUS: /* EAOpus (inside each SNS/SPS block is 16b frame size + standard? Opus packet) */ + /* TODO */ default: VGM_LOG("EA SNS/SPS: unknown codec 0x%02x\n", codec); goto fail; @@ -631,8 +655,8 @@ fail: static size_t get_snr_size(STREAMFILE *streamFile, off_t offset) { switch (read_8bit(offset + 0x04, streamFile) >> 4 & 0x0F) { /* flags */ - case 0x06: return 0x10; - case 0x02: return 0x0C; - default: return 0x08; + case EAAC_FLAG_LOOPED | EAAC_FLAG_STREAMED: return 0x10; + case EAAC_FLAG_LOOPED: return 0x0C; + default: return 0x08; } } diff --git a/src/meta/ea_schl.c b/src/meta/ea_schl.c index d511a197..40a60eb5 100644 --- a/src/meta/ea_schl.c +++ b/src/meta/ea_schl.c @@ -30,7 +30,7 @@ #define EA_CODEC1_NONE -1 #define EA_CODEC1_PCM 0x00 #define EA_CODEC1_VAG 0x01 // unsure -#define EA_CODEC1_EAXA 0x07 // Need for Speed II (PC), FIFA 98 (SAT) +#define EA_CODEC1_EAXA 0x07 #define EA_CODEC1_MT10 0x09 //#define EA_CODEC1_N64 ? @@ -47,10 +47,32 @@ #define EA_CODEC2_XBOXADPCM 0x14 #define EA_CODEC2_MT5 0x16 #define EA_CODEC2_EALAYER3 0x17 -#define EA_CODEC2_ATRAC3PLUS 0x1B /* Medal of Honor Heroes 2 (PSP) */ +#define EA_CODEC2_ATRAC3PLUS 0x1B +/* Block headers, SCxy - where x is block ID and y is endianness flag (always 'l'?) */ +#define EA_BLOCKID_HEADER 0x5343486C /* "SCHl" */ +#define EA_BLOCKID_COUNT 0x5343436C /* "SCCl" */ +#define EA_BLOCKID_DATA 0x5343446C /* "SCDl" */ +#define EA_BLOCKID_END 0x5343456C /* "SCEl" */ -#define EA_MAX_CHANNELS 6 +/* Localized block headers, Sxyy - where x is block ID and yy is lang code (e.g. "SHEN"), used in videos */ +#define EA_BLOCKID_LOC_HEADER 0x53480000 /* "SH" */ +#define EA_BLOCKID_LOC_COUNT 0x53430000 /* "SC" */ +#define EA_BLOCKID_LOC_DATA 0x53440000 /* "SD" */ +#define EA_BLOCKID_LOC_END 0x53450000 /* "SE" */ + +#define EA_BLOCKID_LOC_EN 0x0000454E +#define EA_BLOCKID_LOC_FR 0x00004652 +#define EA_BLOCKID_LOC_GE 0x00004745 +#define EA_BLOCKID_LOC_IT 0x00004954 +#define EA_BLOCKID_LOC_SP 0x00005350 +#define EA_BLOCKID_LOC_RU 0x00005255 +#define EA_BLOCKID_LOC_JA 0x00004A41 + +#define EA_BNK_HEADER_LE 0x424E4B6C /* "BNKl" */ +#define EA_BNK_HEADER_BE 0x424E4B62 /* "BNKb" */ + +#define EA_MAX_CHANNELS 6 typedef struct { int32_t num_samples; @@ -89,14 +111,14 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) { goto fail; /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x5343486C && /* "SCHl" */ - read_32bitBE(0x00,streamFile) != 0x5348454E && /* "SHEN" */ - read_32bitBE(0x00,streamFile) != 0x53484652 && /* "SHFR" */ - read_32bitBE(0x00,streamFile) != 0x53484745 && /* "SHGE" */ - read_32bitBE(0x00,streamFile) != 0x53484954 && /* "SHIT" */ - read_32bitBE(0x00,streamFile) != 0x53485350 && /* "SHSP" */ - read_32bitBE(0x00,streamFile) != 0x53485255 && /* "SHRU" */ - read_32bitBE(0x00,streamFile) != 0x53484A41) /* "SHJA" */ + if (read_32bitBE(0x00,streamFile) != EA_BLOCKID_HEADER && /* "SCHl" */ + read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_EN) && /* "SHEN" */ + read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_FR) && /* "SHFR" */ + read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_GE) && /* "SHGE" */ + read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_IT) && /* "SHIT" */ + read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_SP) && /* "SHSP" */ + read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_RU) && /* "SHRU" */ + read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_JA)) /* "SHJA" */ goto fail; /* Stream is divided into blocks/chunks: SCHl=audio header, SCCl=count of SCDl, SCDl=data xN, SCLl=loop end, SCEl=end. @@ -118,10 +140,10 @@ VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE *streamFile) { goto fail; /* check header (doesn't use EA blocks, otherwise very similar to SCHl) */ - if (read_32bitBE(0x00,streamFile) == 0x424E4B6C || /* "BNKl" (common) */ - read_32bitBE(0x00,streamFile) == 0x424E4B62) /* "BNKb" (FIFA 98 SS) */ + if (read_32bitBE(0x00,streamFile) == EA_BNK_HEADER_LE || + read_32bitBE(0x00,streamFile) == EA_BNK_HEADER_BE) offset = 0; - else if (read_32bitBE(0x100,streamFile) == 0x424E4B6C) /* "BNKl" (common) */ + else if (read_32bitBE(0x100,streamFile) == EA_BNK_HEADER_LE) offset = 0x100; /* Harry Potter and the Goblet of Fire (PS2) .mus have weird extra 0x100 bytes */ else goto fail; @@ -134,7 +156,7 @@ fail: /* EA ABK - common soundbank format in 6th-gen games, can reference RAM and streamed assets */ /* RAM assets are stored in embedded BNK file */ -/* streamed assets are stored externally in AST file (mostly seen in earlier 6th games) */ +/* streamed assets are stored externally in AST file (mostly seen in earlier 6th-gen games) */ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) { int bnk_target_stream, is_dupe, total_sounds = 0, target_stream = streamFile->stream_index; off_t bnk_offset, header_table_offset, base_offset, value_offset, table_offset, entry_offset, target_entry_offset, schl_offset; @@ -210,7 +232,7 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) { for (k = 0; k < num_sounds; k++) { entry_offset = table_offset + 0x04 + 0x0C * k; - sound_type = read_8bit(entry_offset, streamFile); + sound_type = read_8bit(entry_offset + 0x00, streamFile); /* some of these dummies pointing at sound 0 in BNK */ if (sound_type == 0x00 && read_32bit(entry_offset + 0x04, streamFile) == 0) @@ -234,15 +256,15 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) { /* 0x01: ??? */ /* 0x04: index for normal sounds, offset for streamed sounds */ /* 0x08: offset for prefetched sounds */ - sound_type = read_8bit(target_entry_offset, streamFile); + sound_type = read_8bit(target_entry_offset + 0x00, streamFile); switch (sound_type) { case 0x00: if (!bnk_offset) goto fail; - if (read_32bitBE(bnk_offset, streamFile) != 0x424E4B6C && /* "BNKl" */ - read_32bitBE(bnk_offset, streamFile) != 0x424E4B62) /* BNKb */ + if (read_32bitBE(bnk_offset, streamFile) != EA_BNK_HEADER_LE && + read_32bitBE(bnk_offset, streamFile) != EA_BNK_HEADER_BE) goto fail; bnk_target_stream = read_32bit(target_entry_offset + 0x04, streamFile) + 1; @@ -262,7 +284,7 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) { else schl_offset = read_32bit(target_entry_offset + 0x08, streamFile); - if (read_32bitBE(schl_offset, astData) != 0x5343486C) /* "SCHl */ + if (read_32bitBE(schl_offset, astData) != EA_BLOCKID_HEADER) goto fail; vgmstream = parse_schl_block(astData, schl_offset, total_sounds); @@ -294,7 +316,8 @@ VGMSTREAM * init_vgmstream_ea_hdr_dat(STREAMFILE *streamFile) { /* main header's endianness is platform-native but we only care about one byte values */ /* 0x00: ID */ /* 0x02: sub-ID (used for different police voices in NFS games) */ - /* 0x04: userdata size (low nibble) */ + /* 0x04: (low nibble) userdata size */ + /* 0x04: (high nibble) ??? */ /* 0x05: number of files */ /* 0x06: ??? */ /* 0x07: offset multiplier flag */ @@ -307,7 +330,7 @@ VGMSTREAM * init_vgmstream_ea_hdr_dat(STREAMFILE *streamFile) { if (!datFile) goto fail; - if (read_32bitBE(0x00, datFile) != 0x5343486C) /* "SCHl */ + if (read_32bitBE(0x00, datFile) != EA_BLOCKID_HEADER) goto fail; userdata_size = read_8bit(0x04, streamFile) & 0x0F; @@ -320,7 +343,7 @@ VGMSTREAM * init_vgmstream_ea_hdr_dat(STREAMFILE *streamFile) { /* offsets are always big endian */ schl_offset = (off_t)read_16bitBE(0x0C + (0x02+userdata_size) * (target_stream-1), streamFile) * offset_mult; - if (read_32bitBE(schl_offset, datFile) != 0x5343486C) /* "SCHl */ + if (read_32bitBE(schl_offset, datFile) != EA_BLOCKID_HEADER) goto fail; vgmstream = parse_schl_block(datFile, schl_offset, total_sounds); @@ -338,8 +361,7 @@ fail: /* EA IDX/BIG combo - basically a set of HDR/DAT compiled into one file */ VGMSTREAM * init_vgmstream_ea_idx_big(STREAMFILE *streamFile) { int target_stream = streamFile->stream_index, total_sounds, subsound_index; - uint32_t num_hdr; - uint32_t i; + uint32_t i, num_hdr; uint16_t hdr_id, hdr_subid; uint8_t userdata_size, hdr_sounds; off_t entry_offset, hdr_offset, base_offset, schl_offset, offset_mult; @@ -359,7 +381,7 @@ VGMSTREAM * init_vgmstream_ea_idx_big(STREAMFILE *streamFile) { if (!bigFile) goto fail; - if (read_32bitBE(0x00, bigFile) != 0x5343486C) /* "SCHl */ + if (read_32bitBE(0x00, bigFile) != EA_BLOCKID_HEADER) goto fail; /* use number of files for endianness check */ @@ -409,7 +431,7 @@ VGMSTREAM * init_vgmstream_ea_idx_big(STREAMFILE *streamFile) { if (schl_offset == 0xFFFFFFFF) goto fail; - if (read_32bitBE(schl_offset, bigFile) != 0x5343486C) /* "SCHl */ + if (read_32bitBE(schl_offset, bigFile) != EA_BLOCKID_HEADER) goto fail; vgmstream = parse_schl_block(bigFile, schl_offset, total_sounds); @@ -474,7 +496,7 @@ static VGMSTREAM * parse_bnk_header(STREAMFILE *streamFile, off_t offset, int ta /* check multi-streams */ switch(bnk_version) { - case 0x02: /* early [Need For Speed II (PC), FIFA 98 (SAT)] */ + case 0x02: /* early [Need For Speed II (PC/PS1), FIFA 98 (PC/PS1/SAT)] */ table_offset = 0x0c; header_size = read_32bit(offset + 0x08,streamFile); /* full size */ break; @@ -691,7 +713,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_ break; } - case EA_CODEC2_ATRAC3PLUS: { /* regular ATRAC3plus chunked in SCxx blocks, including RIFF header */ + case EA_CODEC2_ATRAC3PLUS: { /* regular ATRAC3plus chunked in SCxx blocks, including RIFF header [Medal of Honor Heroes 2 (PSP)] */ if (!is_bnk) { STREAMFILE* temp_streamFile = NULL; /* remove blocks on reads to feed FFmpeg a clean .at3 */ @@ -1132,7 +1154,7 @@ static int get_ea_stream_total_samples(STREAMFILE* streamFile, off_t start_offse vgmstream->next_block_offset = start_offset; do { uint32_t block_id = read_32bitBE(vgmstream->next_block_offset+0x00,streamFile); - if (block_id == 0x5343486C) /* "SCHl" start block (movie "SHxx" shouldn't use multi files) */ + if (block_id == EA_BLOCKID_HEADER) /* "SCHl" start block (movie "SHxx" shouldn't use multi files) */ new_schl = 1; block_update_ea_schl(vgmstream->next_block_offset,vgmstream); @@ -1168,14 +1190,14 @@ static off_t get_ea_stream_mpeg_start_offset(STREAMFILE* streamFile, off_t start block_size = read_32bitBE(block_offset+0x04,streamFile); switch(block_id) { - case 0x5343446C: /* "SCDl" */ - case 0x5344454E: /* "SDEN" */ - case 0x53444652: /* "SDFR" */ - case 0x53444745: /* "SDGE" */ - case 0x53444954: /* "SDIT" */ - case 0x53445350: /* "SDSP" */ - case 0x53445255: /* "SDRU" */ - case 0x53444A41: /* "SDJA" */ + case EA_BLOCKID_DATA: /* "SCDl" */ + case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_EN: /* "SDEN" */ + case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_FR: /* "SDFR" */ + case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_GE: /* "SDGE" */ + case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_IT: /* "SDIT" */ + case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_SP: /* "SDSP" */ + case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_RU: /* "SDRU" */ + case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_JA: /* "SDJA" */ offset = read_32bit(block_offset+0x0c,streamFile); /* first value seems ok, second is something else in EALayer3 */ return block_offset + 0x0c + ea->channels*0x04 + offset; case 0x00000000: