From 808188dbcdd26637f5f8fccdedbf3b2c2f449f66 Mon Sep 17 00:00:00 2001 From: NicknineTheEagle Date: Thu, 27 Dec 2018 20:01:36 +0300 Subject: [PATCH] EA SCHl: Added MPF/MUS format --- src/formats.c | 1 + src/meta/ea_schl.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++ src/meta/meta.h | 1 + src/vgmstream.c | 1 + 4 files changed, 90 insertions(+) diff --git a/src/formats.c b/src/formats.c index 4eb018c5..47b713fa 100644 --- a/src/formats.c +++ b/src/formats.c @@ -239,6 +239,7 @@ static const char* extension_list[] = { //"mpc", //common "mpdsp", "mpds", + "mpf", "mps", //txth/reserved [Scandal (PS2)] "ms", "msa", diff --git a/src/meta/ea_schl.c b/src/meta/ea_schl.c index c11ae759..a2c051be 100644 --- a/src/meta/ea_schl.c +++ b/src/meta/ea_schl.c @@ -351,6 +351,93 @@ fail: return NULL; } +/* EA MPF/MUS combo - used in newer 6th gen games for storing music */ +VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE *streamFile) { + off_t section_offset, entry_offset, subentry_num, eof_offset, schl_offset; + uint16_t sec1_num; + uint8_t version, sub_version, sec2_num; + int32_t(*read_32bit)(off_t, STREAMFILE*); + int16_t(*read_16bit)(off_t, STREAMFILE*); + STREAMFILE *musFile = NULL; + VGMSTREAM *vgmstream = NULL; + int target_stream = streamFile->stream_index, total_streams; + + /* check extension */ + if (!check_extensions(streamFile, "mpf")) + goto fail; + + /* detect endianness */ + if (read_32bitBE(0x00, streamFile) == 0x50464478) { /* "PFDx" */ + read_32bit = read_32bitBE; + read_16bit = read_16bitBE; + } else if (read_32bitBE(0x00, streamFile) == 0x78444650) { /* "xDFP" */ + read_32bit = read_32bitLE; + read_16bit = read_16bitLE; + } else { + goto fail; + } + + musFile = open_streamfile_by_ext(streamFile, "mus"); + if (!musFile) goto fail; + + version = read_8bit(0x04, streamFile); + sub_version = read_8bit(0x05, streamFile); + + if (version < 0x04 || version > 0x05) goto fail; + if (version == 0x05 && sub_version > 0x02) goto fail; /* newer version using SNR/SNS */ + + if (version == 0x04) { + /* we need to go through the first two sections to find sound table */ + sec1_num = read_16bit(0x12, streamFile); + sec2_num = read_8bit(0x0f, streamFile); + + /* get the last entry offset */ + section_offset = 0x20; + entry_offset = read_16bit(section_offset + (sec1_num - 1) * 0x02, streamFile) * 0x04; + + /* HACK: there's some weird bitstream here that's store differently in LE and BE */ + /* I can't figure it out, so let's just use a workaround for now */ + if (read_32bitBE(0x00, streamFile) == 0x50464478) { + subentry_num = (read_32bitBE(entry_offset + 0x04, streamFile) >> 15) & 0xFF; + } else { + subentry_num = (read_32bitBE(entry_offset + 0x04, streamFile) >> 20) & 0xFF; + } + + section_offset = entry_offset + 0x10 + subentry_num * 0x04; + entry_offset = read_16bit(section_offset + (sec2_num - 1) * 0x02, streamFile) * 0x04; + subentry_num = read_16bit(entry_offset + 0x0e, streamFile); + + section_offset = entry_offset + 0x10 + subentry_num * 0x10; + entry_offset = read_32bit(section_offset, streamFile) * 0x04; + section_offset = read_32bit(entry_offset + 0x00, streamFile) * 0x04; + eof_offset = read_32bit(entry_offset + 0x04, streamFile) * 0x04; + total_streams = (eof_offset - section_offset) / 0x08; + } else if (version == 0x05) { + section_offset = read_32bit(0x34, streamFile); + eof_offset = read_32bit(0x38, streamFile); + total_streams = (eof_offset - section_offset) / 0x08; + } + + if (target_stream == 0) target_stream = 1; + if (target_stream < 0 || total_streams == 0 || target_stream > total_streams) + goto fail; + + schl_offset = read_32bit(section_offset + (target_stream - 1) * 0x08 + 0x00, streamFile) * 0x80; + if (read_32bitBE(schl_offset, musFile) != EA_BLOCKID_HEADER) + goto fail; + + vgmstream = parse_schl_block(musFile, schl_offset, total_streams); + if (!vgmstream) + goto fail; + + close_streamfile(musFile); + return vgmstream; + +fail: + close_streamfile(musFile); + return NULL; +} + /* EA SCHl with variable header - from EA games (roughly 1997~2010); generated by EA Canada's sx.exe/Sound eXchange */ static VGMSTREAM * parse_schl_block(STREAMFILE *streamFile, off_t offset, int total_streams) { off_t start_offset, header_offset; diff --git a/src/meta/meta.h b/src/meta/meta.h index 6075842d..a84067d9 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -645,6 +645,7 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile); 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_mpf_mus(STREAMFILE * steeamFile); VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE * streamFile); diff --git a/src/vgmstream.c b/src/vgmstream.c index 19201e8f..8e93282e 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -352,6 +352,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ea_bnk, init_vgmstream_ea_abk, init_vgmstream_ea_hdr_dat, + init_vgmstream_ea_mpf_mus, init_vgmstream_ea_schl_fixed, init_vgmstream_sk_aud, init_vgmstream_stm,