From 0719c2cc613ec0c049b982b187f756bf8bbfb9d9 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 9 Mar 2019 23:51:56 +0100 Subject: [PATCH] Fix EA SCHl BR and handle multilang better [Battlefield: Hardline (PS3)] --- src/layout/blocked_ea_schl.c | 42 +++++++++-------------- src/meta/ea_schl.c | 66 ++++++++++++++++++------------------ 2 files changed, 49 insertions(+), 59 deletions(-) diff --git a/src/layout/blocked_ea_schl.c b/src/layout/blocked_ea_schl.c index 7c99b6b2..7b4b024e 100644 --- a/src/layout/blocked_ea_schl.c +++ b/src/layout/blocked_ea_schl.c @@ -10,6 +10,10 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) { size_t block_size, block_samples; int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE; + uint32_t flag_lang = (vgmstream->codec_config >> 16) & 0xFFFF; + int flag_be = (vgmstream->codec_config & 0x02); + int flag_adpcm = (vgmstream->codec_config & 0x01); + /* EOF reads: signal we have nothing and let the layout fail */ if (block_offset >= get_streamfile_size(streamFile)) { @@ -23,35 +27,21 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) { { uint32_t block_id = read_32bitBE(block_offset+0x00,streamFile); - if (vgmstream->codec_config & 0x02) /* size is always LE, except in early SS/MAC */ + if (flag_be) /* size is always LE, except in early SS/MAC */ block_size = read_32bitBE(block_offset + 0x04,streamFile); else block_size = read_32bitLE(block_offset + 0x04,streamFile); - switch(block_id) { - case 0x5343446C: /* "SCDl" */ - case 0x5344454E: /* "SDEN" */ - case 0x53444652: /* "SDFR" */ - case 0x53444745: /* "SDGE" */ - case 0x53444445: /* "SDDE" */ - case 0x53444954: /* "SDIT" */ - case 0x53445350: /* "SDSP" */ - case 0x53444553: /* "SDES" */ - case 0x53444D58: /* "SDMX" */ - case 0x53445255: /* "SDRU" */ - case 0x53444A41: /* "SDJA" */ - case 0x53444A50: /* "SDJP" */ - case 0x5344504C: /* "SDPL" */ - /* audio chunk */ - if (vgmstream->coding_type == coding_PSX) - block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels); - else - block_samples = read_32bit(block_offset+0x08,streamFile); - break; - default: - /* ignore other chunks (audio "SCHl/SCCl/...", video "pIQT/MADk/...", etc) */ - block_samples = 0; /* layout ignores this */ - break; + if (block_id == 0x5343446C || block_id == (0x53440000 | flag_lang)) { + /* "SCDl" or "SDxx" audio chunk */ + if (vgmstream->coding_type == coding_PSX) + block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels); + else + block_samples = read_32bit(block_offset+0x08,streamFile); + } + else { + /* ignore other chunks (audio "SCHl/SCCl/...", non-target lang, video "pIQT/MADk/...", etc) */ + block_samples = 0; /* layout ignores this */ } /* "SCHl" start block (movie "SHxx" shouldn't use multi files) */ @@ -185,7 +175,7 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) { } /* read ADPCM history before each channel if needed (not actually read in sx.exe) */ - if (vgmstream->codec_config & 0x01) { + if (flag_adpcm) { for (i = 0; i < vgmstream->channels; i++) { //vgmstream->ch[i].adpcm_history1_32 = read_16bit(vgmstream->ch[i].offset+0x00,streamFile); //vgmstream->ch[i].adpcm_history3_32 = read_16bit(vgmstream->ch[i].offset+0x02,streamFile); diff --git a/src/meta/ea_schl.c b/src/meta/ea_schl.c index 4287e146..b388b575 100644 --- a/src/meta/ea_schl.c +++ b/src/meta/ea_schl.c @@ -74,6 +74,7 @@ #define EA_BLOCKID_LOC_JA 0x00004A41 /* Japanese, older */ #define EA_BLOCKID_LOC_JP 0x00004A50 /* Japanese, newer */ #define EA_BLOCKID_LOC_PL 0x0000504C /* Polish */ +#define EA_BLOCKID_LOC_BR 0x00004252 /* Brazilian Portuguese */ #define EA_BNK_HEADER_LE 0x424E4B6C /* "BNKl" */ #define EA_BNK_HEADER_BE 0x424E4B62 /* "BNKb" */ @@ -135,18 +136,19 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) { /* check header */ 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_DE) && /* "SHDE" */ - 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_ES) && /* "SHES" */ - read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_MX) && /* "SHMX" */ - 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" */ - read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_JP) && /* "SHJP" */ - read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_PL)) /* "SHPL" */ + 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_DE) && /* "SHDE" */ + 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_ES) && /* "SHES" */ + read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_MX) && /* "SHMX" */ + 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" */ + read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_JP) && /* "SHJP" */ + read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_PL) && /* "SHPL" */ + read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_BR)) /* "SHBR" */ goto fail; /* Stream is divided into blocks/chunks: SCHl=audio header, SCCl=count of SCDl, SCDl=data xN, SCLl=loop end, SCEl=end. @@ -702,8 +704,16 @@ fail: static VGMSTREAM * parse_schl_block(STREAMFILE *streamFile, off_t offset, int standalone) { off_t start_offset, header_offset; size_t header_size; + uint32_t header_id; ea_header ea = { 0 }; + /* use higher bits to store target localized block in case of multilang video, + * so only header sub-id will be read and other langs skipped */ + header_id = read_32bitBE(offset + 0x00, streamFile); + if ((header_id & 0xFFFF0000) == EA_BLOCKID_LOC_HEADER) { + ea.codec_config |= (header_id & 0xFFFF) << 16; + } + if (guess_endianness32bit(offset + 0x04, streamFile)) { /* size is always LE, except in early SS/MAC */ header_size = read_32bitBE(offset + 0x04, streamFile); ea.codec_config |= 0x02; @@ -1497,6 +1507,7 @@ static off_t get_ea_stream_mpeg_start_offset(STREAMFILE* streamFile, off_t start size_t file_size = get_streamfile_size(streamFile); off_t block_offset = start_offset; int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE; + uint32_t header_lang = (ea->codec_config >> 16) & 0xFFFF; while (block_offset < file_size) { uint32_t block_id, block_size; @@ -1508,27 +1519,16 @@ static off_t get_ea_stream_mpeg_start_offset(STREAMFILE* streamFile, off_t start if (block_size > 0x00F00000) /* size is always LE, except in early SAT/MAC */ block_size = read_32bitBE(block_offset+0x04,streamFile); - switch(block_id) { - 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_DE: /* "SDDE" */ - 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_ES: /* "SDES" */ - case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_MX: /* "SDMX" */ - case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_RU: /* "SDRU" */ - case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_JA: /* "SDJA" */ - case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_JP: /* "SDJP" */ - case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_PL: /* "SDPL" */ - 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: - goto fail; /* just in case */ - default: - block_offset += block_size; /* size includes header */ - break; + if (block_id == EA_BLOCKID_DATA || block_id == ((EA_BLOCKID_LOC_DATA | header_lang))) { + /* "SCDl" or target "SDxx" multilang blocks */ + 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; + } + else if (block_id == 0x00000000) { + goto fail; /* just in case */ + } + else { + block_offset += block_size; /* size includes header */ } }