From ace62005db887366a681ecc3d62c6a57c0701559 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Mon, 2 May 2022 14:58:25 -0700 Subject: [PATCH] Updated VGMStream to r1745-4-g9ef1030d Signed-off-by: Christopher Snowhill --- .../libvgmstream.xcodeproj/project.pbxproj | 32 +++- .../vgmstream/vgmstream/src/coding/coding.h | 4 +- .../vgmstream/src/coding/hca_decoder.c | 9 +- .../vgmstream/src/coding/ima_decoder.c | 16 +- .../vgmstream/src/coding/mpeg_custom_utils.c | 91 ++++++----- .../vgmstream/src/coding/ubi_adpcm_decoder.c | 60 ++++--- Frameworks/vgmstream/vgmstream/src/decode.c | 11 +- Frameworks/vgmstream/vgmstream/src/formats.c | 9 ++ Frameworks/vgmstream/vgmstream/src/info.c | 20 ++- .../vgmstream/vgmstream/src/layout/blocked.c | 3 + .../vgmstream/src/layout/blocked_tt_ad.c | 31 ++++ .../vgmstream/vgmstream/src/layout/layout.h | 1 + Frameworks/vgmstream/vgmstream/src/meta/aax.c | 62 +++---- Frameworks/vgmstream/vgmstream/src/meta/acb.c | 2 +- .../vgmstream/vgmstream/src/meta/adm3.c | 152 ++++++++++++++++++ Frameworks/vgmstream/vgmstream/src/meta/cpk.c | 7 +- Frameworks/vgmstream/vgmstream/src/meta/csb.c | 6 +- Frameworks/vgmstream/vgmstream/src/meta/esf.c | 46 ++++++ .../vgmstream/vgmstream/src/meta/meta.h | 6 + .../vgmstream/vgmstream/src/meta/mpeg.c | 21 ++- Frameworks/vgmstream/vgmstream/src/meta/p3d.c | 47 +++--- .../vgmstream/vgmstream/src/meta/riff.c | 4 +- .../vgmstream/vgmstream/src/meta/sspf.c | 2 +- Frameworks/vgmstream/vgmstream/src/meta/tgc.c | 22 ++- .../vgmstream/vgmstream/src/meta/tt_ad.c | 94 +++++++++++ .../vgmstream/vgmstream/src/meta/txth.c | 81 +++++----- .../vgmstream/vgmstream/src/meta/ubi_hx.c | 7 +- .../vgmstream/vgmstream/src/meta/ubi_sb.c | 2 +- Frameworks/vgmstream/vgmstream/src/render.c | 1 + .../vgmstream/src/{meta => util}/cri_utf.c | 2 +- .../vgmstream/src/{meta => util}/cri_utf.h | 0 .../vgmstream/vgmstream/src/vgmstream.c | 12 +- .../vgmstream/vgmstream/src/vgmstream.h | 5 + 33 files changed, 667 insertions(+), 201 deletions(-) create mode 100644 Frameworks/vgmstream/vgmstream/src/layout/blocked_tt_ad.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/adm3.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/esf.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/tt_ad.c rename Frameworks/vgmstream/vgmstream/src/{meta => util}/cri_utf.c (99%) rename Frameworks/vgmstream/vgmstream/src/{meta => util}/cri_utf.h (100%) diff --git a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj index 8f06479ce..27e8a7022 100644 --- a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj @@ -251,6 +251,12 @@ 836C052C23F62F3100FA07C7 /* libatrac9.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 835FC6C623F62AEF006960FA /* libatrac9.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 836EF0DB27BB975900BF35B2 /* libvorbis.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 836EF0D027BB960A00BF35B2 /* libvorbis.0.dylib */; }; 836EF0DD27BB97C500BF35B2 /* libvorbisfile.3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 836EF0DC27BB97BA00BF35B2 /* libvorbisfile.3.dylib */; }; + 836F46AE28208735005B9B87 /* blocked_tt_ad.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F46AD28208735005B9B87 /* blocked_tt_ad.c */; }; + 836F46B22820874D005B9B87 /* tt_ad.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F46AF2820874D005B9B87 /* tt_ad.c */; }; + 836F46B32820874D005B9B87 /* esf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F46B02820874D005B9B87 /* esf.c */; }; + 836F46B42820874D005B9B87 /* adm3.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F46B12820874D005B9B87 /* adm3.c */; }; + 836F46B7282087A6005B9B87 /* cri_utf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F46B5282087A6005B9B87 /* cri_utf.c */; }; + 836F46B8282087A6005B9B87 /* cri_utf.h in Headers */ = {isa = PBXBuildFile; fileRef = 836F46B6282087A6005B9B87 /* cri_utf.h */; }; 836F6B4718BDB8880095E648 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 836F6B4518BDB8880095E648 /* InfoPlist.strings */; }; 836F6F1E18BDC2190095E648 /* acm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE018BDC2180095E648 /* acm_decoder.c */; }; 836F6F2018BDC2190095E648 /* adx_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE218BDC2180095E648 /* adx_decoder.c */; }; @@ -677,8 +683,6 @@ 83FBD506235D31F800D35BCD /* riff_ogg_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83FBD502235D31F700D35BCD /* riff_ogg_streamfile.h */; }; 83FC176D23AC58D100E1025F /* xma_ue3.c in Sources */ = {isa = PBXBuildFile; fileRef = 83FC176A23AC58D100E1025F /* xma_ue3.c */; }; 83FC176E23AC58D100E1025F /* csb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83FC176B23AC58D100E1025F /* csb.c */; }; - 83FC176F23AC58D100E1025F /* cri_utf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83FC176C23AC58D100E1025F /* cri_utf.h */; }; - 83FC177123AC59A800E1025F /* cri_utf.c in Sources */ = {isa = PBXBuildFile; fileRef = 83FC177023AC59A800E1025F /* cri_utf.c */; }; 83FC417026D32FF5009A2022 /* hca_decoder_clhca.h in Headers */ = {isa = PBXBuildFile; fileRef = 83FC416E26D32FF5009A2022 /* hca_decoder_clhca.h */; }; 83FC417126D32FF5009A2022 /* hca_decoder_clhca.c in Sources */ = {isa = PBXBuildFile; fileRef = 83FC416F26D32FF5009A2022 /* hca_decoder_clhca.c */; }; 83FC417326D3304D009A2022 /* xsh_xsd_xss.c in Sources */ = {isa = PBXBuildFile; fileRef = 83FC417226D3304D009A2022 /* xsh_xsd_xss.c */; }; @@ -1042,6 +1046,12 @@ 835FC6C123F62AEE006960FA /* libatrac9.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libatrac9.xcodeproj; path = ../libatrac9/libatrac9.xcodeproj; sourceTree = ""; }; 836EF0D027BB960A00BF35B2 /* libvorbis.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libvorbis.0.dylib; path = ../../ThirdParty/vorbis/lib/libvorbis.0.dylib; sourceTree = ""; }; 836EF0DC27BB97BA00BF35B2 /* libvorbisfile.3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libvorbisfile.3.dylib; path = ../../ThirdParty/vorbis/lib/libvorbisfile.3.dylib; sourceTree = ""; }; + 836F46AD28208735005B9B87 /* blocked_tt_ad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_tt_ad.c; sourceTree = ""; }; + 836F46AF2820874D005B9B87 /* tt_ad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tt_ad.c; sourceTree = ""; }; + 836F46B02820874D005B9B87 /* esf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = esf.c; sourceTree = ""; }; + 836F46B12820874D005B9B87 /* adm3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adm3.c; sourceTree = ""; }; + 836F46B5282087A6005B9B87 /* cri_utf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cri_utf.c; sourceTree = ""; }; + 836F46B6282087A6005B9B87 /* cri_utf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cri_utf.h; sourceTree = ""; }; 836F6B3918BDB8880095E648 /* libvgmstream.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = libvgmstream.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 836F6B4418BDB8880095E648 /* libvgmstream-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "libvgmstream-Info.plist"; sourceTree = ""; }; 836F6B4618BDB8880095E648 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -1466,8 +1476,6 @@ 83FBD502235D31F700D35BCD /* riff_ogg_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = riff_ogg_streamfile.h; sourceTree = ""; }; 83FC176A23AC58D100E1025F /* xma_ue3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xma_ue3.c; sourceTree = ""; }; 83FC176B23AC58D100E1025F /* csb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = csb.c; sourceTree = ""; }; - 83FC176C23AC58D100E1025F /* cri_utf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cri_utf.h; sourceTree = ""; }; - 83FC177023AC59A800E1025F /* cri_utf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cri_utf.c; sourceTree = ""; }; 83FC416E26D32FF5009A2022 /* hca_decoder_clhca.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hca_decoder_clhca.h; sourceTree = ""; }; 83FC416F26D32FF5009A2022 /* hca_decoder_clhca.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hca_decoder_clhca.c; sourceTree = ""; }; 83FC417226D3304D009A2022 /* xsh_xsd_xss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xsh_xsd_xss.c; sourceTree = ""; }; @@ -1775,6 +1783,7 @@ 8306B09C20984550000302D4 /* blocked_str_snds.c */, 8306B09820984550000302D4 /* blocked_thp.c */, 8306B09920984550000302D4 /* blocked_tra.c */, + 836F46AD28208735005B9B87 /* blocked_tt_ad.c */, 83031ECA243C50CB00C3F3E0 /* blocked_ubi_sce.c */, 83AA5D1A1F6E2F7F0020821C /* blocked_vgs.c */, 83031ECB243C50CB00C3F3E0 /* blocked_vid1.c */, @@ -1810,6 +1819,7 @@ 837CEAD623487E8300E62A4A /* acb.c */, 836F6E2B18BDC2180095E648 /* acm.c */, 83F2CCE125A5B41600F46FA8 /* acx.c */, + 836F46B12820874D005B9B87 /* adm3.c */, 83D26A7626E66D98001A9475 /* adp_bos.c */, 83AA7F7A2519C042004C5298 /* adp_konami.c */, 834FE0CF215C79E8000A5D3D /* adpcm_capcom.c */, @@ -1863,8 +1873,6 @@ 834FE0E8215C79EC000A5D3D /* ck.c */, 8346D97825BF838C00D1A8B0 /* compresswave.c */, 83A8BAE425667AA7000F5F3F /* cpk.c */, - 83FC177023AC59A800E1025F /* cri_utf.c */, - 83FC176C23AC58D100E1025F /* cri_utf.h */, 83FC176B23AC58D100E1025F /* csb.c */, 834FE0D8215C79EA000A5D3D /* csmp.c */, 836F6E3C18BDC2180095E648 /* Cstr.c */, @@ -1896,6 +1904,7 @@ 83AF2CC826226BA500538240 /* encrypted_bgm_streamfile.h */, 832FC36E278FAE3E0056A860 /* encrypted_mc161_streamfile.h */, 83031ECE243C50DE00C3F3E0 /* encrypted.c */, + 836F46B02820874D005B9B87 /* esf.c */, 836F6E4918BDC2180095E648 /* exakt_sc.c */, 836F6E4A18BDC2180095E648 /* excitebots.c */, 83AF2CC626226BA400538240 /* exst.c */, @@ -2169,6 +2178,7 @@ 83E7FD6425EF2B2400683FD2 /* tac.c */, 8373342E23F60D4100DE14DC /* tgc.c */, 836F6EFA18BDC2190095E648 /* thp.c */, + 836F46AF2820874D005B9B87 /* tt_ad.c */, 836F6EFB18BDC2190095E648 /* tun.c */, 83C7280122BC893A00678B4A /* txth_streamfile.h */, 830165971F256BD000CA0941 /* txth.c */, @@ -2274,6 +2284,8 @@ children = ( 83D26A8026E66DC2001A9475 /* chunks.c */, 83D26A7E26E66DC2001A9475 /* chunks.h */, + 836F46B5282087A6005B9B87 /* cri_utf.c */, + 836F46B6282087A6005B9B87 /* cri_utf.h */, 83B46FD42707FB9A00847FC9 /* endianness.h */, 83D26A7D26E66DC2001A9475 /* log.c */, 83D26A7F26E66DC2001A9475 /* log.h */, @@ -2325,6 +2337,7 @@ 83D26A8326E66DC2001A9475 /* log.h in Headers */, 83C7282222BC893D00678B4A /* mta2_streamfile.h in Headers */, 83AA7F802519C042004C5298 /* sab_streamfile.h in Headers */, + 836F46B8282087A6005B9B87 /* cri_utf.h in Headers */, 83A21F87201D8981000F04B9 /* fsb_keys.h in Headers */, 83E7FD6325EF2B0C00683FD2 /* tac_decoder_lib_data.h in Headers */, 832FC36C278FA4CB0056A860 /* ubi_ckd_cwav_streamfile.h in Headers */, @@ -2341,7 +2354,6 @@ 8349A9111FE6258200E26435 /* bar_streamfile.h in Headers */, 83D2007A248DDB770048BD24 /* fsb_encrypted_streamfile.h in Headers */, 836F6F2718BDC2190095E648 /* g72x_state.h in Headers */, - 83FC176F23AC58D100E1025F /* cri_utf.h in Headers */, 83C7282822BC8C1500678B4A /* mixing.h in Headers */, 832BF82C21E0514B006F50F1 /* hca_keys_awb.h in Headers */, 839933602591E8C1001855AF /* ubi_sb_garbage_streamfile.h in Headers */, @@ -2611,6 +2623,7 @@ 836F6F9B18BDC2190095E648 /* mn_str.c in Sources */, 832BF82821E0514B006F50F1 /* xwma.c in Sources */, 83FC176E23AC58D100E1025F /* csb.c in Sources */, + 836F46B32820874D005B9B87 /* esf.c in Sources */, 8306B0EB20984590000302D4 /* wave_segmented.c in Sources */, 83E7FD5F25EF2B0C00683FD2 /* tac_decoder.c in Sources */, 836F6F9F18BDC2190095E648 /* musc.c in Sources */, @@ -2622,6 +2635,7 @@ 836F6FD718BDC2190095E648 /* ps2_filp.c in Sources */, 8346D97925BF838C00D1A8B0 /* idtech.c in Sources */, 83FF0EBC1E93282100C58054 /* wwise.c in Sources */, + 836F46B42820874D005B9B87 /* adm3.c in Sources */, 836F6F7018BDC2190095E648 /* apple_caff.c in Sources */, 836F6FB618BDC2190095E648 /* ngc_sck_dsp.c in Sources */, 836F6F2818BDC2190095E648 /* ima_decoder.c in Sources */, @@ -2785,6 +2799,7 @@ 83C7282022BC893D00678B4A /* dcs_wav.c in Sources */, 8306B0F220984590000302D4 /* ubi_jade.c in Sources */, 83852B0C2680247900378854 /* ads_midway.c in Sources */, + 836F46AE28208735005B9B87 /* blocked_tt_ad.c in Sources */, 836F6FF918BDC2190095E648 /* ps2_snd.c in Sources */, 836F6F2918BDC2190095E648 /* l5_555_decoder.c in Sources */, 836F6FF318BDC2190095E648 /* ps2_rstm.c in Sources */, @@ -2865,6 +2880,7 @@ 836F6F3118BDC2190095E648 /* ngc_afc_decoder.c in Sources */, 836F6F9918BDC2190095E648 /* maxis_xa.c in Sources */, 836F702118BDC2190095E648 /* rs03.c in Sources */, + 836F46B7282087A6005B9B87 /* cri_utf.c in Sources */, 836F6F8818BDC2190095E648 /* fsb.c in Sources */, 83F2CCE525A5B41600F46FA8 /* acx.c in Sources */, 83FC176D23AC58D100E1025F /* xma_ue3.c in Sources */, @@ -2988,6 +3004,7 @@ 834FE100215C79ED000A5D3D /* svg.c in Sources */, 836F6F2518BDC2190095E648 /* g721_decoder.c in Sources */, 836F6FE818BDC2190095E648 /* ps2_mic.c in Sources */, + 836F46B22820874D005B9B87 /* tt_ad.c in Sources */, 836F6F3C18BDC2190095E648 /* xa_decoder.c in Sources */, 8317C24C26982CC1007DD0B8 /* sspr.c in Sources */, 832BF82521E0514B006F50F1 /* ogg_opus.c in Sources */, @@ -2995,7 +3012,6 @@ 836F6F9118BDC2190095E648 /* ios_psnd.c in Sources */, 836F700618BDC2190095E648 /* vgs_ps.c in Sources */, 834FE10F215C79ED000A5D3D /* sdf.c in Sources */, - 83FC177123AC59A800E1025F /* cri_utf.c in Sources */, 834FE0FF215C79ED000A5D3D /* sqex_scd_sscf.c in Sources */, 8373341A23F60C7B00DE14DC /* relic_decoder_mixfft.c in Sources */, 836F6FAA18BDC2190095E648 /* ngc_bh2pcm.c in Sources */, diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding.h b/Frameworks/vgmstream/vgmstream/src/coding/coding.h index 1b3d52b15..bd2c800e0 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/coding.h +++ b/Frameworks/vgmstream/vgmstream/src/coding/coding.h @@ -265,13 +265,12 @@ size_t ptadpcm_bytes_to_samples(size_t bytes, int channels, size_t frame_size); /* ubi_adpcm_decoder */ typedef struct ubi_adpcm_codec_data ubi_adpcm_codec_data; -ubi_adpcm_codec_data* init_ubi_adpcm(STREAMFILE* sf, off_t offset, int channels); +ubi_adpcm_codec_data* init_ubi_adpcm(STREAMFILE* sf, uint32_t offset, uint32_t size, int channels); void decode_ubi_adpcm(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do); void reset_ubi_adpcm(ubi_adpcm_codec_data* data); void seek_ubi_adpcm(ubi_adpcm_codec_data* data, int32_t num_sample); void free_ubi_adpcm(ubi_adpcm_codec_data* data); int32_t ubi_adpcm_get_samples(ubi_adpcm_codec_data* data); -int32_t ubi_adpcm_bytes_to_samples(ubi_adpcm_codec_data* data, uint32_t size); /* imuse_decoder */ @@ -492,6 +491,7 @@ void free_mpeg(mpeg_codec_data* data); int mpeg_get_sample_rate(mpeg_codec_data* data); long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data* data); +uint32_t mpeg_get_tag_size(STREAMFILE* sf, uint32_t offset, uint32_t header); int mpeg_get_frame_info(STREAMFILE* sf, off_t offset, mpeg_frame_info* info); #endif diff --git a/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c index b1daf710c..bd4a995c2 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c @@ -203,8 +203,11 @@ STREAMFILE* hca_get_streamfile(hca_codec_data* data) { * (ex. newer Tales of the Rays files clip a lot) */ #define HCA_KEY_MIN_TEST_FRAMES 3 //7 #define HCA_KEY_MAX_TEST_FRAMES 7 //12 -/* score of 10~30 isn't uncommon in a single frame, too many frames over that is unlikely */ -#define HCA_KEY_MAX_FRAME_SCORE 150 +/* score of 10~30 isn't uncommon in a single frame, too many frames over that is unlikely + * In rare cases of badly mastered frames there are +580. [Iris Mysteria! (Android)] + * Lesser is preferable (faster skips) but high scores are less common in the current detection. */ +//TODO: may need to improve detection by counting silent (0) vs valid samples, as bad keys give lots of 0s +#define HCA_KEY_MAX_FRAME_SCORE 600 #define HCA_KEY_MAX_TOTAL_SCORE (HCA_KEY_MAX_TEST_FRAMES * 50*HCA_KEY_SCORE_SCALE) /* Test a number of frames if key decrypts correctly. @@ -267,7 +270,7 @@ static int test_hca_score(hca_codec_data* data, hca_keytest_t* hk) { switch(score) { case 1: score = 1; break; case 0: score = 3*HCA_KEY_SCORE_SCALE; break; /* blanks after non-blacks aren't very trustable */ - default: score = score*HCA_KEY_SCORE_SCALE; + default: score = score * HCA_KEY_SCORE_SCALE; } total_score += score; diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c index a6ec41acf..68e6d3f6d 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c @@ -563,21 +563,23 @@ void decode_blitz_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channels /* IMA with custom frame sizes, header and nibble layout. Outputs an odd number of samples per frame, * so to simplify calcs this decodes full frames, thus hist doesn't need to be mantained. * Officially defined in "Microsoft Multimedia Standards Update" doc (RIFFNEW.pdf). */ -void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { +void decode_ms_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { int i, samples_read = 0, samples_done = 0, max_samples; int32_t hist1;// = stream->adpcm_history1_32; int step_index;// = stream->adpcm_step_index; + int frame_channels = vgmstream->codec_config ? 1 : vgmstream->channels; /* mono or mch modes */ + int frame_channel = vgmstream->codec_config ? 0 : channel; /* internal interleave (configurable size), mixed channels */ - int block_samples = ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1; + int block_samples = ((vgmstream->frame_size - 0x04*frame_channels) * 2 / frame_channels) + 1; first_sample = first_sample % block_samples; /* normal header (hist+step+reserved), per channel */ { //if (first_sample == 0) { - off_t header_offset = stream->offset + 0x04*channel; + off_t header_offset = stream->offset + 0x04*frame_channel; - hist1 = read_16bitLE(header_offset+0x00,stream->streamfile); - step_index = read_8bit(header_offset+0x02,stream->streamfile); /* 0x03: reserved */ + hist1 = read_s16le(header_offset+0x00,stream->streamfile); + step_index = read_u8(header_offset+0x02,stream->streamfile); /* 0x03: reserved */ if (step_index < 0) step_index = 0; if (step_index > 88) step_index = 88; @@ -595,7 +597,7 @@ void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * /* decode nibbles (layout: alternates 4 bytes/4*2 nibbles per channel) */ for (i = 0; i < max_samples; i++) { - off_t byte_offset = stream->offset + 0x04*vgmstream->channels + 0x04*channel + 0x04*vgmstream->channels*(i/8) + (i%8)/2; + off_t byte_offset = stream->offset + 0x04*frame_channels + 0x04*frame_channel + 0x04*frame_channels*(i/8) + (i%8)/2; int nibble_shift = (i&1?4:0); /* low nibble first */ std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); /* original expand */ @@ -609,7 +611,7 @@ void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * /* internal interleave: increment offset on complete frame */ if (first_sample + samples_done == block_samples) { - stream->offset += vgmstream->interleave_block_size; + stream->offset += vgmstream->frame_size; } //stream->adpcm_history1_32 = hist1; diff --git a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils.c b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils.c index 4a91fa664..b86c9c382 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils.c @@ -340,6 +340,37 @@ int mpeg_get_frame_info(STREAMFILE* sf, off_t offset, mpeg_frame_info* info) { return mpeg_get_frame_info_h(header, info); } + +uint32_t mpeg_get_tag_size(STREAMFILE* sf, uint32_t offset, uint32_t header) { + if (!header) + header = read_u32be(offset+0x00, sf); + + /* skip ID3v2 */ + if ((header & 0xFFFFFF00) == get_id32be("ID3\0")) { + size_t frame_size = 0; + uint8_t flags = read_u8(offset+0x05, sf); + /* this is how it's officially read :/ */ + frame_size += read_u8(offset+0x06, sf) << 21; + frame_size += read_u8(offset+0x07, sf) << 14; + frame_size += read_u8(offset+0x08, sf) << 7; + frame_size += read_u8(offset+0x09, sf) << 0; + frame_size += 0x0a; + if (flags & 0x10) /* footer? */ + frame_size += 0x0a; + + return frame_size; + + } + + /* skip ID3v1 */ + if ((header & 0xFFFFFF00) == get_id32be("TAG\0")) { + ;VGM_LOG("MPEG: ID3v1 at %x\n", offset); + return 0x80; + } + + return 0; +} + size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) { off_t offset = start_offset; off_t max_offset = start_offset + bytes; @@ -355,32 +386,13 @@ size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) { /* MPEG may use VBR so must read all frames */ while (offset < max_offset) { uint32_t header = read_u32be(offset+0x00, sf); - - /* skip ID3v2 */ - if ((header & 0xFFFFFF00) == 0x49443300) { /* "ID3\0" */ - size_t frame_size = 0; - uint8_t flags = read_u8(offset+0x05, sf); - /* this is how it's officially read :/ */ - frame_size += read_u8(offset+0x06, sf) << 21; - frame_size += read_u8(offset+0x07, sf) << 14; - frame_size += read_u8(offset+0x08, sf) << 7; - frame_size += read_u8(offset+0x09, sf) << 0; - frame_size += 0x0a; - if (flags & 0x10) /* footer? */ - frame_size += 0x0a; - - offset += frame_size; + size_t tag_size = mpeg_get_tag_size(sf, offset, header); + if (tag_size) { + offset += tag_size; continue; } - /* skip ID3v1 */ - if ((header & 0xFFFFFF00) == 0x54414700) { /* "TAG\0" */ - ;VGM_LOG("MPEG: ID3v1 at %lx\n", offset); - offset += 0x80; - continue; - } - - /* regular frame */ + /* regular frame (assumed) */ if (!mpeg_get_frame_info_h(header, &info)) { VGM_LOG("MPEG: unknown frame at %lx\n", offset); break; @@ -407,28 +419,31 @@ size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) { } /* other flags indicate seek table and stuff */ - /* vendor specific */ - if (info.frame_size > xing_offset + 0x78 + 0x24 && - read_u32be(offset + xing_offset + 0x78, sf) == 0x4C414D45) { /* "LAME" */ - if (info.layer == 3) { - uint32_t delays = read_u32be(offset + xing_offset + 0x8C, sf); - encoder_delay = ((delays >> 12) & 0xFFF); - encoder_padding = ((delays >> 0) & 0xFFF); + ;VGM_LOG("MPEG: found Xing header\n"); - encoder_delay += (528 + 1); /* implicit MDCT decoder delay (seen in LAME source) */ - if (encoder_padding > 528 + 1) - encoder_padding -= (528 + 1); - } - else { - encoder_delay = 240 + 1; + /* vendor specific */ + if (info.frame_size > xing_offset + 0x78 + 0x24) { + uint32_t sub_id = read_u32be(offset + xing_offset + 0x78, sf); + if (sub_id == get_id32be("LAME") || /* LAME */ + sub_id == get_id32be("Lavc")) { /* FFmpeg */ + if (info.layer == 3) { + uint32_t delays = read_u32be(offset + xing_offset + 0x8C, sf); + encoder_delay = ((delays >> 12) & 0xFFF); + encoder_padding = ((delays >> 0) & 0xFFF); + + encoder_delay += (528 + 1); /* implicit MDCT decoder delay (seen in LAME source) */ + if (encoder_padding > 528 + 1) + encoder_padding -= (528 + 1); + } + else { + encoder_delay = 240 + 1; + } } /* replay gain and stuff */ } /* there is also "iTunes" vendor with no apparent extra info, iTunes delays are in "iTunSMPB" ID3 tag */ - - ;VGM_LOG("MPEG: found Xing header\n"); break; /* we got samples */ } } diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ubi_adpcm_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ubi_adpcm_decoder.c index 948f039d2..729ff5241 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ubi_adpcm_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ubi_adpcm_decoder.c @@ -71,8 +71,8 @@ struct ubi_adpcm_codec_data { ubi_adpcm_header_data header; ubi_adpcm_channel_data ch[UBI_CHANNELS_MAX]; - off_t start_offset; - off_t offset; + uint32_t start_offset; + uint32_t offset; int subframe_number; uint8_t frame[UBI_FRAME_SIZE_MAX]; @@ -86,16 +86,17 @@ struct ubi_adpcm_codec_data { /* *********************************************************************** */ -static int parse_header(STREAMFILE* sf, ubi_adpcm_codec_data* data, off_t offset); +static int parse_header(STREAMFILE* sf, ubi_adpcm_codec_data* data, uint32_t offset, uint32_t size); static void decode_frame(STREAMFILE* sf, ubi_adpcm_codec_data* data); +static void fix_samples(ubi_adpcm_codec_data* data, uint32_t size); -ubi_adpcm_codec_data* init_ubi_adpcm(STREAMFILE* sf, off_t offset, int channels) { +ubi_adpcm_codec_data* init_ubi_adpcm(STREAMFILE* sf, uint32_t offset, uint32_t size, int channels) { ubi_adpcm_codec_data* data = NULL; data = calloc(1, sizeof(ubi_adpcm_codec_data)); if (!data) goto fail; - if (!parse_header(sf, data, offset)) { + if (!parse_header(sf, data, offset, size)) { VGM_LOG("UBI ADPCM: wrong header\n"); goto fail; } @@ -193,7 +194,7 @@ static void read_header_state(uint8_t* data, ubi_adpcm_header_data* header) { header->channels = get_u32le(data + 0x2c); } -static int parse_header(STREAMFILE* sf, ubi_adpcm_codec_data* data, off_t offset) { +static int parse_header(STREAMFILE* sf, ubi_adpcm_codec_data* data, uint32_t offset, uint32_t size) { uint8_t buf[0x30]; size_t bytes; @@ -214,6 +215,11 @@ static int parse_header(STREAMFILE* sf, ubi_adpcm_codec_data* data, off_t offset if (data->header.channels > UBI_CHANNELS_MAX || data->header.channels < UBI_CHANNELS_MIN) goto fail; + /* some kind of internal bug I guess, seen in a few subsongs in Rayman 3 PC demo */ + if (data->header.sample_count == 0x77E7A374 * data->header.channels) { + fix_samples(data, size); + } + return 1; fail: return 0; @@ -548,8 +554,8 @@ static void decode_frame(STREAMFILE* sf, ubi_adpcm_codec_data* data) { bytes = read_streamfile(data->frame, data->offset, frame_size, sf); if (bytes != frame_size) { - VGM_LOG("UBI ADPCM: wrong bytes read %x vs %x at %lx\n", bytes, frame_size, data->offset); - //goto fail; //? + VGM_LOG("UBI ADPCM: wrong bytes read %x vs %x at %x\n", bytes, frame_size, data->offset); + //goto fail; //may reach EOF earlier } if (channels == 1) { @@ -587,21 +593,37 @@ int32_t ubi_adpcm_get_samples(ubi_adpcm_codec_data* data) { return data->header.sample_count / data->header.channels; } -int32_t ubi_adpcm_bytes_to_samples(ubi_adpcm_codec_data* data, uint32_t size) { - uint32_t frame_size; +static void fix_samples(ubi_adpcm_codec_data* data, uint32_t size) { + uint32_t frame_size, setup_size, subframe_size, base_frames, last_size; + int subframes; + int32_t samples; - if (!data || !data->header.channels || !data->header.subframes_per_frame) - return 0; + if (!data || !data->header.channels || !data->header.subframes_per_frame || !size) + return; + + size -= 0x30; /* ignore header */ + + setup_size = 0x34 * data->header.channels; /* setup per channel */ + subframe_size = (data->header.codes_per_subframe * data->header.bits_per_sample /*+ 8*/) / 8 + 0x01; /* padding byte */ + frame_size = setup_size + subframe_size * data->header.subframes_per_frame; /* don't trust subframe count */ + base_frames = ((size - 0x01) / frame_size); /* force smaller size just in case so last frame isn't used */ + last_size = size - (base_frames * frame_size); + subframes = base_frames * data->header.subframes_per_frame; - size -= 0x30; /* header */ + samples = base_frames * (data->header.codes_per_subframe * data->header.subframes_per_frame); - frame_size = 0x34 * data->header.channels; /* setup per channel */ - frame_size += (data->header.codes_per_subframe * data->header.bits_per_sample /*+ 8*/) * data->header.subframes_per_frame / 8; - frame_size += data->header.subframes_per_frame * 0x01; /* padding byte */ + /* last subframe is shorter (and may contain padding after codes_per_subframe_last), and last frame may not contain all subframes */ + if (last_size > setup_size + subframe_size) { + samples += data->header.codes_per_subframe * (data->header.subframes_per_frame - 1); + subframes += (data->header.subframes_per_frame - 1); + } - return ((size - 0x01) / frame_size) * /* force smaller size so last frame isn't used */ - data->header.codes_per_subframe * data->header.subframes_per_frame + - data->header.codes_per_subframe_last * data->header.subframes_per_frame; + /* for some reason several files that need fixing seem to have garbage in the 2nd half of last codes */ + samples += data->header.codes_per_subframe_last / 2; + subframes += 1; + + data->header.sample_count = samples; /* for all channels */ + data->header.subframe_count = subframes; } diff --git a/Frameworks/vgmstream/vgmstream/src/decode.c b/Frameworks/vgmstream/vgmstream/src/decode.c index 1549e78ea..0e82f468d 100644 --- a/Frameworks/vgmstream/vgmstream/src/decode.c +++ b/Frameworks/vgmstream/vgmstream/src/decode.c @@ -428,7 +428,9 @@ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) { return 64; case coding_MS_IMA: case coding_REF_IMA: - return ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1; + return ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1;/* +1 from header sample */ + case coding_MS_IMA_mono: + return ((vgmstream->frame_size - 0x04) * 2) + 1; /* +1 from header sample */ case coding_RAD_IMA: return (vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels; case coding_NDS_IMA: @@ -628,12 +630,14 @@ int get_vgmstream_frame_size(VGMSTREAM* vgmstream) { case coding_OKI4S: case coding_MTF_IMA: return 0x01; - case coding_MS_IMA: case coding_RAD_IMA: case coding_NDS_IMA: case coding_DAT4_IMA: case coding_REF_IMA: return vgmstream->interleave_block_size; + case coding_MS_IMA: + case coding_MS_IMA_mono: + return vgmstream->frame_size; case coding_AWC_IMA: return 0x800; case coding_RAD_IMA_mono: @@ -931,6 +935,9 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_ } break; case coding_MS_IMA: + case coding_MS_IMA_mono: + //TODO: improve + vgmstream->codec_config = (vgmstream->coding_type == coding_MS_IMA_mono) || vgmstream->channels == 1; /* mono mode */ for (ch = 0; ch < vgmstream->channels; ch++) { decode_ms_ima(vgmstream,&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); diff --git a/Frameworks/vgmstream/vgmstream/src/formats.c b/Frameworks/vgmstream/vgmstream/src/formats.c index 823dc3931..d08c0749f 100644 --- a/Frameworks/vgmstream/vgmstream/src/formats.c +++ b/Frameworks/vgmstream/vgmstream/src/formats.c @@ -82,6 +82,7 @@ static const char* extension_list[] = { "atx", "aud", "audio", //txth/reserved [Grimm Echoes (Android)] + "audio_data", "aus", "awa", //txth/reserved [Missing Parts Side A (PS2)] "awb", @@ -172,6 +173,7 @@ static const char* extension_list[] = { "enm", "eno", "ens", + "esf", "exa", "ezw", @@ -431,6 +433,7 @@ static const char* extension_list[] = { "rxx", //txth/reserved [Full Auto (X360)] "s14", + "s3s", //txth/reserved [DT Racer (PS2)] "s3v", //Sound Voltex (AC) "sab", "sad", @@ -520,6 +523,7 @@ static const char* extension_list[] = { "swag", "swav", "swd", + "switch", //txth/reserved (.m4a-x.switch) [Ikinari Maou (Switch)] "switch_audio", "sx", "sxd", @@ -778,6 +782,7 @@ static const coding_info coding_info_list[] = { {coding_MTF_IMA, "MT Framework 4-bit IMA ADPCM"}, {coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"}, + {coding_MS_IMA_mono, "Microsoft 4-bit IMA ADPCM (mono/interleave)"}, {coding_XBOX_IMA, "XBOX 4-bit IMA ADPCM"}, {coding_XBOX_IMA_mch, "XBOX 4-bit IMA ADPCM (multichannel)"}, {coding_XBOX_IMA_int, "XBOX 4-bit IMA ADPCM (mono/interleave)"}, @@ -925,6 +930,7 @@ static const layout_info layout_info_list[] = { {layout_blocked_vs_square, "blocked (Square VS)"}, {layout_blocked_vid1, "blocked (VID1)"}, {layout_blocked_ubi_sce, "blocked (Ubi SCE)"}, + {layout_blocked_tt_ad, "blocked (TT AD)"}, }; static const meta_info meta_info_list[] = { @@ -1389,6 +1395,9 @@ static const meta_info meta_info_list[] = { {meta_MPEG, "MPEG header"}, {meta_SSPF, "Konami SSPF header"}, {meta_S3V, "Konami S3V header"}, + {meta_ESF, "Eurocom ESF header"}, + {meta_ADM3, "Crankcase ADM3 header"}, + {meta_TT_AD, "Traveller's Tales AUDIO_DATA header"}, }; void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) { diff --git a/Frameworks/vgmstream/vgmstream/src/info.c b/Frameworks/vgmstream/vgmstream/src/info.c index 6d711ed9e..d91121701 100644 --- a/Frameworks/vgmstream/vgmstream/src/info.c +++ b/Frameworks/vgmstream/vgmstream/src/info.c @@ -358,7 +358,13 @@ static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t* * segments use only a few samples from a full file (like Wwise transitions), bitrates * become a bit high since its hard to detect only part of the file is needed. */ - if (vgmstream->layout_type == layout_segmented) { + if (vgmstream->stream_size != 0) { + /* format may report full size for custom layouts that otherwise get odd values */ + bitrate += get_vgmstream_file_bitrate_from_size(vgmstream->stream_size, vgmstream->sample_rate, vgmstream->num_samples); + if (p_uniques) + (*p_uniques)++; + } + else if (vgmstream->layout_type == layout_segmented) { int uniques = 0; segmented_layout_data *data = (segmented_layout_data *) vgmstream->layout_data; for (i = 0; i < data->segment_count; i++) { @@ -400,20 +406,20 @@ static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t* } if (is_unique) { - size_t stream_size; - + size_t file_bitrate; + if (br->count >= br->count_max) goto fail; if (vgmstream->stream_size) { /* stream_size applies to both channels but should add once and detect repeats (for current subsong) */ - stream_size = get_vgmstream_file_bitrate_from_size(vgmstream->stream_size, vgmstream->sample_rate, vgmstream->num_samples); + file_bitrate = get_vgmstream_file_bitrate_from_size(vgmstream->stream_size, vgmstream->sample_rate, vgmstream->num_samples); } else { - stream_size = get_vgmstream_file_bitrate_from_streamfile(sf_cur, vgmstream->sample_rate, vgmstream->num_samples); + file_bitrate = get_vgmstream_file_bitrate_from_streamfile(sf_cur, vgmstream->sample_rate, vgmstream->num_samples); } /* possible in cases like using silence codec */ - if (!stream_size) + if (!file_bitrate) break; br->hash[br->count] = hash_cur; @@ -423,7 +429,7 @@ static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t* if (p_uniques) (*p_uniques)++; - bitrate += stream_size; + bitrate += file_bitrate; break; } diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked.c index ef574958b..dff0e4967 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked.c @@ -213,6 +213,9 @@ void block_update(off_t block_offset, VGMSTREAM* vgmstream) { case layout_blocked_ubi_sce: block_update_ubi_sce(block_offset,vgmstream); break; + case layout_blocked_tt_ad: + block_update_tt_ad(block_offset,vgmstream); + break; default: /* not a blocked layout */ break; } diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_tt_ad.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_tt_ad.c new file mode 100644 index 000000000..f5f1be8fd --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_tt_ad.c @@ -0,0 +1,31 @@ +#include "layout.h" + +/* Traveller's Tales blocks (.AUDIO_DATA) */ +void block_update_tt_ad(off_t block_offset, VGMSTREAM* vgmstream) { + STREAMFILE* sf = vgmstream->ch[0].streamfile; + uint32_t header_id, block_size, header_size; + int i; + + header_size = 0x00; + block_size = vgmstream->frame_size; + + //TODO could be optimized? + /* first chunk and last frame has an extra header: + * 0x00: id + * 0x04: 0 in FRST, left samples in LAST, others not seen (found in exe) */ + header_id = read_u32be(block_offset, sf); + if (header_id == get_id32be("FRST") || header_id == get_id32be("LAST") || + header_id == get_id32be("LSRT") || header_id == get_id32be("LEND")) { + header_size = 0x08; + } + VGM_ASSERT(header_id == get_id32be("LSRT") || header_id == get_id32be("LEND"), "TT-AD: loop found\n"); + + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = block_size /* * vgmstream->channels*/; + vgmstream->next_block_offset = block_offset + block_size * vgmstream->channels + header_size; + + /* MS-IMA = same offset per channel */ + for (i = 0; i < vgmstream->channels; i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset + header_size + block_size * i; + } +} diff --git a/Frameworks/vgmstream/vgmstream/src/layout/layout.h b/Frameworks/vgmstream/vgmstream/src/layout/layout.h index 79dc63b55..7accda7e4 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/layout.h +++ b/Frameworks/vgmstream/vgmstream/src/layout/layout.h @@ -49,6 +49,7 @@ void block_update_xa_aiff(off_t block_offset, VGMSTREAM* vgmstream); void block_update_vs_square(off_t block_offset, VGMSTREAM* vgmstream); void block_update_vid1(off_t block_offset, VGMSTREAM* vgmstream); void block_update_ubi_sce(off_t block_offset, VGMSTREAM* vgmstream); +void block_update_tt_ad(off_t block_offset, VGMSTREAM* vgmstream); /* other layouts */ void render_vgmstream_interleave(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/aax.c b/Frameworks/vgmstream/vgmstream/src/meta/aax.c index b80410099..3e509faae 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/aax.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/aax.c @@ -1,31 +1,32 @@ #include "meta.h" #include "../layout/layout.h" #include "../coding/coding.h" -#include "cri_utf.h" +#include "../util/cri_utf.h" #define MAX_SEGMENTS 2 /* usually segment0=intro, segment1=loop/main */ /* AAX - segmented ADX [Bayonetta (PS3), Pandora's Tower (Wii), Catherine (X360), Binary Domain (PS3)] */ -VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - int loop_flag = 0, channel_count = 0; +VGMSTREAM* init_vgmstream_aax(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + int loop_flag = 0, channels = 0; int32_t sample_count, loop_start_sample = 0, loop_end_sample = 0; - segmented_layout_data *data = NULL; + segmented_layout_data* data = NULL; int segment_count, loop_segment = 0, is_hca; off_t segment_offset[MAX_SEGMENTS]; size_t segment_size[MAX_SEGMENTS]; int i; - utf_context *utf = NULL; + utf_context* utf = NULL; /* checks */ + if (!is_id32be(0x00,sf, "@UTF")) + goto fail; + /* .aax: often with extension (with either HCA or AAX tables) * (extensionless): sometimes without [PES 2013 (PC)] */ - if (!check_extensions(streamFile, "aax,")) - goto fail; - if (read_32bitBE(0x00,streamFile) != 0x40555446) /* "@UTF" */ + if (!check_extensions(sf, "aax,")) goto fail; /* .aax contains a simple UTF table, each row being a segment pointing to a CRI audio format */ @@ -35,7 +36,7 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) { uint32_t table_offset = 0x00; - utf = utf_open(streamFile, table_offset, &rows, &name); + utf = utf_open(sf, table_offset, &rows, &name); if (!utf) goto fail; if (strcmp(name, "AAX") == 0) @@ -74,7 +75,7 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) { /* open each segment subfile */ for (i = 0; i < segment_count; i++) { - STREAMFILE* temp_sf = setup_subfile_streamfile(streamFile, segment_offset[i],segment_size[i], (is_hca ? "hca" : "adx")); + STREAMFILE* temp_sf = setup_subfile_streamfile(sf, segment_offset[i],segment_size[i], (is_hca ? "hca" : "adx")); if (!temp_sf) goto fail; data->segments[i] = is_hca ? @@ -105,11 +106,11 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) { } } - channel_count = data->output_channels; + channels = data->output_channels; /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + vgmstream = allocate_vgmstream(channels,loop_flag); if (!vgmstream) goto fail; vgmstream->sample_rate = data->segments[0]->sample_rate; @@ -135,21 +136,22 @@ fail: /* CRI's UTF wrapper around DSP [Sonic Colors sfx (Wii), NiGHTS: Journey of Dreams sfx (Wii)] */ -VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; +VGMSTREAM* init_vgmstream_utf_dsp(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; off_t start_offset; - uint8_t loop_flag = 0, channel_count; + uint8_t loop_flag = 0, channels; uint32_t sample_rate, num_samples, loop_start, loop_end, interleave; uint32_t data_offset, data_size, header_offset, header_size; - utf_context *utf = NULL; + utf_context* utf = NULL; /* checks */ + if (!is_id32be(0x00,sf, "@UTF")) + goto fail; + /* .aax: assumed * (extensionless): extracted names inside csb/cpk often don't have extensions */ - if (!check_extensions(streamFile, "aax,")) - goto fail; - if (read_32bitBE(0x00,streamFile) != 0x40555446) /* "@UTF" */ + if (!check_extensions(sf, "aax,")) goto fail; /* .aax contains a simple UTF table with one row and various columns being header info */ @@ -159,7 +161,7 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { uint32_t table_offset = 0x00; - utf = utf_open(streamFile, table_offset, &rows, &name); + utf = utf_open(sf, table_offset, &rows, &name); if (!utf) goto fail; if (strcmp(name, "ADPCM_WII") != 0) @@ -172,7 +174,7 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { goto fail; if (!utf_query_u32(utf, 0, "nsmpl", &num_samples)) goto fail; - if (!utf_query_u8(utf, 0, "nch", &channel_count)) + if (!utf_query_u8(utf, 0, "nch", &channels)) goto fail; if (!utf_query_u8(utf, 0, "lpflg", &loop_flag)) /* full loops */ goto fail; @@ -182,21 +184,21 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { if (!utf_query_data(utf, 0, "header", &header_offset, &header_size)) goto fail; - if (channel_count < 1 || channel_count > 2) + if (channels < 1 || channels > 2) goto fail; - if (header_size != channel_count * 0x60) + if (header_size != channels * 0x60) goto fail; start_offset = data_offset; - interleave = (data_size+7) / 8 * 8 / channel_count; + interleave = (data_size+7) / 8 * 8 / channels; - loop_start = read_32bitBE(header_offset + 0x10, streamFile); - loop_end = read_32bitBE(header_offset + 0x14, streamFile); + loop_start = read_32bitBE(header_offset + 0x10, sf); + loop_end = read_32bitBE(header_offset + 0x14, sf); } /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count, loop_flag); + vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; vgmstream->sample_rate = sample_rate; @@ -209,9 +211,9 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { vgmstream->interleave_block_size = interleave; vgmstream->meta_type = meta_UTF_DSP; - dsp_read_coefs_be(vgmstream, streamFile, header_offset+0x1c, 0x60); + dsp_read_coefs_be(vgmstream, sf, header_offset+0x1c, 0x60); - if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) goto fail; return vgmstream; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/acb.c b/Frameworks/vgmstream/vgmstream/src/meta/acb.c index e51cc67a2..84a4a1152 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/acb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/acb.c @@ -1,6 +1,6 @@ #include "meta.h" #include "../coding/coding.h" -#include "cri_utf.h" +#include "../util/cri_utf.h" /* ACB (Atom Cue sheet Binary) - CRI container of memory audio, often together with a .awb wave bank */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/adm3.c b/Frameworks/vgmstream/vgmstream/src/meta/adm3.c new file mode 100644 index 000000000..f38ed06ba --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/adm3.c @@ -0,0 +1,152 @@ +#include "meta.h" +#include "../coding/coding.h" + + +typedef struct { + int total_subsongs; + int target_subsong; + + uint32_t stream_offset; + uint32_t stream_size; + + int loop_flag; + int sample_rate; + int channels; + int32_t num_samples; +} adm3_header_t; + +static int parse_adm3(adm3_header_t* adm3, STREAMFILE* sf); + + +/* ADM3 - Crankcase Audio REV plugin file [Cyberpunk 2077 (PC), MotoGP 21 (PC)] */ +VGMSTREAM* init_vgmstream_adm3(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + adm3_header_t adm3 = {0}; + + + /* checks */ + if (!is_id32be(0x00,sf, "ADM3")) + goto fail; + if (!check_extensions(sf, "wem")) + goto fail; + + adm3.target_subsong = sf->stream_index; + if (adm3.target_subsong == 0) adm3.target_subsong = 1; + + /* ADM3 are files used with the Wwise Crankaudio plugin, that simulate engine noises with + * base internal samples and some internal RPM config (probably). Actual file seems to + * define some combo of samples, this only plays those separate samples. + * Decoder is basically Apple's IMA (internally just "ADPCMDecoder") but transforms to float + * each sample during decode by multiplying by 0.000030518509 */ + + if (!parse_adm3(&adm3, sf)) + goto fail; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(adm3.channels, adm3.loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_ADM3; + vgmstream->sample_rate = adm3.sample_rate; + vgmstream->num_samples = adm3.num_samples; /* slightly lower than bytes-to-samples */ + vgmstream->num_streams = adm3.total_subsongs; + vgmstream->stream_size = adm3.stream_size; + + vgmstream->coding_type = coding_APPLE_IMA4; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x22; + + if (!vgmstream_open_stream(vgmstream, sf, adm3.stream_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + + +static int parse_type(adm3_header_t* adm3, STREAMFILE* sf, uint32_t offset) { + + if (is_id32be(offset, sf, "RMP1")) { + offset = read_u32le(offset + 0x1c, sf); + if (!parse_type(adm3, sf, offset)) + goto fail; + /* 0x24: offset to GRN1 */ + } + else if (is_id32be(offset, sf, "SMB1")) { + uint32_t table_count = read_u32le(offset + 0x10, sf); + uint32_t table_offset = read_u32le(offset + 0x18, sf); + int i; + + for (i = 0; i < table_count; i++) { + uint32_t smp2_unk = read_u32le(table_offset + i * 0x08 + 0x00, sf); + uint32_t smp2_offset = read_u32le(table_offset + i * 0x08 + 0x04, sf); + + if (smp2_unk != 1) + goto fail; + + if (!parse_type(adm3, sf, smp2_offset)) /* SMP2 */ + goto fail; + } + } + else if (is_id32be(offset, sf, "SMP2")) { + adm3->total_subsongs++; + + if (adm3->target_subsong == adm3->total_subsongs) { + /* 0x04 always 0 */ + /* 0x08 always 0x00040000 */ + adm3->channels = read_u32le(offset + 0x0c, sf); + /* 0x10 float pitch? */ + /* 0x14 int pitch? */ + /* 0x18 0x0001? */ + /* 0x1a 0x0030? (header size?) */ + adm3->sample_rate = read_s32le(offset + 0x1c, sf); + adm3->num_samples = read_s32le(offset + 0x20, sf); + adm3->stream_size = read_u32le(offset + 0x24, sf); + /* 0x28 1? */ + adm3->stream_offset = read_u32le(offset + 0x2c, sf); + } + } + else { + VGM_LOG("ADM3: unknown at %x\n", offset); + goto fail; + } + + return 1; +fail: + return 0; +} + +static int parse_adm3(adm3_header_t* adm3, STREAMFILE* sf) { + uint32_t offset; + + /* 0x04: null */ + /* 0x08: version? */ + /* 0x0c: header size */ + /* 0x10: data start */ + /* rest unknown, looks mostly the same between files */ + + /* higher ramp, N samples from low to high */ + offset = read_u32le(0x0FC, sf); + if (!parse_type(adm3, sf, offset)) goto fail; /* RMP1 */ + if (read_u32le(0x100, sf) != 1) goto fail; + + /* lower ramp, also N samples */ + offset = read_u32le(0x104, sf); + if (!parse_type(adm3, sf, offset)) goto fail; /* RMP1 */ + if (read_u32le(0x108, sf) != 1) goto fail; + + /* idle engine */ + offset = read_u32le(0x10c, sf); + if (!parse_type(adm3, sf, offset)) goto fail; /* SMP2 */ + if (read_u32le(0x110, sf) != 1) goto fail; + + if (adm3->target_subsong < 0 || adm3->target_subsong > adm3->total_subsongs || adm3->total_subsongs < 1) + goto fail; + + return 1; +fail: + return 0; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/cpk.c b/Frameworks/vgmstream/vgmstream/src/meta/cpk.c index f42f2b731..1dd2ffafc 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/cpk.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/cpk.c @@ -1,6 +1,6 @@ #include "meta.h" #include "../coding/coding.h" -#include "cri_utf.h" +#include "../util/cri_utf.h" typedef enum { HCA, CWAV, ADX } cpk_type_t; @@ -26,10 +26,11 @@ VGMSTREAM* init_vgmstream_cpk_memory(STREAMFILE* sf, STREAMFILE* sf_acb) { /* checks */ - if (!check_extensions(sf, "awb")) - goto fail; if (!is_id32be(0x00,sf, "CPK ")) goto fail; + if (!check_extensions(sf, "awb")) + goto fail; + if (!is_id32be(0x10,sf, "@UTF")) goto fail; /* 04: 0xFF? */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/csb.c b/Frameworks/vgmstream/vgmstream/src/meta/csb.c index 68be6d72e..832117502 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/csb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/csb.c @@ -1,6 +1,6 @@ #include "meta.h" #include "../coding/coding.h" -#include "cri_utf.h" +#include "../util/cri_utf.h" /* CSB (Cue Sheet Binary?) - CRI container of memory audio, often together with a .cpk wave bank */ @@ -9,8 +9,8 @@ VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) { STREAMFILE* temp_sf = NULL; off_t subfile_offset; size_t subfile_size; - utf_context *utf = NULL; - utf_context *utf_sdl = NULL; + utf_context* utf = NULL; + utf_context* utf_sdl = NULL; int total_subsongs, target_subsong = sf->stream_index; uint8_t fmt = 0; const char* stream_name = NULL; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/esf.c b/Frameworks/vgmstream/vgmstream/src/meta/esf.c new file mode 100644 index 000000000..66a54a6fe --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/esf.c @@ -0,0 +1,46 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* .ESF - from Mortal Kombat 4 (PC) */ +VGMSTREAM* init_vgmstream_esf(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint32_t pcm_size; + off_t start_offset; + int loop_flag, bps_flag, hq_flag, channels, bps; + + /* checks */ + if (!is_id32be(0x00, sf, "ESF\x06")) + goto fail; + + if (!check_extensions(sf, "esf")) + goto fail; + + pcm_size = read_u32le(0x04, sf); + bps_flag = pcm_size & 0x20000000; + hq_flag = pcm_size & 0x40000000; + loop_flag = pcm_size & 0x80000000; + pcm_size &= 0x1FFFFFFF; + + channels = 1; /* mono only */ + start_offset = 0x08; + bps = bps_flag ? 16 : 8; /* 16 is supposed to mean PCM16 but is actually IMA */ + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_ESF; + vgmstream->sample_rate = hq_flag ? 22050 : 11025; + vgmstream->coding_type = (bps == 8) ? coding_PCM8_U : coding_DVI_IMA; + vgmstream->num_samples = pcm_bytes_to_samples(pcm_size, 1, bps); + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = vgmstream->num_samples; + + 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 034751d27..4aff0a009 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -982,4 +982,10 @@ VGMSTREAM* init_vgmstream_sspf(STREAMFILE* sf); VGMSTREAM* init_vgmstream_s3v(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_esf(STREAMFILE* sf); + +VGMSTREAM* init_vgmstream_adm3(STREAMFILE* sf); + +VGMSTREAM* init_vgmstream_tt_ad(STREAMFILE* sf); + #endif /*_META_H*/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mpeg.c b/Frameworks/vgmstream/vgmstream/src/meta/mpeg.c index cbe454b98..b3fad20ab 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/mpeg.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/mpeg.c @@ -2,16 +2,33 @@ #include "../coding/coding.h" -/* MPEG - standard MP1/2/3 audio MP3 */ +/* MPEG - standard MP1/2/3 audio */ VGMSTREAM* init_vgmstream_mpeg(STREAMFILE* sf) { #ifdef VGM_USE_MPEG VGMSTREAM* vgmstream = NULL; + uint32_t start_offset; int loop_flag = 0; mpeg_frame_info info = {0}; + uint32_t header_id; /* checks */ - if (!mpeg_get_frame_info(sf, 0x00, &info)) + header_id = read_u32be(0x00, sf); + if ((header_id & 0xFFF00000) != 0xFFF00000 && + (header_id & 0xFFFFFF00) != get_id32be("ID3\0") && + (header_id & 0xFFFFFF00) != get_id32be("TAG\0")) + goto fail; + + //TODO: may try init_mpeg as-is, already skips tags + start_offset = 0x00; + while (start_offset < get_streamfile_size(sf)) { + uint32_t tag_size = mpeg_get_tag_size(sf, start_offset, 0); + if (tag_size == 0) + break; + start_offset += tag_size; + } + + if (!mpeg_get_frame_info(sf, start_offset, &info)) goto fail; /* .mp3/mp2: standard (is .mp1 ever used in games?) diff --git a/Frameworks/vgmstream/vgmstream/src/meta/p3d.c b/Frameworks/vgmstream/vgmstream/src/meta/p3d.c index 2e3895f95..0a7bb263d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/p3d.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/p3d.c @@ -1,15 +1,17 @@ #include "meta.h" #include "../coding/coding.h" +#include "../util/endianness.h" + /* P3D - from Radical's Prototype 1/2 (PC/PS3/X360), Spider-Man 4 Beta (X360) */ VGMSTREAM* init_vgmstream_p3d(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; - off_t start_offset, offset, name_offset = 0; + uint32_t start_offset, offset, name_offset = 0; size_t header_size, file_size, data_size; uint32_t xma2_offset = 0, xma2_size = 0; int loop_flag, channels, sample_rate, codec; - int i, name_count, text_len, block_size = 0, num_samples; - uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL; + int i, name_count, unk_count, text_len, block_size = 0, num_samples; + read_u32_t read_u32; /* checks */ @@ -19,30 +21,36 @@ VGMSTREAM* init_vgmstream_p3d(STREAMFILE* sf) { if (!check_extensions(sf,"p3d")) goto fail; - read_u32 = guess_endianness32bit(0x04,sf) ? read_u32be : read_u32le; + read_u32 = guess_endian32(0x04,sf) ? read_u32be : read_u32le; file_size = get_streamfile_size(sf); /* base header */ header_size = read_u32(0x04,sf); - if (header_size != 0x0C) goto fail; + if (header_size != 0x0c) goto fail; if (read_u32(0x08,sf) != file_size) goto fail; - if (read_u32(0x0C,sf) != 0xFE000000) goto fail; /* fixed */ - if (read_u32(0x10,sf) + header_size != file_size) goto fail; - if (read_u32(0x14,sf) + header_size != file_size) goto fail; /* body size again */ - if (read_u32(0x18,sf) != 0x0000000A) goto fail; /* fixed */ + offset = 0x0c; - /* header text */ - offset = 0x1C; - text_len = read_u32(offset,sf); + /* P3D is just a generic container used in Radical's games, so we only want "AudioFile". + * Rarely some voice files start with a "AudioDialogueSubtitle" section, so skip that first */ + if (is_id64be(offset+0x14,sf, "AudioDia")) { + offset += read_u32(offset + 0x04,sf); /* section size */ + } + + /* AudioFile section */ + if (read_u32(offset + 0x00,sf) != 0xFE000000) goto fail; /* section marker */ + if (read_u32(offset + 0x04,sf) + offset != file_size) goto fail; /* AudioFile size */ + if (read_u32(offset + 0x08,sf) + offset != file_size) goto fail; /* again */ + if (read_u32(offset + 0x0c,sf) != 0x0000000A) goto fail; /* fixed */ + + text_len = read_u32(offset + 0x10,sf); if (text_len != 9) goto fail; - offset += 0x04; + offset += 0x14; - /* check the type as P3D is just a generic container used in Radical's games */ if (!is_id64be(offset+0x00,sf, "AudioFil") || read_u16be(offset+0x08,sf) != 0x6500) /* "AudioFile\0" */ goto fail; offset += text_len + 0x01; - /* file names: always 2 (repeated); but if it's 3 there is an extra string later */ + /* file names: 1 internal stream name + 1 external filename (usually repeated) + 1 an extra string later (P2) */ name_count = read_u32(offset,sf); if (name_count != 2 && name_count != 3) goto fail; /* 2: Prototype1, 3: Prototype2 */ offset += 0x04; @@ -55,8 +63,9 @@ VGMSTREAM* init_vgmstream_p3d(STREAMFILE* sf) { offset += 0x04 + text_len; } - /* info count? */ - if (0x01 != read_u32(offset,sf)) goto fail; + /* 1=music, 0=dialogues */ + unk_count = read_u32(offset,sf); + if (unk_count != 0x00 && unk_count != 0x01) goto fail; offset += 0x04; /* next string can be used as a codec id */ @@ -64,8 +73,8 @@ VGMSTREAM* init_vgmstream_p3d(STREAMFILE* sf) { codec = read_u32be(offset+0x04,sf); offset += 0x04 + text_len + 0x01; - /* extra "Music" string in Prototype 2 */ - if (name_count == 3) { + /* extra "Music" or "Dialogue" string in Prototype 2 */ + if (name_count >= 3) { text_len = read_u32(offset,sf) + 1; /* null-terminated */ offset += 0x04 + text_len; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/riff.c b/Frameworks/vgmstream/vgmstream/src/meta/riff.c index 2220adaf4..bd2999344 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/riff.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/riff.c @@ -654,8 +654,8 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) { read_u32be(start_offset+0x3c, sf) == 0xFFFFFFFF) goto fail; - ///* MSADPCM .ckd are parsed elsewhere, though they are valid so no big deal if parsed here (just that loops should be ignored) */ - if (!fmt.is_at9 && check_extensions(sf, "ckd")) + /* MSADPCM .ckd are parsed elsewhere, though they are valid so no big deal if parsed here (just that loops should be ignored) */ + if (fmt.codec == 0x0002 && check_extensions(sf, "ckd")) goto fail; /* ignore Gitaroo Man Live! (PSP) multi-RIFF (to allow chunked TXTH) */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sspf.c b/Frameworks/vgmstream/vgmstream/src/meta/sspf.c index 2929fa4ee..da9f1cf6e 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sspf.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sspf.c @@ -21,7 +21,7 @@ VGMSTREAM* init_vgmstream_sspf(STREAMFILE* sf) { goto fail; /* extra check to ignore .spc, that are a RAM pack of .ssp with a ~0x800 table at the end */ - file_size = read_u32be(0x08, sf) + 0x08; /* without padding */ + file_size = read_u32be(0x08, sf); /* without padding */ pad_size = 0; if (file_size % 0x800) /* add padding */ pad_size = 0x800 - (file_size % 0x800); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/tgc.c b/Frameworks/vgmstream/vgmstream/src/meta/tgc.c index a865309ec..806f8e65e 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/tgc.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/tgc.c @@ -2,24 +2,36 @@ #include "../coding/coding.h" /* Tiger Game.com ADPCM file */ -VGMSTREAM * init_vgmstream_tgc(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; +VGMSTREAM* init_vgmstream_tgc(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint16_t size; + off_t start_offset; + /* checks */ - if (!check_extensions(streamFile, "4")) + if (read_u8(0x00, sf) != 0) goto fail; + if (!check_extensions(sf, "4")) + goto fail; + + size = read_u16be(0x01, sf); + if (size != get_streamfile_size(sf)) + goto fail; + start_offset = 0x03; + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(1, 0); if (!vgmstream) goto fail; vgmstream->sample_rate = 8000; - vgmstream->num_samples = ((uint16_t)read_16bitBE(1, streamFile) - 3) * 2; + vgmstream->num_samples = (size - 0x03) * 2; vgmstream->meta_type = meta_TGC; vgmstream->layout_type = layout_none; vgmstream->coding_type = coding_TGC; - if (!vgmstream_open_stream(vgmstream, streamFile, 3)) + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) goto fail; return vgmstream; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/tt_ad.c b/Frameworks/vgmstream/vgmstream/src/meta/tt_ad.c new file mode 100644 index 000000000..5bfffa506 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/tt_ad.c @@ -0,0 +1,94 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* .AUDIO_DATA - Traveller's Tales "NTT" engine audio format [Lego Star Wars: The Skywalker Saga (PC/Switch)] */ +VGMSTREAM* init_vgmstream_tt_ad(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint32_t offset, stream_offset, stream_size; + int loop_flag, channels, sample_rate, codec, frame_size = 0; + int32_t num_samples; + + + /* checks */ + if (!is_id32be(0x00,sf, "FMT ")) + goto fail; + + /* actual extension */ + if (!check_extensions(sf, "audio_data")) + goto fail; + + offset = 0x08; + /* 0x00: null */ + codec = read_u16le(offset + 0x02,sf); + sample_rate = read_s32le(offset + 0x04,sf); + num_samples = read_s32le(offset + 0x08,sf); + channels = read_u8(offset + 0x0c,sf); + /* 0x0d: bps (16=IMA, 32=Ogg) */ + /* 0x10: + Ogg = some size? + IMA = frame size + flag? */ + if (codec == 0x0a) + frame_size = read_u16le(offset + 0x10,sf); + + + loop_flag = 0; /* music just repeats? */ + + offset += read_u32le(0x04, sf); + + /* Ogg seek table*/ + if (is_id32be(offset, sf, "SEEK")) { + offset += 0x08 + read_u32le(offset + 0x04, sf); + } + + /* found with some IMA */ + if (is_id32be(offset, sf, "RMS ")) { + offset += 0x08 + read_u32le(offset + 0x04, sf); + } + + if (!is_id32be(offset, sf, "DATA")) + goto fail; + + stream_offset = offset + 0x08; + stream_size = read_u32le(offset + 0x04, sf); + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_TT_AD; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = num_samples; + + switch(codec) { +#ifdef VGM_USE_VORBIS + case 0x01: { + vgmstream->codec_data = init_ogg_vorbis(sf, stream_offset, stream_size, NULL); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_OGG_VORBIS; + vgmstream->layout_type = layout_none; + + break; + } +#endif + + case 0x0a: + vgmstream->coding_type = coding_MS_IMA_mono; + vgmstream->layout_type = layout_blocked_tt_ad; + vgmstream->frame_size = frame_size; + vgmstream->interleave_block_size = frame_size; + break; + + default: + vgm_logi("FMT: unsupported codec 0x%x\n", codec); + goto fail; + } + + if (!vgmstream_open_stream(vgmstream, sf, stream_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/txth.c b/Frameworks/vgmstream/vgmstream/src/meta/txth.c index e23548413..da3efc697 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/txth.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/txth.c @@ -46,6 +46,7 @@ typedef enum { XA, XA_EA, CP_YM, + PCM_FLOAT_LE, UNKNOWN = 99, } txth_codec_t; @@ -213,13 +214,14 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) { if (txth.interleave == 0) { uint32_t interleave = 0; switch(txth.codec) { - case PSX: interleave = 0x10; break; - case PSX_bf: interleave = 0x10; break; - case NGC_DSP: interleave = 0x08; break; - case PCM16LE: interleave = 0x02; break; - case PCM16BE: interleave = 0x02; break; - case PCM8: interleave = 0x01; break; - case PCM8_U: interleave = 0x01; break; + case PSX: interleave = 0x10; break; + case PSX_bf: interleave = 0x10; break; + case NGC_DSP: interleave = 0x08; break; + case PCM16LE: interleave = 0x02; break; + case PCM16BE: interleave = 0x02; break; + case PCM8: interleave = 0x01; break; + case PCM8_U: interleave = 0x01; break; + case PCM_FLOAT_LE: interleave = 0x04; break; default: break; } @@ -229,26 +231,27 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) { /* type to coding conversion */ switch (txth.codec) { - case PSX: coding = coding_PSX; break; - case XBOX: coding = coding_XBOX_IMA; break; - case NGC_DTK: coding = coding_NGC_DTK; break; - case PCM16BE: coding = coding_PCM16BE; break; - case PCM16LE: coding = coding_PCM16LE; break; - case PCM8: coding = coding_PCM8; break; - case SDX2: coding = coding_SDX2; break; - case DVI_IMA: coding = coding_DVI_IMA; break; + case PSX: coding = coding_PSX; break; + case XBOX: coding = coding_XBOX_IMA; break; + case NGC_DTK: coding = coding_NGC_DTK; break; + case PCM16BE: coding = coding_PCM16BE; break; + case PCM16LE: coding = coding_PCM16LE; break; + case PCM8: coding = coding_PCM8; break; + case PCM_FLOAT_LE: coding = coding_PCMFLOAT; break; + case SDX2: coding = coding_SDX2; break; + case DVI_IMA: coding = coding_DVI_IMA; break; #ifdef VGM_USE_MPEG - case MPEG: coding = coding_MPEG_layer3; break; /* we later find out exactly which */ + case MPEG: coding = coding_MPEG_layer3; break; /* we later find out exactly which */ #endif - case IMA: coding = coding_IMA; break; - case AICA: coding = coding_AICA; break; - case MSADPCM: coding = coding_MSADPCM; break; - case NGC_DSP: coding = coding_NGC_DSP; break; - case PCM8_U_int: coding = coding_PCM8_U_int; break; - case PSX_bf: coding = coding_PSX_badflags; break; - case MS_IMA: coding = coding_MS_IMA; break; - case PCM8_U: coding = coding_PCM8_U; break; - case APPLE_IMA4: coding = coding_APPLE_IMA4; break; + case IMA: coding = coding_IMA; break; + case AICA: coding = coding_AICA; break; + case MSADPCM: coding = coding_MSADPCM; break; + case NGC_DSP: coding = coding_NGC_DSP; break; + case PCM8_U_int: coding = coding_PCM8_U_int; break; + case PSX_bf: coding = coding_PSX_badflags; break; + case MS_IMA: coding = coding_MS_IMA; break; + case PCM8_U: coding = coding_PCM8_U; break; + case APPLE_IMA4: coding = coding_APPLE_IMA4; break; #ifdef VGM_USE_FFMPEG case ATRAC3: case ATRAC3PLUS: @@ -256,19 +259,19 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) { case XMA2: case AC3: case AAC: - case FFMPEG: coding = coding_FFmpeg; break; + case FFMPEG: coding = coding_FFmpeg; break; #endif - case PCFX: coding = coding_PCFX; break; - case PCM4: coding = coding_PCM4; break; - case PCM4_U: coding = coding_PCM4_U; break; - case OKI16: coding = coding_OKI16; break; - case OKI4S: coding = coding_OKI4S; break; - case TGC: coding = coding_TGC; break; - case ASF: coding = coding_ASF; break; - case EAXA: coding = coding_EA_XA; break; - case XA: coding = coding_XA; break; - case XA_EA: coding = coding_XA_EA; break; - case CP_YM: coding = coding_CP_YM; break; + case PCFX: coding = coding_PCFX; break; + case PCM4: coding = coding_PCM4; break; + case PCM4_U: coding = coding_PCM4_U; break; + case OKI16: coding = coding_OKI16; break; + case OKI4S: coding = coding_OKI4S; break; + case TGC: coding = coding_TGC; break; + case ASF: coding = coding_ASF; break; + case EAXA: coding = coding_EA_XA; break; + case XA: coding = coding_XA; break; + case XA_EA: coding = coding_XA_EA; break; + case CP_YM: coding = coding_CP_YM; break; default: goto fail; } @@ -305,6 +308,7 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) { case coding_PCM16BE: case coding_PCM8: case coding_PCM8_U: + case coding_PCMFLOAT: case coding_PCM4: case coding_PCM4_U: case coding_SDX2: @@ -963,6 +967,7 @@ static txth_codec_t parse_codec(txth_header* txth, const char* val) { else if (is_string(val,"XA")) return XA; else if (is_string(val,"XA_EA")) return XA_EA; else if (is_string(val,"CP_YM")) return CP_YM; + else if (is_string(val,"PCM_FLOAT_LE")) return PCM_FLOAT_LE; /* special handling */ else if (is_string(val,"name_value")) return txth->name_values[0]; else if (is_string(val,"name_value1")) return txth->name_values[0]; @@ -2039,6 +2044,8 @@ static int get_bytes_to_samples(txth_header* txth, uint32_t bytes) { case PCM8_U_int: case PCM8_U: return pcm_bytes_to_samples(bytes, txth->channels, 8); + case PCM_FLOAT_LE: + return pcm_bytes_to_samples(bytes, txth->channels, 32); case PCM4: case PCM4_U: case TGC: diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c index 3b80d4b8b..6dc4c5a14 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c @@ -705,18 +705,13 @@ static VGMSTREAM* init_vgmstream_ubi_hx_header(ubi_hx_header* hx, STREAMFILE* sf break; case UBI: - vgmstream->codec_data = init_ubi_adpcm(sb, hx->stream_offset, vgmstream->channels); + vgmstream->codec_data = init_ubi_adpcm(sb, hx->stream_offset, hx->stream_size, vgmstream->channels); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_UBI_ADPCM; vgmstream->layout_type = layout_none; vgmstream->num_samples = ubi_adpcm_get_samples(vgmstream->codec_data); - /* some kind of internal bug I guess, seen in a few subsongs in Rayman 3 PC demo, other values are also buggy */ - if (vgmstream->num_samples == 0x77E7A374) { - vgmstream->num_samples = ubi_adpcm_bytes_to_samples(vgmstream->codec_data, hx->stream_size); - } - /* XIII has 6-bit stereo music, Rayman 3 4-bit music, both use 6-bit mono) */ break; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c index b97827715..10bbdf39c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c @@ -1018,7 +1018,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_base(ubi_sb_header* sb, STREAMFILE* sf_h sb->stream_size -= 0x08; } - vgmstream->codec_data = init_ubi_adpcm(sf_data, start_offset, vgmstream->channels); + vgmstream->codec_data = init_ubi_adpcm(sf_data, start_offset, 0, vgmstream->channels); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_UBI_ADPCM; vgmstream->layout_type = layout_none; diff --git a/Frameworks/vgmstream/vgmstream/src/render.c b/Frameworks/vgmstream/vgmstream/src/render.c index 5e5243a21..6233ec844 100644 --- a/Frameworks/vgmstream/vgmstream/src/render.c +++ b/Frameworks/vgmstream/vgmstream/src/render.c @@ -304,6 +304,7 @@ int render_layout(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstream) { case layout_blocked_vs_square: case layout_blocked_vid1: case layout_blocked_ubi_sce: + case layout_blocked_tt_ad: render_vgmstream_blocked(buf, sample_count, vgmstream); break; case layout_segmented: diff --git a/Frameworks/vgmstream/vgmstream/src/meta/cri_utf.c b/Frameworks/vgmstream/vgmstream/src/util/cri_utf.c similarity index 99% rename from Frameworks/vgmstream/vgmstream/src/meta/cri_utf.c rename to Frameworks/vgmstream/vgmstream/src/util/cri_utf.c index a2919bec6..e3174ca00 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/cri_utf.c +++ b/Frameworks/vgmstream/vgmstream/src/util/cri_utf.c @@ -1,5 +1,5 @@ #include "cri_utf.h" -#include "../util/log.h" +#include "log.h" #define UTF_MAX_SCHEMA_SIZE 0x8000 /* arbitrary max */ #define COLUMN_BITMASK_FLAG 0xf0 diff --git a/Frameworks/vgmstream/vgmstream/src/meta/cri_utf.h b/Frameworks/vgmstream/vgmstream/src/util/cri_utf.h similarity index 100% rename from Frameworks/vgmstream/vgmstream/src/meta/cri_utf.h rename to Frameworks/vgmstream/vgmstream/src/util/cri_utf.h diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c index bad69dc55..012adc5de 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c @@ -470,7 +470,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_csb, init_vgmstream_fwse, init_vgmstream_fda, - init_vgmstream_tgc, init_vgmstream_kwb, init_vgmstream_lrmd, init_vgmstream_bkhd, @@ -522,6 +521,9 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_sspf, init_vgmstream_opus_rsnd, init_vgmstream_s3v, + init_vgmstream_esf, + init_vgmstream_adm3, + init_vgmstream_tt_ad, /* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */ init_vgmstream_mpeg, @@ -535,6 +537,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_seb, init_vgmstream_ps2_pnb, init_vgmstream_sli_ogg, + init_vgmstream_tgc, /* 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 */ @@ -1159,9 +1162,10 @@ int vgmstream_open_stream_bf(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t start_o goto fail; } - if ((vgmstream->coding_type == coding_MSADPCM || - vgmstream->coding_type == coding_MSADPCM_ck || - vgmstream->coding_type == coding_MSADPCM_int) && + if ((vgmstream->coding_type == coding_MSADPCM || vgmstream->coding_type == coding_MSADPCM_ck || + vgmstream->coding_type == coding_MSADPCM_int || + vgmstream->coding_type == coding_MS_IMA || vgmstream->coding_type == coding_MS_IMA_mono + ) && vgmstream->frame_size == 0) { vgmstream->frame_size = vgmstream->interleave_block_size; } diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.h b/Frameworks/vgmstream/vgmstream/src/vgmstream.h index 9cff9a3a3..585407108 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.h @@ -123,6 +123,7 @@ typedef enum { coding_BLITZ_IMA, /* Blitz Games 4-bit IMA ADPCM */ coding_MS_IMA, /* Microsoft IMA ADPCM */ + coding_MS_IMA_mono, /* Microsoft IMA ADPCM (mono/interleave) */ coding_XBOX_IMA, /* XBOX IMA ADPCM */ coding_XBOX_IMA_mch, /* XBOX IMA ADPCM (multichannel) */ coding_XBOX_IMA_int, /* XBOX IMA ADPCM (mono/interleave) */ @@ -286,6 +287,7 @@ typedef enum { layout_blocked_vs_square, layout_blocked_vid1, layout_blocked_ubi_sce, + layout_blocked_tt_ad, /* otherwise odd */ layout_segmented, /* song divided in segments (song sections) */ @@ -765,6 +767,9 @@ typedef enum { meta_MPEG, meta_SSPF, meta_S3V, + meta_ESF, + meta_ADM3, + meta_TT_AD, } meta_t;