From ac998301c65cd4a8aaee2eac9cb1f0f89231011e Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Tue, 5 Oct 2021 20:31:37 -0700 Subject: [PATCH] Updated VGMStream to r1640-104-gc92e4f85 --- .../libvgmstream.xcodeproj/project.pbxproj | 8 +++ .../vgmstream/src/coding/ffmpeg_decoder.c | 2 +- .../src/coding/ffmpeg_decoder_custom_opus.c | 2 +- Frameworks/vgmstream/vgmstream/src/formats.c | 5 +- Frameworks/vgmstream/vgmstream/src/meta/hca.c | 56 +++++++++-------- .../vgmstream/vgmstream/src/meta/hca_keys.h | 17 +++++- .../vgmstream/vgmstream/src/meta/lopu.c | 61 +++++++++++++++++++ .../vgmstream/vgmstream/src/meta/lpcm_fb.c | 61 +++++++++++++++++++ .../vgmstream/vgmstream/src/meta/meta.h | 4 ++ Frameworks/vgmstream/vgmstream/src/meta/mp4.c | 30 ++++++--- Frameworks/vgmstream/vgmstream/src/meta/nwa.c | 16 ++++- Frameworks/vgmstream/vgmstream/src/meta/psb.c | 10 ++- .../vgmstream/vgmstream/src/vgmstream.c | 2 + .../vgmstream/vgmstream/src/vgmstream.h | 2 + 14 files changed, 236 insertions(+), 40 deletions(-) create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/lopu.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/lpcm_fb.c diff --git a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj index 3879cde40..852c63eda 100644 --- a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj @@ -518,6 +518,8 @@ 839933612591E8C1001855AF /* sbk.c in Sources */ = {isa = PBXBuildFile; fileRef = 8399335E2591E8C0001855AF /* sbk.c */; }; 83997F5B22D9569E00633184 /* rad.c in Sources */ = {isa = PBXBuildFile; fileRef = 83997F5722D9569E00633184 /* rad.c */; }; 839B54521EEE1D9600048A2D /* ngc_ulw.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BD11F1EEE1CF200198540 /* ngc_ulw.c */; }; + 839C3D27270D49FF00E13653 /* lpcm_fb.c in Sources */ = {isa = PBXBuildFile; fileRef = 839C3D22270D49FF00E13653 /* lpcm_fb.c */; }; + 839C3D28270D49FF00E13653 /* lopu.c in Sources */ = {isa = PBXBuildFile; fileRef = 839C3D26270D49FF00E13653 /* lopu.c */; }; 839E21E01F2EDAF100EE54D7 /* vorbis_custom_data_fsb.h in Headers */ = {isa = PBXBuildFile; fileRef = 839E21D61F2EDAF000EE54D7 /* vorbis_custom_data_fsb.h */; }; 839E21E11F2EDAF100EE54D7 /* vorbis_custom_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 839E21D71F2EDAF000EE54D7 /* vorbis_custom_decoder.c */; }; 839E21E21F2EDAF100EE54D7 /* vorbis_custom_utils_wwise.c in Sources */ = {isa = PBXBuildFile; fileRef = 839E21D81F2EDAF000EE54D7 /* vorbis_custom_utils_wwise.c */; }; @@ -1328,6 +1330,8 @@ 8399335D2591E8C0001855AF /* ubi_sb_garbage_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ubi_sb_garbage_streamfile.h; sourceTree = ""; }; 8399335E2591E8C0001855AF /* sbk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sbk.c; sourceTree = ""; }; 83997F5722D9569E00633184 /* rad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rad.c; sourceTree = ""; }; + 839C3D22270D49FF00E13653 /* lpcm_fb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lpcm_fb.c; sourceTree = ""; }; + 839C3D26270D49FF00E13653 /* lopu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lopu.c; sourceTree = ""; }; 839E21D61F2EDAF000EE54D7 /* vorbis_custom_data_fsb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vorbis_custom_data_fsb.h; sourceTree = ""; }; 839E21D71F2EDAF000EE54D7 /* vorbis_custom_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_decoder.c; sourceTree = ""; }; 839E21D81F2EDAF000EE54D7 /* vorbis_custom_utils_wwise.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_utils_wwise.c; sourceTree = ""; }; @@ -1945,6 +1949,8 @@ 83D20074248DDB760048BD24 /* ktsr.c */, 830EBE122004656E0023AA10 /* ktss.c */, 8373342423F60CDB00DE14DC /* kwb.c */, + 839C3D26270D49FF00E13653 /* lopu.c */, + 839C3D22270D49FF00E13653 /* lpcm_fb.c */, 8373341F23F60CDB00DE14DC /* lrmd_streamfile.h */, 8373342223F60CDB00DE14DC /* lrmd.c */, 836F6E5A18BDC2180095E648 /* lsf.c */, @@ -2656,6 +2662,7 @@ 834FE109215C79ED000A5D3D /* idsp_ie.c in Sources */, 83299FD01E7660C7003A3242 /* bik.c in Sources */, 8346D97C25BF838C00D1A8B0 /* mjb_mjh.c in Sources */, + 839C3D27270D49FF00E13653 /* lpcm_fb.c in Sources */, 8373341823F60C7B00DE14DC /* tgcadpcm_decoder.c in Sources */, 83FC417326D3304D009A2022 /* xsh_xsd_xss.c in Sources */, 836F6F3318BDC2190095E648 /* ngc_dtk_decoder.c in Sources */, @@ -2756,6 +2763,7 @@ 83AA7F812519C042004C5298 /* silence.c in Sources */, 834FE0B3215C798C000A5D3D /* acm_decoder_util.c in Sources */, 837CEA7A23487E2500E62A4A /* ffmpeg_decoder_utils.c in Sources */, + 839C3D28270D49FF00E13653 /* lopu.c in Sources */, 837CEAF823487F2C00E62A4A /* xmv_valve.c in Sources */, 836F6F6718BDC2190095E648 /* acm.c in Sources */, 834FE0FD215C79ED000A5D3D /* vpk.c in Sources */, diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c index e363f5afc..fa971d2cc 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c @@ -404,9 +404,9 @@ ffmpeg_codec_data* init_ffmpeg_header_offset_subsong(STREAMFILE* sf, uint8_t* he VGM_ASSERT(stream->codecpar->trailing_padding > 0, "FFMPEG: trailing_padding %i\n", (int)stream->codecpar->trailing_padding); VGM_ASSERT(stream->codecpar->seek_preroll > 0, "FFMPEG: seek_preroll %i\n", (int)stream->codecpar->seek_preroll);//seek delay: OPUS VGM_ASSERT(stream->start_time > 0, "FFMPEG: start_time %i\n", (int)stream->start_time); //delay +#if 0 //LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 64, 100) VGM_ASSERT(stream->first_discard_sample > 0, "FFMPEG: first_discard_sample %i\n", (int)stream->first_discard_sample); //padding: MP3 VGM_ASSERT(stream->last_discard_sample > 0, "FFMPEG: last_discard_sample %i\n", (int)stream->last_discard_sample); //padding: MP3 -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 64, 100) VGM_ASSERT(stream->skip_samples > 0, "FFMPEG: skip_samples %i\n", (int)stream->skip_samples); //delay: MP4 VGM_ASSERT(stream->start_skip_samples > 0, "FFMPEG: start_skip_samples %i\n", (int)stream->start_skip_samples); //delay: MP3 #endif diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c index 80f676e13..cb69586e1 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c @@ -349,7 +349,7 @@ static STREAMFILE* setup_opus_streamfile(STREAMFILE* sf, opus_config* cfg, off_t /* setup subfile */ new_sf = open_wrap_streamfile(sf); new_sf = open_io_streamfile_ex_f(new_sf, &io_data, sizeof(opus_io_data), opus_io_read, opus_io_size, opus_io_init, opus_io_close); - new_sf = open_buffer_streamfile_f(new_sf, 0); + //new_sf = open_buffer_streamfile_f(new_sf, 0); /* seems slightly slower on typical files */ return new_sf; fail: return NULL; diff --git a/Frameworks/vgmstream/vgmstream/src/formats.c b/Frameworks/vgmstream/vgmstream/src/formats.c index 98a8c890b..ad468ca84 100644 --- a/Frameworks/vgmstream/vgmstream/src/formats.c +++ b/Frameworks/vgmstream/vgmstream/src/formats.c @@ -266,6 +266,7 @@ static const char* extension_list[] = { "l", "l00", //txth/reserved [Disney's Dinosaur (PS2)] "laac", //fake extension for .aac (tri-Ace) + "ladpcm", //not fake "laif", //fake extension for .aif (various) "laiff", //fake extension for .aiff "laifc", //fake extension for .aifc @@ -289,7 +290,7 @@ static const char* extension_list[] = { "lmp4", //fake extension for .mp4 "lmpc", //fake extension for .mpc, FFmpeg/not parsed "logg", //fake extension for .ogg - "lopus", //fake extension for .opus + "lopus", //fake extension for .opus, used by LOPU too "lp", "lpcm", "lpk", @@ -1364,6 +1365,8 @@ static const meta_info meta_info_list[] = { {meta_BNK_RELIC, "Relic BNK header"}, {meta_XSH_XSD_XSS, "Treyarch XSH+XSD/XSS header"}, {meta_PSB, "M2 PSB header"}, + {meta_LOPU_FB, "French-Bread LOPU header"}, + {meta_LPCM_FB, "French-Bread LPCM header"}, }; void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) { diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca.c b/Frameworks/vgmstream/vgmstream/src/meta/hca.c index 1a9fb4864..ddc7226e3 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca.c @@ -3,7 +3,7 @@ #include "../coding/coding.h" #include "../coding/hca_decoder_clhca.h" -//#define HCA_BRUTEFORCE +#define HCA_BRUTEFORCE #ifdef HCA_BRUTEFORCE static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey); #endif @@ -22,12 +22,12 @@ VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) { /* checks */ + if ((read_u32be(0x00,sf) & 0x7F7F7F7F) != get_id32be("HCA\0")) /* masked in encrypted files */ + goto fail; + if (!check_extensions(sf, "hca")) return NULL; - if ((read_u32be(0x00,sf) & 0x7F7F7F7F) != 0x48434100) /* "HCA\0", possibly masked */ - goto fail; - /* init vgmstream and library's context, will validate the HCA */ hca_data = init_hca(sf); if (!hca_data) { @@ -212,15 +212,15 @@ static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data off_t keys_size, bytes; int pos; uint64_t old_key = 0; + uint64_t key = 0; - VGM_LOG("HCA: test keys.bin (type %i)\n", type); - - *p_keycode = 0; - /* load whole file in memory for performance (exes with keys shouldn't be too big) */ sf_keys = open_streamfile_by_filename(sf, "keys.bin"); - if (!sf_keys) goto done; + if (!sf_keys) return; + + VGM_LOG("HCA: test keys.bin (type %i)\n", type); + *p_keycode = 0; keys_size = get_streamfile_size(sf_keys); @@ -234,7 +234,6 @@ static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data pos = 0; while (pos < keys_size - 4) { - uint64_t key; VGM_ASSERT(pos % 0x1000000 == 0, "HCA: pos %x...\n", pos); /* keys are usually u64le but other orders may exist */ @@ -256,8 +255,10 @@ static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data cur_score = 0; test_key(hca_data, key, subkey, &cur_score, p_keycode); - if (cur_score == 1) + if (cur_score == 1) { + best_score = cur_score; goto done; + } if (cur_score > 0 && cur_score <= 500) { VGM_LOG("HCA: possible key=%08x%08x (score=%i) at %x\n", @@ -268,25 +269,32 @@ static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data } done: - VGM_ASSERT(best_score > 0, "HCA: best key=%08x%08x (score=%i)\n", - (uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), best_score); - VGM_ASSERT(best_score < 0, "HCA: key not found\n"); - if (best_score < 0 || best_score > 10000) + if (best_score < 0 || best_score > 10000) { *p_keycode = 0; + VGM_LOG("HCA: good key not found\n"); + } + else { + /* print key as p_keycode includes subkey */ + VGM_LOG("HCA: best key=%08x%08x (score=%i)\n", + (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), best_score); + } close_streamfile(sf_keys); free(buf); } static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) { - bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_4); - bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_4); - bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_4); - bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_4); bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_1); - bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_1); +/* bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_1); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_1); bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_1); + + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_4); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_4); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_4); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_4); +*/ } @@ -303,13 +311,13 @@ static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, uns char line[1024]; - VGM_LOG("HCA: test keys.txt\n"); - - *p_keycode = 0; /* load whole file in memory for performance (exes with keys shouldn't be too big) */ sf_keys = open_streamfile_by_filename(sf, "keys.txt"); - if (!sf_keys) goto done; + if (!sf_keys) return; + + VGM_LOG("HCA: test keys.txt\n"); + *p_keycode = 0; keys_size = get_streamfile_size(sf_keys); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h index 616cad7f7..759a4c27b 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h @@ -758,9 +758,24 @@ static const hcakey_info hcakey_list[] = { // m HOLD'EM (Android) {369211553984367}, // 00014FCBC385AF6F - + // Sonic Colors Ultimate (multi) {1991062320101111}, // 000712DC5250B6F7 + + // ALTDEUS: Beyond Chronos (PC) [base-string 14238637353525924 + mods)] + {14238637353525934}, // 003295F7198AE2AE - bgm + {14238637353525954}, // 003295F7198AE2C2 - se + {14238637353525944}, // 003295F7198AE2B8 - voice + + // SHOW BY ROCK!! Fes A Live (Android) + {54605542411982574}, // 00C1FF73963BD6EE + + // Touhou Danmaku Kagura (Android) + {5654863921795627}, // 001417119B4FD22B + + // Nogizaka 46 Fractal (Android) + {984635491346198130}, // 0DAA20C336EEAE72 + }; #endif/*_HCA_KEYS_H_*/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/lopu.c b/Frameworks/vgmstream/vgmstream/src/meta/lopu.c new file mode 100644 index 000000000..f62853197 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/lopu.c @@ -0,0 +1,61 @@ +#include "meta.h" +#include "../coding/coding.h" + + +/* LOPU - French-Bread's Opus [Melty Blood: Type Lumina (Switch)] */ +VGMSTREAM* init_vgmstream_lopu_fb(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint32_t start_offset, data_size; + int loop_flag, channels, sample_rate; + int32_t num_samples, loop_start, loop_end, skip; + + /* checks */ + if (!is_id32be(0x00, sf, "LOPU")) + goto fail; + + /* .lopus: real extension (honest) */ + if (!check_extensions(sf, "lopus")) + goto fail; + + start_offset = read_u32le(0x04, sf); + sample_rate = read_s32le(0x08, sf); + channels = read_s16le(0x0c, sf); + /* 0x10: ? (1984) */ + num_samples = read_s32le(0x14, sf); + loop_start = read_s32le(0x18, sf); + loop_end = read_s32le(0x1c, sf) + 1; + /* 0x20: frame size */ + skip = read_s16le(0x24, sf); + data_size = read_u32le(0x28, sf); + /* rest: null */ + + loop_flag = (loop_end > 0); /* -1 if no loop */ + num_samples -= skip; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_LOPU_FB; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = num_samples; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; + +#ifdef VGM_USE_FFMPEG + vgmstream->codec_data = init_ffmpeg_switch_opus(sf, start_offset, data_size, vgmstream->channels, skip, vgmstream->sample_rate); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; +#else + goto fail; +#endif + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/lpcm_fb.c b/Frameworks/vgmstream/vgmstream/src/meta/lpcm_fb.c new file mode 100644 index 000000000..0907c8eef --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/lpcm_fb.c @@ -0,0 +1,61 @@ +#include "meta.h" +#include "../coding/coding.h" + + +/* LPCM - French-Bread's DSP [Melty Blood: Type Lumina (Switch)] */ +VGMSTREAM* init_vgmstream_lpcm_fb(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint32_t start_offset; + int loop_flag, channels, sample_rate; + int32_t num_samples; + + /* checks */ + if (!is_id32be(0x00, sf, "LPCM")) + goto fail; + + /* .ladpcm: real extension (honest) */ + if (!check_extensions(sf, "ladpcm")) + goto fail; + + /* 0x04: dsp offset (0x20) */ + if (read_u32le(0x04, sf) != 0x20) + goto fail; + + num_samples = read_s32le(0x20, sf); + /* 0x24: nibbles? */ + sample_rate = read_s32le(0x28, sf); + /* 0x2c: 0? */ + /* 0x30: 2? */ + /* 0x34: nibbles? */ + /* 0x38: 2? */ + if (read_u32le(0x38, sf) != 2) + goto fail; + + channels = 1; + loop_flag = 0; + + start_offset = 0x78; /* could be 0x80 but this is closer to num_samples */ + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_LPCM_FB; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = num_samples; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_none; + + dsp_read_coefs_le(vgmstream, sf, 0x3c, 0); + /* 0x5c: hist? */ + + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h index 32d354d94..c2e097fae 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -964,4 +964,8 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf); VGMSTREAM* init_vgmstream_psb(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_lopu_fb(STREAMFILE* sf); + +VGMSTREAM* init_vgmstream_lpcm_fb(STREAMFILE* sf); + #endif /*_META_H*/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mp4.c b/Frameworks/vgmstream/vgmstream/src/meta/mp4.c index 288d80a61..7f51871c6 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/mp4.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/mp4.c @@ -25,16 +25,16 @@ VGMSTREAM* init_vgmstream_mp4_aac_ffmpeg(STREAMFILE* sf) { /* checks */ - /* .bin: Final Fantasy Dimensions (iOS), Final Fantasy V (iOS) - * .msd: UNO (iOS) */ - if (!check_extensions(sf,"mp4,m4a,m4v,lmp4,bin,lbin,msd")) - goto fail; - if ((read_u32be(0x00,sf) & 0xFFFFFF00) != 0) /* first atom BE size (usually ~0x18) */ goto fail; if (!is_id32be(0x04,sf, "ftyp")) goto fail; + /* .bin: Final Fantasy Dimensions (iOS), Final Fantasy V (iOS) + * .msd: UNO (iOS) */ + if (!check_extensions(sf,"mp4,m4a,m4v,lmp4,bin,lbin,msd")) + goto fail; + file_size = get_streamfile_size(sf); ffmpeg_data = init_ffmpeg_offset(sf, start_offset, file_size); @@ -86,7 +86,7 @@ fail: /* read useful MP4 chunks */ static void parse_mp4(STREAMFILE* sf, mp4_header* mp4) { - off_t offset, suboffset, max_offset, max_suboffset; + uint32_t offset, suboffset, max_offset, max_suboffset; /* MOV format chunks, called "atoms", size goes first because Apple */ @@ -117,12 +117,25 @@ static void parse_mp4(STREAMFILE* sf, mp4_header* mp4) { mp4->loop_start = read_u32be(offset + 0x08 + 0x2c,sf); mp4->loop_end = read_u32be(offset + 0x08 + 0x30,sf); } - /* could stop reading since FFmpeg will too */ + max_offset = 0; + } + /* M2 emu's .m4a (codename zoom) */ + else if (is_id32be(offset + 0x08 + 0x00,sf, "ZOOM")) { + /* 0x00: id */ + mp4->encoder_delay = read_s32be(offset + 0x08 + 0x04,sf); /* Apple's 2112, also in iTunes tag */ + /* 0x08: end padding */ + mp4->num_samples = read_s32be(offset + 0x08 + 0x0c,sf); + mp4->loop_start = read_s32be(offset + 0x08 + 0x10,sf); + mp4->loop_end = read_s32be(offset + 0x08 + 0x14,sf); + mp4->loop_flag = (mp4->loop_end != 0); + if (mp4->loop_flag) + mp4->loop_end++; /* assumed, matches num_samples this way */ + max_offset = 0; } break; case 0x6D6F6F76: { /* "moov" (header) */ - suboffset = offset += 0x08; + suboffset = offset + 0x08; max_suboffset = offset + size; while (suboffset < max_suboffset) { uint32_t subsize = read_u32be(suboffset + 0x00,sf); @@ -145,6 +158,7 @@ static void parse_mp4(STREAMFILE* sf, mp4_header* mp4) { mp4->num_samples = read_s32be(criw_offset + 0x0c,sf); mp4->loop_flag = (mp4->loop_end > 0); /* next 2 fields are null */ + max_offset = 0; } break; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/nwa.c b/Frameworks/vgmstream/vgmstream/src/meta/nwa.c index ca554442f..d5f634b1b 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/nwa.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/nwa.c @@ -200,9 +200,19 @@ static int get_loops_gameexe_ini(STREAMFILE* sf, int* p_loop_flag, int32_t* p_lo length = ext-1-namebase; file_size = get_streamfile_size(sf_loop); - /* format of line is: - * #DSTRACK = 00000000 - eeeeeeee - ssssssss = "name" = "name2?" - * ^22 ^33 ^45 ^57 + /* According to the official documentation of RealLiveMax (the public version of RealLive), format of line is: + * #DSTRACK = 00000000 - eeeeeeee - ssssssss = "filename" = "alias for game script" + * ^22 ^33 ^45 ^57? + * + * Original text from the documentation (written in Japanese) is: + * ; ■BGMの登録:DirectSound + * ;(※必要ない場合は登録しないで下さい。) + * ; 終了位置の設定が 99999999 なら最後まで演奏します。 + * ; ※設定値はサンプル数で指定して下さい。(旧システムではバイト指定でしたので注意してください。) + * ;========================================================================================================= + * ; 開始位置 - 終了位置 - リピート = ファイル名 = 登録名 + * #DSTRACK = 00000000 - 01896330 - 00088270 = "b_manuke" = "b_manuke" + * #DSTRACK = 00000000 - 01918487 - 00132385 = "c_happy" = "c_happy" */ for (found = 0, offset = 0; !found && offsetcoding_type = coding_PCM24LE; break; /* Legend of Mana (PC) */ default: goto fail; } + + if (psb.duration_test && psb.loop_start + psb.loop_end < vgmstream->num_samples) + vgmstream->loop_end_sample += psb.loop_start; break; case MSADPCM: /* [Senxin Aleste (AC)] */ @@ -218,6 +222,8 @@ VGMSTREAM* init_vgmstream_psb(STREAMFILE* sf) { } vgmstream->num_samples = read_u32le(psb.stream_offset[0] + 0x00, sf); + if (psb.duration_test && psb.loop_start + psb.loop_end < vgmstream->num_samples) + vgmstream->loop_end_sample += psb.loop_start; break; default: @@ -592,7 +598,9 @@ static int parse_psb_channels(psb_header_t* psb, psb_node_t* nchans) { psb->loop_start = psb_node_get_result(&nsub).num; psb_node_by_index(&node, 1, &nsub); - psb->loop_end = psb_node_get_result(&nsub).num + psb->loop_start; /* duration */ + psb->loop_end = psb_node_get_result(&nsub).num + 1; /* assumed, matches num_samples */ + /* duration [LoM (PC), Namco Museum V1 (PC)] or standard [G-Darius (Sw)] (no apparent flags) */ + psb->duration_test = 1; } } diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c index f05370cb1..c42bced87 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c @@ -527,6 +527,8 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_bnk_relic, init_vgmstream_xsh_xsd_xss, init_vgmstream_psb, + init_vgmstream_lopu_fb, + init_vgmstream_lpcm_fb, /* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */ diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.h b/Frameworks/vgmstream/vgmstream/src/vgmstream.h index 4a972ba02..7e36a84ab 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.h @@ -756,6 +756,8 @@ typedef enum { meta_BNK_RELIC, meta_XSH_XSD_XSS, meta_PSB, + meta_LOPU_FB, + meta_LPCM_FB, } meta_t;