From f6ccd77b4131ddab871f5cd3e1dcd11603b837eb Mon Sep 17 00:00:00 2001 From: EdnessP <55930127+EdnessP@users.noreply.github.com> Date: Mon, 20 May 2024 02:05:03 +0300 Subject: [PATCH] EA MPF+MUS: EA Redwood Shores variant --- src/formats.c | 1 + src/meta/ea_eaac_mpf_mus.c | 57 ++++++++++++++++++++++++++++++++---- src/meta/ea_sbk.c | 3 +- src/meta/ea_schl.c | 59 ++++++++++++++++++++++++++++++++++---- src/meta/meta.h | 8 ++++-- src/vgmstream.c | 6 ++-- 6 files changed, 116 insertions(+), 18 deletions(-) diff --git a/src/formats.c b/src/formats.c index d5c2f4b4..82a99cb0 100644 --- a/src/formats.c +++ b/src/formats.c @@ -365,6 +365,7 @@ static const char* extension_list[] = { "mss", "msv", "msvp", //fake extension/header id for .msv + "msx", "mta2", "mtaf", "mtt", //txth/reserved [Splinter Cell: Pandora Tomorrow (PS2)] diff --git a/src/meta/ea_eaac_mpf_mus.c b/src/meta/ea_eaac_mpf_mus.c index a5a7cee5..88795144 100644 --- a/src/meta/ea_eaac_mpf_mus.c +++ b/src/meta/ea_eaac_mpf_mus.c @@ -4,11 +4,61 @@ #include "../util/companion_files.h" +static VGMSTREAM* init_vgmstream_ea_mpf_mus_eaac(STREAMFILE* sf, const char* mus_name); static STREAMFILE *open_mapfile_pair(STREAMFILE* sf, int track /*, int num_tracks*/); +/* .MPF - Standard EA MPF+MUS */ +VGMSTREAM* init_vgmstream_ea_mpf_eaac(STREAMFILE* sf) { + if (!check_extensions(sf, "mpf")) + return NULL; + return init_vgmstream_ea_mpf_mus_eaac(sf, NULL); +} + +/* .MSB/.MSX - EA Redwood Shores (MSB/MSX)+MUS [The Godfather (PS3/360), The Simpsons Game (PS3/360)] */ +VGMSTREAM* init_vgmstream_ea_msb_eaac(STREAMFILE* sf) { + /* container with MPF, extra info, and a pre-defined MUS filename */ + VGMSTREAM* vgmstream = NULL; + STREAMFILE* sf_mpf = NULL; + const char* mus_name[0x20 + 1]; + size_t header_size; + off_t info_offset, mus_name_offset; + read_u32_t read_u32; + + if (!check_extensions(sf, "msb,msx")) + return NULL; + + header_size = 0x50; + mus_name_offset = 0x30; + + /* 0x08: buffer size of the pre-defined .mus filename? (always 0x20) + * 0x20: mpf version number? (always 0x05) + * 0x24: offset to a chunk of plaintext data w/ event and node info & names + * 0x2C: some hash? + * 0x30: intended .mus filename */ + read_u32 = guess_read_u32(0x08, sf); + + /* not exactly the same as mpf size since it's aligned, but doesn't matter here */ + info_offset = read_u32(0x24, sf); //+ header_size; + read_string(mus_name, 0x20 + 1, mus_name_offset, sf); + + sf_mpf = open_wrap_streamfile(sf); + sf_mpf = open_clamp_streamfile(sf_mpf, header_size, info_offset); + if (!sf_mpf) goto fail; + + vgmstream = init_vgmstream_ea_mpf_mus_eaac(sf_mpf, mus_name); + if (!vgmstream) goto fail; + close_streamfile(sf_mpf); + + return vgmstream; + +fail: + close_vgmstream(vgmstream); + close_streamfile(sf_mpf); + return NULL; +} /* EA MPF/MUS combo - used in older 7th gen games for storing interactive music */ -VGMSTREAM* init_vgmstream_ea_mpf_mus_eaac(STREAMFILE* sf) { +static VGMSTREAM* init_vgmstream_ea_mpf_mus_eaac(STREAMFILE* sf, const char* mus_name) { VGMSTREAM* vgmstream = NULL; STREAMFILE *sf_mus = NULL; uint32_t num_tracks, track_start, track_checksum = 0, mus_sounds, mus_stream = 0, bnk_index = 0, bnk_sound_index = 0, @@ -34,9 +84,6 @@ VGMSTREAM* init_vgmstream_ea_mpf_mus_eaac(STREAMFILE* sf) { return NULL; } - if (!check_extensions(sf, "mpf")) - return NULL; - version = read_u8(0x04, sf); sub_version = read_u8(0x05, sf); if (version != 5 || sub_version < 2 || sub_version > 3) goto fail; @@ -69,7 +116,7 @@ VGMSTREAM* init_vgmstream_ea_mpf_mus_eaac(STREAMFILE* sf) { } /* open MUS file that matches this track */ - sf_mus = open_mapfile_pair(sf, i);//, num_tracks + sf_mus = mus_name ? open_streamfile_by_filename(sf, mus_name) : open_mapfile_pair(sf, i);//, num_tracks if (!sf_mus) goto fail; /* sample offsets table is still there but it just holds SNS offsets, we only need it for RAM sound indexes */ diff --git a/src/meta/ea_sbk.c b/src/meta/ea_sbk.c index 622dd790..0b0f3868 100644 --- a/src/meta/ea_sbk.c +++ b/src/meta/ea_sbk.c @@ -64,9 +64,8 @@ VGMSTREAM* init_vgmstream_ea_sbk(STREAMFILE* sf) { * 0x04: 0x0313BABE (?) * 0x08: stream offset * 0x0C: 0xFEEDFEED (?) - * - * Dead Space 3 has non-placeholder data at 0x04 (SPS related?) */ + /* Dead Space 3 has non-placeholder data at 0x04 (SPS related?) */ entry_offset = sdat_offset + 0x08 + target_stream * 0x10; if (read_u32(entry_offset + 0x00, sf) != target_stream) goto fail; diff --git a/src/meta/ea_schl.c b/src/meta/ea_schl.c index 79c22df0..b7434eed 100644 --- a/src/meta/ea_schl.c +++ b/src/meta/ea_schl.c @@ -134,6 +134,7 @@ typedef struct { size_t stream_size; } ea_header; +static VGMSTREAM* init_vgmstream_ea_mpf_mus(STREAMFILE* sf, const char* mus_name); static VGMSTREAM* parse_schl_block(STREAMFILE* sf, off_t offset); static VGMSTREAM* parse_bnk_header(STREAMFILE* sf, off_t offset, int target_stream, int is_embedded); static int parse_variable_header(STREAMFILE* sf, ea_header* ea, off_t begin_offset, int max_length, int bnk_version); @@ -859,8 +860,58 @@ fail: return NULL; } +/* .MPF - Standard EA MPF+MUS */ +VGMSTREAM* init_vgmstream_ea_mpf(STREAMFILE* sf) { + if (!check_extensions(sf, "mpf")) + return NULL; + return init_vgmstream_ea_mpf_mus(sf, NULL); +} + +/* .MSB/.MSX - EA Redwood Shores (MSB/MSX)+MUS [007: From Russia with Love, The Godfather (PC/PS2/Wii)] */ +VGMSTREAM* init_vgmstream_ea_msb(STREAMFILE* sf) { + /* container with MPF, extra info, and a pre-defined MUS filename */ + VGMSTREAM* vgmstream = NULL; + STREAMFILE* sf_mpf = NULL; + const char* mus_name[0x20 + 1]; + size_t header_size; + off_t info_offset, mus_name_offset; + read_u32_t read_u32; + + if (!check_extensions(sf, "msb,msx")) + return NULL; + + header_size = 0x50; + mus_name_offset = 0x30; + + /* 0x08: buffer size of the pre-defined .mus filename? (always 0x20) + * 0x20: mpf version number? (always 0x05) + * 0x24: offset to a chunk of plaintext data w/ event and node info & names + * 0x2C: some hash? + * 0x30: intended .mus filename */ + read_u32 = guess_read_u32(0x08, sf); + + /* not exactly the same as mpf size since it's aligned, but correct size is only needed for v3 */ + info_offset = read_u32(0x24, sf); //+ header_size; + read_string(mus_name, 0x20 + 1, mus_name_offset, sf); + + sf_mpf = open_wrap_streamfile(sf); + sf_mpf = open_clamp_streamfile(sf_mpf, header_size, info_offset); + if (!sf_mpf) goto fail; + + vgmstream = init_vgmstream_ea_mpf_mus(sf_mpf, mus_name); + if (!vgmstream) goto fail; + close_streamfile(sf_mpf); + + return vgmstream; + +fail: + close_vgmstream(vgmstream); + close_streamfile(sf_mpf); + return NULL; +} + /* EA MPF/MUS combo - used in 6th gen games for interactive music (for EA's PathFinder tool) */ -VGMSTREAM* init_vgmstream_ea_mpf_mus(STREAMFILE* sf) { +static VGMSTREAM* init_vgmstream_ea_mpf_mus(STREAMFILE* sf, const char* mus_name) { VGMSTREAM* vgmstream = NULL; STREAMFILE* sf_mus = NULL; segmented_layout_data *data_s = NULL; @@ -873,10 +924,6 @@ VGMSTREAM* init_vgmstream_ea_mpf_mus(STREAMFILE* sf) { uint32_t(*read_u32)(off_t, STREAMFILE *); uint16_t(*read_u16)(off_t, STREAMFILE *); - /* check extension */ - if (!check_extensions(sf, "mpf")) - goto fail; - /* detect endianness */ if (is_id32be(0x00, sf, "PFDx")) { read_u32 = read_u32be; @@ -1041,7 +1088,7 @@ VGMSTREAM* init_vgmstream_ea_mpf_mus(STREAMFILE* sf) { goto fail; /* open MUS file that matches this track */ - sf_mus = open_mapfile_pair(sf, i); //, num_tracks + sf_mus = mus_name ? open_streamfile_by_filename(sf, mus_name) : open_mapfile_pair(sf, i); //, num_tracks if (!sf_mus) goto fail; diff --git a/src/meta/meta.h b/src/meta/meta.h index a5301245..e2093fc8 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -602,8 +602,9 @@ VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ea_hdr_dat(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ea_hdr_dat_v2(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_ea_map_mus(STREAMFILE * steeamFile); -VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE * steeamFile); +VGMSTREAM * init_vgmstream_ea_map_mus(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_ea_mpf(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_ea_msb(STREAMFILE * streamFile); VGMSTREAM* load_vgmstream_ea_bnk(STREAMFILE* sf, off_t offset, int target_stream, int is_embedded); VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE * streamFile); @@ -648,7 +649,8 @@ VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ea_abk_eaac(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_ea_mpf_eaac(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_ea_msb_eaac(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ea_tmx(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE * streamFile); diff --git a/src/vgmstream.c b/src/vgmstream.c index 1a4fd5c6..6df58bcd 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -293,7 +293,8 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_ea_hdr_dat, init_vgmstream_ea_hdr_dat_v2, init_vgmstream_ea_map_mus, - init_vgmstream_ea_mpf_mus, + init_vgmstream_ea_mpf, + init_vgmstream_ea_msb, init_vgmstream_ea_schl_fixed, init_vgmstream_sk_aud, init_vgmstream_stma, @@ -320,7 +321,8 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_ea_sps, init_vgmstream_ea_abk_eaac, init_vgmstream_ea_hdr_sth_dat, - init_vgmstream_ea_mpf_mus_eaac, + init_vgmstream_ea_mpf_eaac, + init_vgmstream_ea_msb_eaac, init_vgmstream_ea_tmx, init_vgmstream_ea_sbr, init_vgmstream_ea_sbr_harmony,