From 49628d6198fe658d4b15aada9a3fa01445c8c097 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 2 Jan 2019 16:15:03 +0100 Subject: [PATCH] Add SCHl .hab/gsf/abk and custom mpf+mus pairs, remove trj/trm map pair --- src/formats.c | 4 +- src/meta/ea_schl.c | 117 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 99 insertions(+), 22 deletions(-) diff --git a/src/formats.c b/src/formats.c index c22d884c..f672c60c 100644 --- a/src/formats.c +++ b/src/formats.c @@ -156,10 +156,12 @@ static const char* extension_list[] = { "genh", "gms", "gsb", + //"gsf", //conflicts with GBA gsf plugins? "gtd", "gwm", "h4m", + "hab", "hca", "hdr", "hgc1", @@ -417,8 +419,6 @@ static const char* extension_list[] = { "thp", "tk5", "tra", - "trj", - "trm", "tun", "txth", "txtp", diff --git a/src/meta/ea_schl.c b/src/meta/ea_schl.c index ea8325de..b38c9050 100644 --- a/src/meta/ea_schl.c +++ b/src/meta/ea_schl.c @@ -5,24 +5,24 @@ /* header version */ #define EA_VERSION_NONE -1 -#define EA_VERSION_V0 0x00 // ~early PC (when codec1 was used) -#define EA_VERSION_V1 0x01 // ~PC -#define EA_VERSION_V2 0x02 // ~PS era -#define EA_VERSION_V3 0x03 // ~PS2 era +#define EA_VERSION_V0 0x00 /* ~early PC (when codec1 was used) */ +#define EA_VERSION_V1 0x01 /* ~PC */ +#define EA_VERSION_V2 0x02 /* ~PS1 */ +#define EA_VERSION_V3 0x03 /* ~PS2 */ -/* platform constants (unasigned values seem internal only) */ -#define EA_PLATFORM_GENERIC -1 // typically Wii/X360/PS3/videos +/* platform constants (unassigned values seem internal only) */ +#define EA_PLATFORM_GENERIC -1 /* typically Wii/X360/PS3/videos */ #define EA_PLATFORM_PC 0x00 #define EA_PLATFORM_PSX 0x01 #define EA_PLATFORM_N64 0x02 #define EA_PLATFORM_MAC 0x03 #define EA_PLATFORM_SAT 0x04 #define EA_PLATFORM_PS2 0x05 -#define EA_PLATFORM_GC_WII 0x06 // reused later for Wii +#define EA_PLATFORM_GC_WII 0x06 #define EA_PLATFORM_XBOX 0x07 -#define EA_PLATFORM_X360 0x09 // also "Xenon" +#define EA_PLATFORM_X360 0x09 #define EA_PLATFORM_PSP 0x0A -#define EA_PLATFORM_PS3 0x0E // very rare [Need for Speed: Carbon (PS3)] +#define EA_PLATFORM_PS3 0x0E /* very rare [Need for Speed: Carbon (PS3)] */ #define EA_PLATFORM_3DS 0x14 /* codec constants (undefined are probably reserved, ie.- sx.exe encodes PCM24/DVI but no platform decodes them) */ @@ -112,9 +112,24 @@ static void update_ea_stream_size_and_samples(STREAMFILE* streamFile, off_t star /* EA SCHl with variable header - from EA games (roughly 1997~2010); generated by EA Canada's sx.exe/Sound eXchange */ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) { - /* check extension; exts don't seem enforced by EA's tools, but usually: - * STR/ASF/MUS ~early, EAM ~mid, SNG/AUD ~late, rest uncommon/one game (ex. STRM: MySims Kingdom Wii) */ - if (!check_extensions(streamFile,"str,asf,mus,eam,sng,aud,sx,strm,xa,xsf,exa,stm,trj,trm")) + + /* check extension */ + /* they don't seem enforced by EA's tools but usually: + * .asf: ~early [ex. Need for Speed (PC)] + * .str: ~early [ex. FIFA 2002 (PS1)] + * .eam: ~mid (fake?) + * .exa: ~mid [ex. 007 - From Russia with Love] + * .sng: ~late (fake?) + * .aud: ~late [ex. FIFA 14 (3DS)] + * .strm: MySims Kingdom (Wii) + * .stm: FIFA 12 (3DS) + * .sx/xa: fake? + * .hab: GoldenEye - Rogue Agent (inside .big) + * .xsf: 007 - Agent Under Fire (Xbox) + * .gsf: 007 - Everything or Nothing (GC) + * .mus: map/mpf+mus only? + * (extensionless): SSX (PS2) (inside .big) */ + if (!check_extensions(streamFile,"asf,str,eam,exa,sng,aud,sx,xa,strm,stm,hab,xsf,gsf,mus,")) goto fail; /* check header */ @@ -147,8 +162,12 @@ VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE *streamFile) { off_t offset; /* check extension */ - /* .bnk: sfx, .sdt: speech, .mus: streams/jingles (rare) */ - if (!check_extensions(streamFile,"bnk,sdt,mus")) + /* .bnk: common + * .sdt: Harry Potter games + * .mus: streams/jingles (rare) + * .abk: GoldenEye - Rogue Agent + * .ast: FIFA 2004 (inside .big) */ + if (!check_extensions(streamFile,"bnk,sdt,mus,abk,ast")) goto fail; /* check header (doesn't use EA blocks, otherwise very similar to SCHl) */ @@ -363,7 +382,59 @@ fail: return NULL; } -/* EA MAP/MUS combo - used in some old games for interactive music info */ + +/* 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) { + static const char *const mapfile_pairs[][2] = { + /* standard cases, replace map part with mus part (from the end to preserve prefixes) */ + {"MUS_CTRL.MPF","MUS_STR.MUS"}, /* GoldenEye - Rogue Agent (PS2) */ + {"mus_ctrl.mpf","mus_str.mus"}, /* GoldenEye - Rogue Agent (others) */ + {".mpf","_main.mus"}, /* 007 - Everything or Nothing (GC) */ + /* hack when when multiple maps point to the same mus, uses name before "+" + * ex. ZZZTR00A.TRJ+ZTR00PGR.MAP or ZZZTR00A.TRJ+ZTR00R0A.MAP both point to ZZZTR00A.TRJ */ + {"+",""}, /* Need for Speed III (PS1) */ + }; + STREAMFILE *musFile = NULL; + char file_name[PATH_LIMIT]; + int pair_count = (sizeof(mapfile_pairs)/sizeof(mapfile_pairs[0])); + int i; + size_t file_len, map_len; + + get_streamfile_filename(streamFile, file_name, PATH_LIMIT); + file_len = strlen(file_name); + + for (i = 0; i < pair_count; i++) { + const char *map_name = mapfile_pairs[i][0]; + const char *mus_name = mapfile_pairs[i][1]; + map_len = strlen(map_name); + + if (map_name[0] == '+') { + /* use name before "+" */ + char *mod_name = strchr(file_name, '+'); + if (mod_name == NULL) + continue; + mod_name[0] = '\0'; + } + else { + /* replace map_name with expected mus_name */ + if (file_len < map_len) + continue; + if (strncmp(file_name+(file_len - map_len), map_name, map_len) != 0) + continue; + file_name[file_len - map_len] = '\0'; + strcat(file_name, mus_name); + } + + musFile = open_streamfile_by_filename(streamFile, file_name); + if (musFile) return musFile; + + get_streamfile_filename(streamFile, file_name, PATH_LIMIT); /* reset for next loop */ + } + + return NULL; +} + +/* EA MAP/MUS combo - used in older games for interactive music (for EA's PathFinder tool) */ VGMSTREAM * init_vgmstream_ea_map_mus(STREAMFILE *streamFile) { uint8_t version, num_sounds, num_userdata, userdata_size; off_t section_offset, schl_offset; @@ -383,7 +454,10 @@ VGMSTREAM * init_vgmstream_ea_map_mus(STREAMFILE *streamFile) { if (version > 1) goto fail; musFile = open_streamfile_by_ext(streamFile, "mus"); - if (!musFile) goto fail; + if (!musFile) { + musFile = open_mapfile_pair(streamFile); + if (!musFile) goto fail; + } /* * 0x04: ??? @@ -427,7 +501,7 @@ fail: return NULL; } -/* EA MPF/MUS combo - used in newer 6th gen games for storing music */ +/* EA MPF/MUS combo - used in newer 6th gen games for interactive music (for EA's PathFinder tool) */ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE *streamFile) { off_t section_offset, entry_offset, subentry_num, eof_offset, off_mult, schl_offset; size_t sec2_size; @@ -463,12 +537,15 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE *streamFile) { if (version == 5 && sub_version > 2) goto fail; /* newer version using SNR/SNS */ musFile = open_streamfile_by_ext(streamFile, "mus"); - if (!musFile) goto fail; + if (!musFile) { + musFile = open_mapfile_pair(streamFile); + if (!musFile) goto fail; + } /* HACK: number of sub-entries is stored in bitstreams that are different in LE and BE */ /* I can't figure it out, so let's just use a workaround for now */ - if (version == 3 && sub_version == 1) { /* SSX Tricky /* + if (version == 3 && sub_version == 1) { /* SSX Tricky */ /* we need to go through the first two sections to find sound table */ sec1_num = read_16bit(0x12, streamFile); sec2_size = read_8bit(0x0e, streamFile); @@ -517,7 +594,7 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE *streamFile) { eof_offset = read_32bit(entry_offset + 0x04, streamFile) * 0x04; total_streams = (eof_offset - section_offset) / 0x08; off_mult = 0x04; - } else if (version == 4) { /* SSX 3, Need for Speed: Underground 2 /* + } else if (version == 4) { /* SSX 3, Need for Speed: Underground 2 */ /* 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);