diff --git a/src/meta/fsb_keys.h b/src/meta/fsb_keys.h index 35603baf..4b1cbabc 100644 --- a/src/meta/fsb_keys.h +++ b/src/meta/fsb_keys.h @@ -69,6 +69,7 @@ static const fsbkey_info fsbkey_list[] = { { MODE_FSB5, FSBKEY_ADD("resoforce") }, // Rivals of Aether 2 (PC) { MODE_FSB5, FSBKEY_ADD("3cfe772db5b55b806541d3faf894020e") }, // Final Fantasy XV: War for Eos (Android) { MODE_FSB5, FSBKEY_ADD("aj#$kLucf2lh}eqh") }, // Forza Motorsport 2023 (PC) + { MODE_FSB4, FSBKEY_ADD("dpdjeoqkr") }, // AirRider CrazyRacing (PC) /* some games use a key per file, generated from the filename * (could add all of them but there are a lot of songs, so external .fsbkey are probably better) */ diff --git a/src/meta/hca_keys.h b/src/meta/hca_keys.h index 73fa5d25..91ede4ce 100644 --- a/src/meta/hca_keys.h +++ b/src/meta/hca_keys.h @@ -1455,11 +1455,14 @@ static const hcakey_info hcakey_list[] = { {9182735170}, // 0000000223556B42 // Super Robot Wars DD (Android) - {464113616464131416}, // 0670DCE00CC43558 + {464113616464131416}, // 0670DCE00CC43558 // Ange Re:Link (Android) {9666854456}, // 0000000240307E38 + // Metaphor: ReFantazio Demo (PC) + {572184256205070254}, // 07F0CE8CA92C9FAE + }; -#endif/*_HCA_KEYS_H_*/ +#endif diff --git a/src/meta/sndx.c b/src/meta/sndx.c index 798990cd..801e838d 100644 --- a/src/meta/sndx.c +++ b/src/meta/sndx.c @@ -10,7 +10,7 @@ VGMSTREAM* init_vgmstream_sndx(STREAMFILE* sf) { off_t start_offset, chunk_offset, first_offset = 0x60, name_offset = 0; size_t chunk_size, stream_size = 0; - int is_dual, is_external; + bool is_dual, is_external; int loop_flag, channels, codec, sample_rate; int32_t num_samples, loop_start_sample, loop_end_sample; uint32_t flags, at9_config_data = 0; @@ -18,11 +18,14 @@ VGMSTREAM* init_vgmstream_sndx(STREAMFILE* sf) { /* checks */ + if (!is_id32be(0x00, sf, "SXDF") && !is_id32be(0x00, sf, "SXDS")) + return NULL; + /* .sxd: header+data (SXDF) * .sxd1: header (SXDF) + .sxd2 = data (SXDS) * .sxd3: sxd1 + sxd2 pasted together (found in some PS4 games, ex. Fate Extella)*/ if (!check_extensions(sf,"sxd,sxd2,sxd3")) - goto fail; + return NULL; /* setup head/body variations */ if (check_extensions(sf,"sxd2")) { @@ -33,7 +36,7 @@ VGMSTREAM* init_vgmstream_sndx(STREAMFILE* sf) { sf_sxd1 = sf_h; sf_sxd2 = sf; - is_dual = 1; + is_dual = true; } else if (check_extensions(sf,"sxd3")) { /* sxd3: make subfiles for head and body to simplify parsing */ @@ -50,13 +53,13 @@ VGMSTREAM* init_vgmstream_sndx(STREAMFILE* sf) { sf_sxd1 = sf_h; sf_sxd2 = sf_b; - is_dual = 1; + is_dual = true; } else { /* sxd: use the current file as header */ sf_sxd1 = sf; sf_sxd2 = NULL; - is_dual = 0; + is_dual = false; } if (sf_sxd1 && !is_id32be(0x00, sf_sxd1, "SXDF")) @@ -225,6 +228,14 @@ VGMSTREAM* init_vgmstream_sndx(STREAMFILE* sf) { goto fail; } + /* .sxd have names but they are a bit complex: + * - WAVE chunk has N subsongs + * - NAME chunk may define M names but usually doesn't match with subsongs (may be less or more) + * - LVRN may define some state and LVAR its possible values (battle_state=bgm_battle_start/win/intro) + * - TRNS also has names based on possible transition + * - final WAVE seem to depend on NAME (event?) + state=value, similar to Wwise + * - presumably TONE/REQD/SEQD chunks have WAVE<>event matching info since they seem to always appear + */ /* open the file for reading */ if (!vgmstream_open_stream(vgmstream, sf_data, start_offset))