From 34357351c8ddc507c856ba9ac27d665d6a09ab49 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Sun, 8 Oct 2017 16:25:44 -0700 Subject: [PATCH] Updated VGMStream to r1050-707-gfcc79e8f. --- .../vgmstream.xcodeproj/project.pbxproj | 32 ++- .../vgmstream/vgmstream/src/coding/coding.h | 14 +- .../vgmstream/src/coding/coding_utils.c | 240 ++++++++++-------- .../vgmstream/src/coding/ffmpeg_decoder.c | 30 +-- .../src/coding/ffmpeg_decoder_utils.h | 6 +- .../src/coding/ffmpeg_decoder_utils_ea_xma.c | 172 ++++++++++--- ...s.c => ffmpeg_decoder_utils_switch_opus.c} | 31 ++- .../vgmstream/src/coding/pcm_decoder.c | 36 ++- Frameworks/vgmstream/vgmstream/src/formats.c | 11 +- .../vgmstream/vgmstream/src/meta/ea_snu.c | 16 +- Frameworks/vgmstream/vgmstream/src/meta/fsb.c | 2 +- .../vgmstream/vgmstream/src/meta/fsb5.c | 6 +- Frameworks/vgmstream/vgmstream/src/meta/hca.c | 20 +- .../vgmstream/vgmstream/src/meta/hca_keys.h | 8 +- .../vgmstream/vgmstream/src/meta/meta.h | 8 +- .../vgmstream/vgmstream/src/meta/musc.c | 85 +++---- .../vgmstream/vgmstream/src/meta/nsw_opus.c | 64 +++++ .../src/meta/{x360_nub.c => nub_xma.c} | 2 +- .../vgmstream/vgmstream/src/meta/pc_al2.c | 40 +++ .../vgmstream/vgmstream/src/meta/ps2_rxws.c | 2 +- .../vgmstream/vgmstream/src/meta/sgxd.c | 2 +- .../vgmstream/vgmstream/src/meta/vawx.c | 31 +-- .../vgmstream/vgmstream/src/meta/wwise.c | 24 +- Frameworks/vgmstream/vgmstream/src/meta/xma.c | 12 +- .../vgmstream/src/meta/{ps3_xvag.c => xvag.c} | 4 +- Frameworks/vgmstream/vgmstream/src/meta/xwb.c | 2 +- .../vgmstream/vgmstream/src/vgmstream.c | 15 +- .../vgmstream/vgmstream/src/vgmstream.h | 12 +- 28 files changed, 614 insertions(+), 313 deletions(-) rename Frameworks/vgmstream/vgmstream/src/coding/{ffmpeg_decoder_utils_wwise_opus.c => ffmpeg_decoder_utils_switch_opus.c} (90%) create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/nsw_opus.c rename Frameworks/vgmstream/vgmstream/src/meta/{x360_nub.c => nub_xma.c} (95%) create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/pc_al2.c rename Frameworks/vgmstream/vgmstream/src/meta/{ps3_xvag.c => xvag.c} (96%) diff --git a/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj index a3eaab450..6e02f3528 100644 --- a/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj @@ -22,7 +22,6 @@ 831BA61D1EAC61A500CF89B0 /* ubi_raki.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6131EAC61A500CF89B0 /* ubi_raki.c */; }; 831BA61E1EAC61A500CF89B0 /* vawx.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6141EAC61A500CF89B0 /* vawx.c */; }; 831BA61F1EAC61A500CF89B0 /* x360_cxs.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6151EAC61A500CF89B0 /* x360_cxs.c */; }; - 831BA6201EAC61A500CF89B0 /* x360_nub.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6161EAC61A500CF89B0 /* x360_nub.c */; }; 831BA6211EAC61A500CF89B0 /* x360_pasx.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6171EAC61A500CF89B0 /* x360_pasx.c */; }; 831BA6281EAC61CB00CF89B0 /* coding_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6221EAC61CB00CF89B0 /* coding_utils.c */; }; 8323894A1D22419B00482226 /* clHCA.c in Sources */ = {isa = PBXBuildFile; fileRef = 832389481D22419B00482226 /* clHCA.c */; }; @@ -32,6 +31,11 @@ 83299FD01E7660C7003A3242 /* bik.c in Sources */ = {isa = PBXBuildFile; fileRef = 83299FCE1E7660C7003A3242 /* bik.c */; }; 83299FD11E7660C7003A3242 /* dsp_adx.c in Sources */ = {isa = PBXBuildFile; fileRef = 83299FCF1E7660C7003A3242 /* dsp_adx.c */; }; 832C70BF1E9335E400BD7B4E /* Vorbis.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83F4128F1E932F9A002E37D0 /* Vorbis.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 83345A4A1F8AEAF900B2EAA4 /* ffmpeg_decoder_utils_switch_opus.c in Sources */ = {isa = PBXBuildFile; fileRef = 83345A491F8AEAF900B2EAA4 /* ffmpeg_decoder_utils_switch_opus.c */; }; + 83345A4F1F8AEB2800B2EAA4 /* nub_xma.c in Sources */ = {isa = PBXBuildFile; fileRef = 83345A4B1F8AEB2700B2EAA4 /* nub_xma.c */; }; + 83345A501F8AEB2800B2EAA4 /* pc_al2.c in Sources */ = {isa = PBXBuildFile; fileRef = 83345A4C1F8AEB2700B2EAA4 /* pc_al2.c */; }; + 83345A511F8AEB2800B2EAA4 /* nsw_opus.c in Sources */ = {isa = PBXBuildFile; fileRef = 83345A4D1F8AEB2800B2EAA4 /* nsw_opus.c */; }; + 83345A521F8AEB2800B2EAA4 /* xvag.c in Sources */ = {isa = PBXBuildFile; fileRef = 83345A4E1F8AEB2800B2EAA4 /* xvag.c */; }; 833A7A2E1ED11961003EC53E /* xau.c in Sources */ = {isa = PBXBuildFile; fileRef = 833A7A2D1ED11961003EC53E /* xau.c */; }; 834D3A6E19F47C98001C54F6 /* g1l.c in Sources */ = {isa = PBXBuildFile; fileRef = 834D3A6D19F47C98001C54F6 /* g1l.c */; }; 8350270D1ED119D200C25929 /* ps3_mta2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8350270C1ED119D200C25929 /* ps3_mta2.c */; }; @@ -270,7 +274,6 @@ 836F701318BDC2190095E648 /* ps3_klbs.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED718BDC2190095E648 /* ps3_klbs.c */; }; 836F701418BDC2190095E648 /* ps3_msf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED818BDC2190095E648 /* ps3_msf.c */; }; 836F701518BDC2190095E648 /* ps3_past.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED918BDC2190095E648 /* ps3_past.c */; }; - 836F701818BDC2190095E648 /* ps3_xvag.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EDC18BDC2190095E648 /* ps3_xvag.c */; }; 836F701918BDC2190095E648 /* psx_cdxa.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EDD18BDC2190095E648 /* psx_cdxa.c */; }; 836F701A18BDC2190095E648 /* psx_fag.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EDE18BDC2190095E648 /* psx_fag.c */; }; 836F701B18BDC2190095E648 /* psx_gms.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EDF18BDC2190095E648 /* psx_gms.c */; }; @@ -344,7 +347,6 @@ 83709E0D1ECBC1C3005C03D3 /* mc3_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E0B1ECBC1C3005C03D3 /* mc3_decoder.c */; }; 83709E0E1ECBC1C3005C03D3 /* psv_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E0C1ECBC1C3005C03D3 /* psv_decoder.c */; }; 8374EE3E1F787AB600033E90 /* ffmpeg_decoder_utils_ea_xma.c in Sources */ = {isa = PBXBuildFile; fileRef = 8374EE361F787AB500033E90 /* ffmpeg_decoder_utils_ea_xma.c */; }; - 8374EE3F1F787AB600033E90 /* ffmpeg_decoder_utils_wwise_opus.c in Sources */ = {isa = PBXBuildFile; fileRef = 8374EE3B1F787AB600033E90 /* ffmpeg_decoder_utils_wwise_opus.c */; }; 8374EE401F787AB600033E90 /* ffmpeg_decoder_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 8374EE3C1F787AB600033E90 /* ffmpeg_decoder_utils.h */; }; 8374EE411F787AB600033E90 /* ffmpeg_decoder_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8374EE3D1F787AB600033E90 /* ffmpeg_decoder_utils.c */; }; 838BDB641D3AF08C0022CA6F /* libavcodec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB611D3AF08C0022CA6F /* libavcodec.a */; }; @@ -525,7 +527,6 @@ 831BA6131EAC61A500CF89B0 /* ubi_raki.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ubi_raki.c; sourceTree = ""; }; 831BA6141EAC61A500CF89B0 /* vawx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vawx.c; sourceTree = ""; }; 831BA6151EAC61A500CF89B0 /* x360_cxs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x360_cxs.c; sourceTree = ""; }; - 831BA6161EAC61A500CF89B0 /* x360_nub.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x360_nub.c; sourceTree = ""; }; 831BA6171EAC61A500CF89B0 /* x360_pasx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x360_pasx.c; sourceTree = ""; }; 831BA6221EAC61CB00CF89B0 /* coding_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = coding_utils.c; sourceTree = ""; }; 831BD11F1EEE1CF200198540 /* ngc_ulw.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ngc_ulw.c; sourceTree = ""; }; @@ -536,6 +537,11 @@ 832389511D224C0800482226 /* hca_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hca_decoder.c; sourceTree = ""; }; 83299FCE1E7660C7003A3242 /* bik.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bik.c; sourceTree = ""; }; 83299FCF1E7660C7003A3242 /* dsp_adx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dsp_adx.c; sourceTree = ""; }; + 83345A491F8AEAF900B2EAA4 /* ffmpeg_decoder_utils_switch_opus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffmpeg_decoder_utils_switch_opus.c; sourceTree = ""; }; + 83345A4B1F8AEB2700B2EAA4 /* nub_xma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nub_xma.c; sourceTree = ""; }; + 83345A4C1F8AEB2700B2EAA4 /* pc_al2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pc_al2.c; sourceTree = ""; }; + 83345A4D1F8AEB2800B2EAA4 /* nsw_opus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nsw_opus.c; sourceTree = ""; }; + 83345A4E1F8AEB2800B2EAA4 /* xvag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xvag.c; sourceTree = ""; }; 833A7A2D1ED11961003EC53E /* xau.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xau.c; sourceTree = ""; }; 834D3A6D19F47C98001C54F6 /* g1l.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = g1l.c; sourceTree = ""; }; 8350270C1ED119D200C25929 /* ps3_mta2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_mta2.c; sourceTree = ""; }; @@ -776,7 +782,6 @@ 836F6ED718BDC2190095E648 /* ps3_klbs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_klbs.c; sourceTree = ""; }; 836F6ED818BDC2190095E648 /* ps3_msf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_msf.c; sourceTree = ""; }; 836F6ED918BDC2190095E648 /* ps3_past.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_past.c; sourceTree = ""; }; - 836F6EDC18BDC2190095E648 /* ps3_xvag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_xvag.c; sourceTree = ""; }; 836F6EDD18BDC2190095E648 /* psx_cdxa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = psx_cdxa.c; sourceTree = ""; }; 836F6EDE18BDC2190095E648 /* psx_fag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = psx_fag.c; sourceTree = ""; }; 836F6EDF18BDC2190095E648 /* psx_gms.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = psx_gms.c; sourceTree = ""; }; @@ -850,7 +855,6 @@ 83709E0B1ECBC1C3005C03D3 /* mc3_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mc3_decoder.c; sourceTree = ""; }; 83709E0C1ECBC1C3005C03D3 /* psv_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = psv_decoder.c; sourceTree = ""; }; 8374EE361F787AB500033E90 /* ffmpeg_decoder_utils_ea_xma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffmpeg_decoder_utils_ea_xma.c; sourceTree = ""; }; - 8374EE3B1F787AB600033E90 /* ffmpeg_decoder_utils_wwise_opus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffmpeg_decoder_utils_wwise_opus.c; sourceTree = ""; }; 8374EE3C1F787AB600033E90 /* ffmpeg_decoder_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffmpeg_decoder_utils.h; sourceTree = ""; }; 8374EE3D1F787AB600033E90 /* ffmpeg_decoder_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffmpeg_decoder_utils.c; sourceTree = ""; }; 838BDB611D3AF08C0022CA6F /* libavcodec.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavcodec.a; path = ../../ThirdParty/ffmpeg/lib/libavcodec.a; sourceTree = ""; }; @@ -1050,8 +1054,8 @@ 836F6DDF18BDC2180095E648 /* coding */ = { isa = PBXGroup; children = ( + 83345A491F8AEAF900B2EAA4 /* ffmpeg_decoder_utils_switch_opus.c */, 8374EE361F787AB500033E90 /* ffmpeg_decoder_utils_ea_xma.c */, - 8374EE3B1F787AB600033E90 /* ffmpeg_decoder_utils_wwise_opus.c */, 8374EE3D1F787AB600033E90 /* ffmpeg_decoder_utils.c */, 8374EE3C1F787AB600033E90 /* ffmpeg_decoder_utils.h */, 83AA5D0E1F6E2F5F0020821C /* ea_xa_decoder.c */, @@ -1157,6 +1161,10 @@ 836F6E2718BDC2180095E648 /* meta */ = { isa = PBXGroup; children = ( + 83345A4D1F8AEB2800B2EAA4 /* nsw_opus.c */, + 83345A4B1F8AEB2700B2EAA4 /* nub_xma.c */, + 83345A4C1F8AEB2700B2EAA4 /* pc_al2.c */, + 83345A4E1F8AEB2800B2EAA4 /* xvag.c */, 83AA5D201F6E2F9B0020821C /* awc.c */, 83AA5D221F6E2F9C0020821C /* ea_snu.c */, 83AA5D211F6E2F9C0020821C /* hca_keys.h */, @@ -1184,7 +1192,6 @@ 831BA6131EAC61A500CF89B0 /* ubi_raki.c */, 831BA6141EAC61A500CF89B0 /* vawx.c */, 831BA6151EAC61A500CF89B0 /* x360_cxs.c */, - 831BA6161EAC61A500CF89B0 /* x360_nub.c */, 831BA6171EAC61A500CF89B0 /* x360_pasx.c */, 83FF0EBB1E93282100C58054 /* wwise.c */, 83AB8C731E8072A100086084 /* nub_vag.c */, @@ -1370,7 +1377,6 @@ 836F6ED718BDC2190095E648 /* ps3_klbs.c */, 836F6ED818BDC2190095E648 /* ps3_msf.c */, 836F6ED918BDC2190095E648 /* ps3_past.c */, - 836F6EDC18BDC2190095E648 /* ps3_xvag.c */, 836F6EDD18BDC2190095E648 /* psx_cdxa.c */, 836F6EDE18BDC2190095E648 /* psx_fag.c */, 836F6EDF18BDC2190095E648 /* psx_gms.c */, @@ -1672,7 +1678,6 @@ 836F6F9B18BDC2190095E648 /* mn_str.c in Sources */, 836F6F5918BDC2190095E648 /* tra_blocked.c in Sources */, 836F6F9F18BDC2190095E648 /* musc.c in Sources */, - 836F701818BDC2190095E648 /* ps3_xvag.c in Sources */, 836F6FCA18BDC2190095E648 /* ps2_adm.c in Sources */, 836F6FA118BDC2190095E648 /* myspd.c in Sources */, 836F6FD718BDC2190095E648 /* ps2_filp.c in Sources */, @@ -1681,7 +1686,6 @@ 836F6F7018BDC2190095E648 /* apple_caff.c in Sources */, 836F700018BDC2190095E648 /* ps2_svag.c in Sources */, 836F6FB618BDC2190095E648 /* ngc_sck_dsp.c in Sources */, - 8374EE3F1F787AB600033E90 /* ffmpeg_decoder_utils_wwise_opus.c in Sources */, 836F6F2818BDC2190095E648 /* ima_decoder.c in Sources */, 836F702318BDC2190095E648 /* rsf.c in Sources */, 83299FD01E7660C7003A3242 /* bik.c in Sources */, @@ -1760,6 +1764,7 @@ 836F6FD318BDC2190095E648 /* ps2_ccc.c in Sources */, 83AA5D261F6E2F9C0020821C /* ea_snu.c in Sources */, 83AA5D171F6E2F600020821C /* mpeg_custom_utils_ealayer3.c in Sources */, + 83345A521F8AEB2800B2EAA4 /* xvag.c in Sources */, 836F704C18BDC2190095E648 /* xbox_xvas.c in Sources */, 836F6F3918BDC2190095E648 /* SASSC_decoder.c in Sources */, 836F703A18BDC2190095E648 /* vs.c in Sources */, @@ -1818,6 +1823,7 @@ 836F6F6D18BDC2190095E648 /* aifc.c in Sources */, 836F702218BDC2190095E648 /* rsd.c in Sources */, 836F6FC618BDC2190095E648 /* pcm.c in Sources */, + 83345A501F8AEB2800B2EAA4 /* pc_al2.c in Sources */, 836F702518BDC2190095E648 /* rwx.c in Sources */, 836F6F3A18BDC2190095E648 /* sdx2_decoder.c in Sources */, 836F6FAF18BDC2190095E648 /* ngc_dsp_std.c in Sources */, @@ -1840,7 +1846,6 @@ 836F6F4618BDC2190095E648 /* filp_blocked.c in Sources */, 836F6FE518BDC2190095E648 /* ps2_lpcm.c in Sources */, 836F6FB318BDC2190095E648 /* ngc_lps.c in Sources */, - 831BA6201EAC61A500CF89B0 /* x360_nub.c in Sources */, 836F6FC018BDC2190095E648 /* p3d.c in Sources */, 836F6FC718BDC2190095E648 /* pona.c in Sources */, 836F6FE618BDC2190095E648 /* ps2_mcg.c in Sources */, @@ -1884,6 +1889,7 @@ 836F6F8018BDC2190095E648 /* dsp_bdsp.c in Sources */, 836F6F9618BDC2190095E648 /* lsf.c in Sources */, 8374EE3E1F787AB600033E90 /* ffmpeg_decoder_utils_ea_xma.c in Sources */, + 83345A511F8AEB2800B2EAA4 /* nsw_opus.c in Sources */, 836F6FC818BDC2190095E648 /* pos.c in Sources */, 8350C05A1E071990009E0A93 /* ps2_svag_snk.c in Sources */, 836F6F8918BDC2190095E648 /* gca.c in Sources */, @@ -1948,6 +1954,7 @@ 836F6F3618BDC2190095E648 /* ogg_vorbis_decoder.c in Sources */, 836F704718BDC2190095E648 /* xbox_hlwav.c in Sources */, 836F701C18BDC2190095E648 /* psx_str_mgav.c in Sources */, + 83345A4F1F8AEB2800B2EAA4 /* nub_xma.c in Sources */, 836F6F7618BDC2190095E648 /* brstm.c in Sources */, 836F700718BDC2190095E648 /* ps2_vgv.c in Sources */, 836F704F18BDC2190095E648 /* xwb.c in Sources */, @@ -1982,6 +1989,7 @@ 836F6FBA18BDC2190095E648 /* ngc_ymf.c in Sources */, 836F705018BDC2190095E648 /* ydsp.c in Sources */, 836F702718BDC2190095E648 /* sat_baka.c in Sources */, + 83345A4A1F8AEAF900B2EAA4 /* ffmpeg_decoder_utils_switch_opus.c in Sources */, 836F6F8C18BDC2190095E648 /* gh3_bar.c in Sources */, 836F704B18BDC2190095E648 /* xbox_xmu.c in Sources */, 832389501D2246C300482226 /* hca.c in Sources */, diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding.h b/Frameworks/vgmstream/vgmstream/src/coding/coding.h index 0c21a18d5..1976a5e10 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/coding.h +++ b/Frameworks/vgmstream/vgmstream/src/coding/coding.h @@ -64,6 +64,7 @@ void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channels void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian); size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample); @@ -214,7 +215,10 @@ void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples); size_t ffmpeg_make_opus_header(uint8_t * buf, int buf_size, int channels, int skip, int sample_rate); -size_t ffmpeg_get_eaxma_virtual_size(off_t real_offset, size_t real_size, STREAMFILE *streamFile); +size_t ffmpeg_get_eaxma_virtual_size(int channels, off_t real_offset, size_t real_size, STREAMFILE *streamFile); + +size_t switch_opus_get_samples(off_t offset, size_t data_size, int sample_rate, STREAMFILE *streamFile); + #endif /* coding_utils */ @@ -229,12 +233,14 @@ int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t data /* MS audio format's sample info (struct to avoid passing so much stuff, separate for reusing) */ typedef struct { + /* input */ int xma_version; - int channels; - int stream_mode; off_t data_offset; size_t data_size; + int channels; /* for skips */ + off_t chunk_offset; /* for multistream config */ + /* frame offsets */ int loop_flag; uint32_t loop_start_b; @@ -253,7 +259,7 @@ void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_ void wma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags); void xma1_parse_fmt_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * channels, int * sample_rate, int * loop_flag, int32_t * loop_start_b, int32_t * loop_end_b, int32_t * loop_subframe, int be); -void xma2_parse_fmt_chunk_extra(STREAMFILE *streamFile, off_t chunk_offset, int * loop_flag, int32_t * num_samples, int32_t * loop_start_sample, int32_t * loop_end_sample, int be); +void xma2_parse_fmt_chunk_extra(STREAMFILE *streamFile, off_t chunk_offset, int * loop_flag, int32_t * out_num_samples, int32_t * out_loop_start_sample, int32_t * out_loop_end_sample, int be); void xma2_parse_xma2_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * channels, int * sample_rate, int * loop_flag, int32_t * num_samples, int32_t * loop_start_sample, int32_t * loop_end_sample); size_t atrac3_bytes_to_samples(size_t bytes, int full_block_align); diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c b/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c index 308180c7c..a57331469 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c @@ -235,7 +235,7 @@ int ffmpeg_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, s put_16bitLE(buf+0x14, codec_XMA2); put_16bitLE(buf+0x16, channels); put_32bitLE(buf+0x18, sample_rate); - put_32bitLE(buf+0x1c, sample_rate*channels / sizeof(sample)); /* average bytes per second (wrong unneeded) */ + put_32bitLE(buf+0x1c, sample_rate*channels / sizeof(sample)); /* average bytes per second (wrong, unneeded) */ put_16bitLE(buf+0x20, (int16_t)(channels*sizeof(sample))); /* block align */ put_16bitLE(buf+0x22, 16); /* bits per sample */ @@ -243,7 +243,7 @@ int ffmpeg_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, s put_16bitLE(buf+0x26, streams); /* number of streams */ put_32bitLE(buf+0x28, speakers); /* speaker position */ put_32bitLE(buf+0x2c, bytecount); /* PCM samples */ - put_32bitLE(buf+0x30, block_size); /* XMA block size */ + put_32bitLE(buf+0x30, block_size); /* XMA block size (can be zero, it's for seeking only) */ /* (looping values not set, expected to be handled externally) */ put_32bitLE(buf+0x34, 0); /* play begin */ put_32bitLE(buf+0x38, 0); /* play length */ @@ -251,7 +251,7 @@ int ffmpeg_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, s put_32bitLE(buf+0x40, 0); /* loop length */ put_8bit(buf+0x44, 0); /* loop count */ put_8bit(buf+0x45, 4); /* encoder version */ - put_16bitLE(buf+0x46, block_count); /* blocks count = entries in seek table */ + put_16bitLE(buf+0x46, block_count); /* blocks count (entries in seek table, can be zero) */ memcpy(buf+0x48, "data", 4); put_32bitLE(buf+0x4c, data_size); /* data size */ @@ -424,19 +424,18 @@ fail: /* ******************************************** */ /* XMA PARSING */ /* ******************************************** */ -#define XMA_CHECK_SKIPS 0 /** * Find total and loop samples of Microsoft audio formats (WMAPRO/XMA1/XMA2) by reading frame headers. * * The stream is made of packets, each containing N small frames of X samples. Frames are further divided into subframes. - * XMA1/XMA2/WMAPRO only differ in the packet headers. + * XMA1/XMA2 can divided into streams for multichannel (1/2ch ... 1/2ch). From the file start, packet 1..N is owned by + * stream 1..N. Then must follow "packet_skip" value to find the stream next packet, as they are arbitrarily interleaved. + * XMA1/XMA2/WMAPRO data only differs in the packet headers. */ -static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int bytes_per_packet, int samples_per_frame, int samples_per_subframe, int bits_frame_size) { - int frames = 0, samples = 0, loop_start_frame = 0, loop_end_frame = 0, skip_packets; -#if XMA_CHECK_SKIPS - int start_skip = 0, end_skip = 0, first_start_skip = 0, last_end_skip = 0; -#endif +static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int start_packet, int channels_per_packet, int bytes_per_packet, int samples_per_frame, int samples_per_subframe, int bits_frame_size) { + int frames = 0, samples = 0, loop_start_frame = 0, loop_end_frame = 0, start_skip = 0, end_skip = 0; + uint32_t first_frame_b, packet_skip_count = 0, frame_size_b, packet_size_b, header_size_b; uint64_t offset_b, packet_offset_b, frame_offset_b; size_t size; @@ -445,25 +444,15 @@ static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, i off_t offset = msd->data_offset; uint32_t stream_offset_b = msd->data_offset * 8; + offset += start_packet * packet_size; size = offset + msd->data_size; packet_size_b = packet_size * 8; - /* if we knew the streams mode then we could read just the first one and adjust samples later - * not a big deal but maybe important for skip stuff */ - //streams = (msd->stream_mode==0 ? (msd->channels + 1) / 2 : msd->channels) - skip_packets = 0; - /* read packets */ while (offset < size) { offset_b = offset * 8; /* global offset in bits */ offset += packet_size; /* global offset in bytes */ - /* skip packets not owned by the first stream, since we only need samples from it */ - if (skip_packets && packet_skip_count) { - packet_skip_count--; - continue; - } - /* packet header */ if (msd->xma_version == 1) { /* XMA1 */ //packet_sequence = read_bitsBE_b(offset_b+0, 4, streamFile); /* numbered from 0 to N */ @@ -480,149 +469,141 @@ static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, i } else { /* WMAPRO(v3) */ //packet_sequence = read_bitsBE_b(offset_b+0, 4, streamFile); /* numbered from 0 to N */ //unknown = read_bitsBE_b(offset_b+4, 2, streamFile); /* packet_metadata? (always 2) */ - first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, streamFile); /* offset in bits inside the packet */ - packet_skip_count = 0; /* xwma probably has no need to skip packets since it uses real multichannel ch audio */ - header_size_b = 4+2+bits_frame_size; /* variable-size header */ + first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, streamFile); /* offset in bits inside the packet */ + packet_skip_count = 0; /* xwma has no need to skip packets since it uses real multichannel audio */ + header_size_b = 4+2+bits_frame_size; /* variable-sized header */ } - /* full packet skip */ - if (packet_skip_count == 0x7FF) { + /* XMA2 packets with XMA1 RIFF (transmogrified), remove the packet metadata flag */ + if (msd->xma_version == 1 && (packet_skip_count & 0x700) == 0x100) { + //VGM_LOG("MS_SAMPLES: XMA1 transmogrified packet header at 0x%lx\n", (off_t)offset_b/8); + packet_skip_count &= ~0x100; + } + + /* full packet skip, no new frames start in this packet (prev frames can end here) */ + if (packet_skip_count == 0x7FF) { /* XMA1, 11b */ + VGM_LOG("MS_SAMPLES: XMA1 full packet_skip %i at 0x%lx\n", packet_skip_count, (off_t)offset_b/8); packet_skip_count = 0; continue; } - if (packet_skip_count > 255) { /* seen in some (converted?) XMA1 */ + else if (packet_skip_count == 0xFF) { /* XMA2, 8b*/ + VGM_LOG("MS_SAMPLES: XMA2 full packet_skip %i at 0x%lx\n", packet_skip_count, (off_t)offset_b/8); packet_skip_count = 0; + continue; } - VGM_ASSERT(packet_skip_count > 10, "XMA: found big packet skip %i\n", packet_skip_count);//a bit unusual... - //VGM_LOG("packet: off=%x, ff=%i, ps=%i\n", offset, first_frame_b, packet_skip_b); + offset += packet_size * (packet_skip_count); /* skip packets not owned by the first stream, since we only need samples from it */ + + /* unusual but not impossible, as the encoder can interleave packets in any way */ + VGM_ASSERT(packet_skip_count > 10, "MS_SAMPLES: found big packet skip %i at 0x%lx\n", packet_skip_count, (off_t)offset_b/8); + + packet_offset_b = header_size_b + first_frame_b; - packet_offset_b = header_size_b + first_frame_b; /* packet offset in bits */ /* read packet frames */ while (packet_offset_b < packet_size_b) { frame_offset_b = offset_b + packet_offset_b; /* in bits for aligment stuff */ - //todo not sure if frames or frames+1 (considering skip_samples) + /* loops, later adjusted with subframe (seems correct vs tests) */ if (msd->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == msd->loop_start_b) loop_start_frame = frames; if (msd->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == msd->loop_end_b) loop_end_frame = frames; - /* frame header */ frame_size_b = read_bitsBE_b(frame_offset_b, bits_frame_size, streamFile); frame_offset_b += bits_frame_size; - if (frame_size_b == 0) /* observed in some files with empty frames/packets */ + //;VGM_LOG("MS_SAMPLES: frame_offset=0x%lx (0b%lx), frame_size=0x%x (0b%x)\n", (off_t)frame_offset_b/8,(off_t)frame_offset_b, frame_size_b/8, frame_size_b); + + /* stop when packet padding starts (0x00 for XMA1 or 0xFF in XMA2) */ + if (frame_size_b == 0 || frame_size_b == (0xffffffff >> (32 - bits_frame_size))) { break; + } packet_offset_b += frame_size_b; /* including header */ -#if 0 - { - uint32_t frame_config - frame_config = read_bitsBE_b(frame_offset_b, 15, streamFile); - //VGM_LOG(" frame %04i: off_b=%I64x (~0x%I64x), fs_b=%i (~0x%x), fs=%x\n",frames, frame_offset_b, frame_offset_b/8, frame_size_b,frame_size_b/8, frame_config); - - //if (frame_config != 0x7f00) /* "contains all subframes"? */ - // continue; // todo read packet end bit instead - } -#endif - frame_offset_b += 15; //todo bits_frame_size? - - if (frame_size_b == 0x7FFF) { /* end packet frame marker */ - break; - } - -#if XMA_CHECK_SKIPS - // more header stuff (info from FFmpeg) - { + /* find skips (info from FFmpeg) */ + if (channels_per_packet && (msd->xma_version == 1 || msd->xma_version == 2)) { int flag; + int tilehdr_size = 15; //todo incorrect but usable for XMA, fix for WMAPro (complex calcs, see ffmpeg decode_tilehdr) + + frame_offset_b += tilehdr_size; /* ignore "postproc transform" */ - if (msd->channels > 1) { + if (channels_per_packet > 1) { flag = read_bitsBE_b(frame_offset_b, 1, streamFile); frame_offset_b += 1; if (flag) { flag = read_bitsBE_b(frame_offset_b, 1, streamFile); frame_offset_b += 1; if (flag) { - frame_offset_b += 1 + 4 * msd->channels*msd->channels; /* 4-something per double channel? */ + frame_offset_b += 1 + 4 * channels_per_packet*channels_per_packet; /* 4-something per double channel? */ } } } - /* get start/end skips to get the proper number of samples */ //todo check if first bit =1 means full 512 skip + /* get start/end skips to get the proper number of samples */ flag = read_bitsBE_b(frame_offset_b, 1, streamFile); frame_offset_b += 1; if (flag) { - int new_skip; - /* get start skip */ flag = read_bitsBE_b(frame_offset_b, 1, streamFile); frame_offset_b += 1; if (flag) { - VGM_LOG("start_skip at 0x%I64x\n", frame_offset_b); - new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile); + int new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile); + VGM_LOG("MS_SAMPLES: start_skip %i at 0x%lx (bit 0x%lx)\n", new_skip, (off_t)frame_offset_b/8, (off_t)frame_offset_b); + VGM_ASSERT(start_skip, "MS_SAMPLES: more than one start_skip (%i)\n", new_skip); //ignore, happens due to incorrect tilehdr_size frame_offset_b += 10; - VGM_ASSERT(start_skip, "XMA: more than one start_skip (%i)\n", new_skip); - if (new_skip > samples_per_frame) { /* from xmaencode */ - VGM_LOG("XMA: bad start_skip (%i)\n", new_skip); + if (new_skip > samples_per_frame) /* from xmaencode */ new_skip = samples_per_frame; - } - if (frames==0) first_start_skip = new_skip; /* sometimes in the middle */ - start_skip += new_skip; + if (start_skip==0) + start_skip = new_skip; } /* get end skip */ flag = read_bitsBE_b(frame_offset_b, 1, streamFile); frame_offset_b += 1; if (flag) { - VGM_LOG("end_skip at 0x%I64x\n", frame_offset_b); - new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile); + int new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile); + VGM_LOG("MS_SAMPLES: end_skip %i at 0x%lx (bit 0x%lx)\n", new_skip, (off_t)frame_offset_b/8, (off_t)frame_offset_b); + VGM_ASSERT(end_skip, "MS_SAMPLES: more than one end_skip (%i)\n", new_skip);//ignore, happens due to incorrect tilehdr_size frame_offset_b += 10; - VGM_ASSERT(end_skip, "XMA: more than one end_skip (%i)\n", new_skip); - if (new_skip > samples_per_frame) { /* from xmaencode */ - VGM_LOG("XMA: bad end_skip (%i)\n", new_skip); + if (new_skip > samples_per_frame) /* from xmaencode */ new_skip = samples_per_frame; - } - last_end_skip = new_skip; /* not seen */ - end_skip += new_skip; + end_skip = new_skip; } - - VGM_LOG(" skip: st=%i, ed=%i\n", start_skip, end_skip); } } -#endif + samples += samples_per_frame; frames++; + + /* last bit in frame = more frames flag, end packet to avoid reading garbage in some cases + * (last frame spilling to other packets also has this flag, though it's ignored here) */ + if (packet_offset_b < packet_size_b && !read_bitsBE_b(offset_b + packet_offset_b - 1, 1, streamFile)) { + break; + } } } -#if XMA_CHECK_SKIPS - //todo this seems to usually work, but not always - /* apply skips (not sure why 64, empty samples generated by the decoder not in the file?) */ - samples = samples + 64 - start_skip; - samples = samples + 64 - end_skip; - - msd->skip_samples = 64 + samples_per_frame; //todo not always correct -#endif + //todo FFmpeg seems to decode 1 subframe late vs xmaencode, and doesn't write 128 init samples, so skips are not useful ATM + //samples = samples + 128 - start_skip - end_skip; /* 128 init samples added by xmaencode */ msd->num_samples = samples; + msd->skip_samples = start_skip; if (msd->loop_flag && loop_end_frame > loop_start_frame) { msd->loop_start_sample = loop_start_frame * samples_per_frame + msd->loop_start_subframe * samples_per_subframe; msd->loop_end_sample = loop_end_frame * samples_per_frame + msd->loop_end_subframe * samples_per_subframe; -#if XMA_CHECK_SKIPS - /* maybe this is needed */ - //msd->loop_start_sample -= msd->skip_samples; - //msd->loop_end_sample -= msd->skip_samples; -#endif + + //todo maybe this is needed + //msd->loop_start_sample -= start_skip; + //msd->loop_end_sample -= start_skip; } } @@ -658,7 +639,28 @@ void xma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile) { const int samples_per_frame = 512; const int samples_per_subframe = 128; - ms_audio_get_samples(msd, streamFile, bytes_per_packet, samples_per_frame, samples_per_subframe, 15); + int start_stream = 0; + int channels_per_stream = 0; + + /* get from stream config (needed to find skips) */ + if (msd->chunk_offset) { + int format = read_16bitLE(msd->chunk_offset,streamFile); + if (format == 0x0165 || format == 0x6501) { /* XMA1 */ + channels_per_stream = read_8bit(msd->chunk_offset + 0x0C + 0x14*start_stream + 0x11,streamFile); + } else if (format == 0x0166 || format == 0x6601) { /* new XMA2 */ + channels_per_stream = msd->channels > 1 ? 2 : 1; + } else { /* old XMA2 */ + int version = read_8bit(msd->chunk_offset,streamFile); + channels_per_stream = read_8bit(msd->chunk_offset + 0x20 + (version==3 ? 0x00 : 0x08) + 0x4*start_stream + 0x00,streamFile); + } + } + else if (msd->channels) { + channels_per_stream = msd->channels > 1 ? 2 : 1; + } + if (channels_per_stream > 2) + channels_per_stream = 0; + + ms_audio_get_samples(msd, streamFile, start_stream, channels_per_stream, bytes_per_packet, samples_per_frame, samples_per_subframe, 15); } void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags) { @@ -667,21 +669,20 @@ void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_ int samples_per_frame = 0; int samples_per_subframe = 0; int bits_frame_size = 0; + int start_packet = 0; + int channels_per_stream = msd->channels; - /* do some WMAPRO setup (code from ffmpeg) */ + if (!(decode_flags & 0x40)) { + VGM_LOG("MS_SAMPLES: no frame length in WMAPro\n"); + msd->num_samples = 0; + return; + } samples_per_frame = wma_get_samples_per_frame(version, sample_rate, decode_flags); + bits_frame_size = floor(log(block_align) / log(2)) + 4; /* max bits needed to represent this block_align */ + samples_per_subframe = 0; /* not really needed WMAPro can't use loop subframes (complex subframe lengths) */ + msd->xma_version = 0; /* signal it's not XMA */ - /* max bits needed to represent this block_align */ - bits_frame_size = floor(log(block_align) / log(2)) + 4; - - /* not really needed as I've never seen loop subframe data for WMA (probably possible though) - * (FFmpeg has code to get min_samples_per subframe) */ - samples_per_subframe = 0; - - /* signal it's not XMA */ - msd->xma_version = 0; - - ms_audio_get_samples(msd, streamFile, bytes_per_packet, samples_per_frame, samples_per_subframe, bits_frame_size); + ms_audio_get_samples(msd, streamFile, start_packet, channels_per_stream, bytes_per_packet, samples_per_frame, samples_per_subframe, bits_frame_size); } void wma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags) { @@ -745,27 +746,46 @@ void xma1_parse_fmt_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * chan /* channels is the sum of all streams */ for (i = 0; i < num_streams; i++) { - total_channels += read_8bit(chunk_offset+0x0C+0x11+i*0x10,streamFile); + total_channels += read_8bit(chunk_offset+0x0C+0x14*i+0x11,streamFile); } if(channels) *channels = total_channels; } /* Read values from a 'new' XMA2 RIFF "fmt" chunk (XMA2WAVEFORMATEX), starting from an offset *after* chunk type+size. * Useful as custom X360 headers commonly have it lurking inside. Only the extra data, the first part is a normal WAVEFORMATEX. */ -void xma2_parse_fmt_chunk_extra(STREAMFILE *streamFile, off_t chunk_offset, int * loop_flag, int32_t * num_samples, int32_t * loop_start_sample, int32_t * loop_end_sample, int be) { +void xma2_parse_fmt_chunk_extra(STREAMFILE *streamFile, off_t chunk_offset, int * out_loop_flag, int32_t * out_num_samples, int32_t * out_loop_start_sample, int32_t * out_loop_end_sample, int be) { int16_t (*read_16bit)(off_t,STREAMFILE*) = be ? read_16bitBE : read_16bitLE; int32_t (*read_32bit)(off_t,STREAMFILE*) = be ? read_32bitBE : read_32bitLE; + int num_samples, loop_start_sample, loop_end_sample, loop_flag; if (read_16bit(chunk_offset+0x00,streamFile) != 0x166) return; /* up to extra data is a WAVEFORMATEX */ if (read_16bit(chunk_offset+0x10,streamFile) < 0x22) return; /* expected extra data size */ - if(num_samples) *num_samples = read_32bit(chunk_offset+0x18,streamFile); - if(loop_start_sample) *loop_start_sample = read_32bit(chunk_offset+0x28,streamFile); - if(loop_end_sample) *loop_end_sample = read_32bit(chunk_offset+0x28,streamFile) + read_32bit(chunk_offset+0x2C,streamFile); - if(loop_flag) *loop_flag = (uint8_t)read_8bit(chunk_offset+0x30,streamFile) > 0 /* never set in practice */ - || read_32bit(chunk_offset+0x2C,streamFile); /*loop_end_sample*/ - /* play_begin+end = probably pcm_samples (for original sample rate), don't seem to affect anything */ + num_samples = read_32bit(chunk_offset+0x18,streamFile); /* max samples from all frames */ + loop_start_sample = read_32bit(chunk_offset+0x28,streamFile); + loop_end_sample = loop_start_sample + read_32bit(chunk_offset+0x2C,streamFile); + loop_flag = (uint8_t)read_8bit(chunk_offset+0x30,streamFile) != 0; + /* num_samples isn't used by xmaencode, so final_num_samples = num_samples + setup_samples (128) - start_skip (~512) - end_skip (0..512) */ + /* loop values seem to be after applying skips, so loop_end wouldn't be higher than final_num_samples */ + + /* flag rarely set, use loop_end as marker */ + if (!loop_flag) { + loop_flag = loop_end_sample > 0; + + /* loop_end_sample - 128 + start_skip + end_skip = num_samples, use approx */ + if (loop_start_sample == 384 && loop_end_sample - 128 + 512 + 512 >= num_samples) { + VGM_LOG("XMA2 PARSE: disabling full loop\n"); + loop_flag = 0; /* some XMA have full loop set without loop flag and shouldn't loop */ + } + } + + if(out_num_samples) *out_num_samples = num_samples; + if(out_loop_start_sample) *out_loop_start_sample = loop_start_sample; + if(out_loop_end_sample) *out_loop_end_sample = loop_end_sample; + if(out_loop_flag) *out_loop_flag = loop_flag; + + /* play_begin+end = pcm_samples in original sample rate (not usable when resampled = looped) */ /* int32_t play_begin_sample = read_32bit(xma->chunk_offset+0x20,streamFile); */ /* int32_t play_end_sample = play_begin_sample + read_32bit(xma->chunk_offset+0x24,streamFile); */ } diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c index 1dc445505..fd703699c 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c @@ -218,11 +218,11 @@ static int ffmpeg_read(void *opaque, uint8_t *buf, int buf_size) { /* main read */ switch(data->config.type) { - case FFMPEG_EA_XMA: ret = ffmpeg_custom_read_eaxma(data, buf, buf_size); break; - case FFMPEG_WWISE_OPUS: ret = ffmpeg_custom_read_wwise_opus(data, buf, buf_size); break; - //case FFMPEG_EA_SCHL: ret = ffmpeg_custom_read_ea_schl(data, buf, buf_size); break; - //case FFMPEG_SFH: ret = ffmpeg_custom_read_sfh(data, buf, buf_size); break; - default: ret = ffmpeg_custom_read_standard(data, buf, buf_size); break; + case FFMPEG_EA_XMA: ret = ffmpeg_custom_read_eaxma(data, buf, buf_size); break; + case FFMPEG_SWITCH_OPUS: ret = ffmpeg_custom_read_switch_opus(data, buf, buf_size); break; + //case FFMPEG_EA_SCHL: ret = ffmpeg_custom_read_ea_schl(data, buf, buf_size); break; + //case FFMPEG_SFH: ret = ffmpeg_custom_read_sfh(data, buf, buf_size); break; + default: ret = ffmpeg_custom_read_standard(data, buf, buf_size); break; } data->virtual_offset += ret; //data->real_offset = ; /* must be updated in function */ @@ -285,11 +285,11 @@ static int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) { /* main seek */ switch(data->config.type) { - case FFMPEG_EA_XMA: offset = ffmpeg_custom_seek_eaxma(data, offset); break; - case FFMPEG_WWISE_OPUS: offset = ffmpeg_custom_seek_wwise_opus(data, offset); break; - //case FFMPEG_EA_SCHL: offset = ffmpeg_custom_seek_ea_schl(data, offset); break; - //case FFMPEG_SFH: offset = ffmpeg_custom_seek_sfh(data, offset); break; - default: offset = ffmpeg_custom_seek_standard(data, offset); break; + case FFMPEG_EA_XMA: offset = ffmpeg_custom_seek_eaxma(data, offset); break; + case FFMPEG_SWITCH_OPUS: offset = ffmpeg_custom_seek_switch_opus(data, offset); break; + //case FFMPEG_EA_SCHL: offset = ffmpeg_custom_seek_ea_schl(data, offset); break; + //case FFMPEG_SFH: offset = ffmpeg_custom_seek_sfh(data, offset); break; + default: offset = ffmpeg_custom_seek_standard(data, offset); break; } data->virtual_offset = offset; //data->real_offset = ; /* must be updated in function */ @@ -302,11 +302,11 @@ static int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) { static int64_t ffmpeg_size(ffmpeg_codec_data * data) { int64_t bytes; switch(data->config.type) { - case FFMPEG_EA_XMA: bytes = ffmpeg_custom_size_eaxma(data); break; - case FFMPEG_WWISE_OPUS: bytes = ffmpeg_custom_size_wwise_opus(data); break; - //case FFMPEG_EA_SCHL: bytes = ffmpeg_custom_size_ea_schl(data); break; - //case FFMPEG_SFH: bytes = ffmpeg_custom_size_sfh(data); break; - default: bytes = ffmpeg_custom_size_standard(data); break; + case FFMPEG_EA_XMA: bytes = ffmpeg_custom_size_eaxma(data); break; + case FFMPEG_SWITCH_OPUS: bytes = ffmpeg_custom_size_switch_opus(data); break; + //case FFMPEG_EA_SCHL: bytes = ffmpeg_custom_size_ea_schl(data); break; + //case FFMPEG_SFH: bytes = ffmpeg_custom_size_sfh(data); break; + default: bytes = ffmpeg_custom_size_standard(data); break; } return bytes; diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils.h b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils.h index 18957e3c3..64461fe9f 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils.h +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils.h @@ -27,9 +27,9 @@ int ffmpeg_custom_read_eaxma(ffmpeg_codec_data *data, uint8_t *buf, int buf_size int64_t ffmpeg_custom_seek_eaxma(ffmpeg_codec_data *data, int64_t virtual_offset); int64_t ffmpeg_custom_size_eaxma(ffmpeg_codec_data *data); -int ffmpeg_custom_read_wwise_opus(ffmpeg_codec_data *data, uint8_t *buf, int buf_size); -int64_t ffmpeg_custom_seek_wwise_opus(ffmpeg_codec_data *data, int64_t virtual_offset); -int64_t ffmpeg_custom_size_wwise_opus(ffmpeg_codec_data *data); +int ffmpeg_custom_read_switch_opus(ffmpeg_codec_data *data, uint8_t *buf, int buf_size); +int64_t ffmpeg_custom_seek_switch_opus(ffmpeg_codec_data *data, int64_t virtual_offset); +int64_t ffmpeg_custom_size_switch_opus(ffmpeg_codec_data *data); //int ffmpeg_custom_read_ea_schl(ffmpeg_codec_data *data, uint8_t *buf, int buf_size); //int64_t ffmpeg_custom_seek_ea_schl(ffmpeg_codec_data *data, int64_t virtual_offset); diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils_ea_xma.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils_ea_xma.c index 84e69fd73..6c79a60b4 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils_ea_xma.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils_ea_xma.c @@ -3,58 +3,121 @@ #ifdef VGM_USE_FFMPEG -#define EAXMA_XMA_BLOCK_SIZE 0x800 +#define EAXMA_XMA_MAX_PACKETS_PER_SNS_BLOCK 3 /* only seen up to 3 (Dante's Inferno) */ +#define EAXMA_XMA_MAX_STREAMS_PER_SNS_BLOCK 4 /* XMA2 max is 8ch = 4 * 2ch */ +#define EAXMA_XMA_PACKET_SIZE 0x800 +#define EAXMA_XMA_BUFFER_SIZE (EAXMA_XMA_MAX_PACKETS_PER_SNS_BLOCK * EAXMA_XMA_MAX_STREAMS_PER_SNS_BLOCK * EAXMA_XMA_PACKET_SIZE) /** - * EA-XMA is XMA with padding removed (so a real 0x450 block would be padded to a virtual 0x800 block). - * //todo missing multichannel (packet multistream) support, unknown layout + * EA-XMA is XMA2 with padding removed (so a real 0x450 block would be padded to a virtual 0x800 block). + * Each EA-XMA SNS block contains 1~3 packets per stream, and multistream uses fully separate streams + * (no packet_skip set). We'll pad and reinterleave packets so it resembles standard XMA2. + * + * XMA2 data layout (XMA1 is the same but doesn't use blocks, they are only for seeking): + * - frames (containing 1..4 subframes): decode into 128*4 samples + * - packets: size 0x800, containing N frames (last frame can spill into next packet), must be padded + * - blocks: fixed size, containing N packets (last packet's frames won't spill into next block) + * - stream: N interleaved packets (1/2ch) for multichannel (Nch) audio. Interleave is not fixed: + * at file start/new block has one packet per stream, then must follow the "packet_skip" value + * in the XMA packet header to find its next packet (skiping packets from other streams). + * ex.: s1_p1 skip1, s2_p1 skip2, s1_p2 skip0 s1_p3 skip1, s2_p2 skip1, s1_p4... */ +static int get_block_max_packets(int num_streams, off_t packets_offset, STREAMFILE * streamfile); + int ffmpeg_custom_read_eaxma(ffmpeg_codec_data *data, uint8_t *buf, int buf_size) { - uint8_t v_buf[0x8000]; /* intermediate buffer, could be simplified */ + uint8_t v_buf[EAXMA_XMA_BUFFER_SIZE]; /* intermediate buffer, could be simplified */ int buf_done = 0; uint64_t real_offset = data->real_offset; uint64_t virtual_offset = data->virtual_offset - data->header_size; uint64_t virtual_base = data->virtual_base; + /* EA-XMA always uses late XMA2 streams (2ch + ... + 1/2ch) */ + int num_streams = (data->config.channels / 2) + (data->config.channels % 2 ? 1 : 0); - /* read and transform SNS/EA-XMA block into XMA block by adding padding */ + /* read and transform SNS/EA-XMA blocks into XMA packets */ while (buf_done < buf_size) { - int bytes_to_copy; - size_t data_size, extra_size = 0, gap_size = 0; + int s, p, bytes_to_copy, max_packets; + size_t data_size = 0, gap_size = 0; size_t block_size = read_32bitBE(real_offset, data->streamfile); - /* 0x04(4): some kind of size? 0x08(4): decoded samples */ + /* 0x04(4): decoded samples */ + off_t packets_offset = real_offset + 0x08; - /* setup */ - data_size = (block_size & 0x00FFFFFF) - 0x0c; //todo last block size may be slightly off? - if (data_size % EAXMA_XMA_BLOCK_SIZE) /* aligned padding */ - extra_size = EAXMA_XMA_BLOCK_SIZE - (data_size % EAXMA_XMA_BLOCK_SIZE); - if (buf_done == 0) /* first read */ - gap_size = virtual_offset - virtual_base; /* might start a few bytes into the block */ + max_packets = get_block_max_packets(num_streams, packets_offset, data->streamfile); + if (max_packets == 0) goto fail; - if (data_size + extra_size > 0x8000) { - VGM_LOG("EA-XMA: total size bigger than buffer at %lx\n", (off_t)real_offset); - return 0; + if (max_packets * num_streams * EAXMA_XMA_PACKET_SIZE > EAXMA_XMA_BUFFER_SIZE) { + VGM_LOG("EA XMA: block too big at %lx\n", (off_t)real_offset); + goto fail; } - bytes_to_copy = data_size + extra_size - gap_size; + /* data is divided into a sub-block per stream (N packets), can be smaller than block_size (= has padding) + * copy XMA data re-interleaving for multichannel. To simplify some calcs fills the same number of packets + * per stream and adjusts packet headers (see above for XMA2 multichannel layout). */ + //to-do this doesn't make correct blocks sizes (but blocks are not needed to decode) + for (s = 0; s < num_streams; s++) { + size_t packets_size; + size_t packets_size4 = read_32bitBE(packets_offset, data->streamfile); /* size * 4, no idea */ + + packets_size = (packets_size4 / 4) - 0x04; + + /* Re-interleave all packets in order, one per stream. If one stream has more packets than + * others we add empty packets to keep the same number for all, avoiding packet_skip calcs */ + for (p = 0; p < max_packets; p++) { + off_t packet_offset = packets_offset + 0x04 + p * EAXMA_XMA_PACKET_SIZE; /* can be off but will copy 0 */ + off_t v_buf_offset = p * EAXMA_XMA_PACKET_SIZE * num_streams + s * EAXMA_XMA_PACKET_SIZE; + size_t packet_to_do = packets_size - p * EAXMA_XMA_PACKET_SIZE; + size_t extra_size = 0; + uint32_t header; + + if (packets_size < p * EAXMA_XMA_PACKET_SIZE) + packet_to_do = 0; /* empty packet */ + else if (packet_to_do > EAXMA_XMA_PACKET_SIZE) + packet_to_do = EAXMA_XMA_PACKET_SIZE; + + /* padding will be full size if packet_to_do is 0 */ + if (packet_to_do < EAXMA_XMA_PACKET_SIZE) + extra_size = EAXMA_XMA_PACKET_SIZE - (packet_to_do % EAXMA_XMA_PACKET_SIZE); + + /* copy data (or fully pad if empty packet) */ + read_streamfile(v_buf + v_buf_offset, packet_offset, packet_to_do, data->streamfile); + memset(v_buf + v_buf_offset + packet_to_do, 0xFF, extra_size); /* add padding, typically 0xFF */ + + /* rewrite packet header to add packet skips for multichannel (EA XMA streams are fully separate and have none) + * header bits: 6=num_frames, 15=first_frame_bits_offset, 3=metadata, 8=packet_skip */ + if (packet_to_do == 0) + header = 0x3FFF800; /* new empty packet header (0 num_frames, first_frame_bits_offset set to max) */ + else + header = (uint32_t)read_32bitBE(packet_offset, data->streamfile); + + /* get base header + change packet_skip since we know interleave is always 1 packet per stream */ + header = (header & 0xFFFFFF00) | ((header & 0x000000FF) + num_streams - 1); + put_32bitBE(v_buf + v_buf_offset, header); + } + + packets_offset += (packets_size4 / 4); + } + + if (buf_done == 0) /* first read */ + gap_size = virtual_offset - virtual_base; /* might start a few bytes into the XMA */ + + data_size = max_packets * num_streams * EAXMA_XMA_PACKET_SIZE; + + bytes_to_copy = data_size - gap_size; if (bytes_to_copy > buf_size - buf_done) bytes_to_copy = buf_size - buf_done; - /* transform */ - read_streamfile(v_buf, real_offset + 0x0c, data_size, data->streamfile); - memset(v_buf + data_size, 0xFF, extra_size); /* padding can be any value, typically 0xFF */ + /* pad + copy */ memcpy(buf + buf_done, v_buf + gap_size, bytes_to_copy); + buf_done += bytes_to_copy; /* move when block is fully done */ - if (data_size + extra_size == bytes_to_copy + gap_size) { + if (data_size == bytes_to_copy + gap_size) { real_offset += (block_size & 0x00FFFFFF); - virtual_base += data_size + extra_size; + virtual_base += data_size; } - buf_done += bytes_to_copy; - /* exit on last block just in case, though should reach file size */ if (block_size & 0x80000000) break; @@ -64,6 +127,9 @@ int ffmpeg_custom_read_eaxma(ffmpeg_codec_data *data, uint8_t *buf, int buf_size data->real_offset = real_offset; data->virtual_base = virtual_base; return buf_size; + +fail: + return 0; } int64_t ffmpeg_custom_seek_eaxma(ffmpeg_codec_data *data, int64_t virtual_offset) { @@ -89,8 +155,8 @@ int64_t ffmpeg_custom_seek_eaxma(ffmpeg_codec_data *data, int64_t virtual_offset size_t block_size = read_32bitBE(real_offset, data->streamfile); data_size = (block_size & 0x00FFFFFF) - 0x0c; - if (data_size % EAXMA_XMA_BLOCK_SIZE) - extra_size = EAXMA_XMA_BLOCK_SIZE - (data_size % EAXMA_XMA_BLOCK_SIZE); + if (data_size % EAXMA_XMA_PACKET_SIZE) + extra_size = EAXMA_XMA_PACKET_SIZE - (data_size % EAXMA_XMA_PACKET_SIZE); /* stop if virtual_offset lands inside current block */ if (data_size + extra_size > virtual_offset) @@ -117,26 +183,32 @@ int64_t ffmpeg_custom_size_eaxma(ffmpeg_codec_data *data) { } /* needed to know in meta for fake RIFF */ -size_t ffmpeg_get_eaxma_virtual_size(off_t real_offset, size_t real_size, STREAMFILE *streamFile) { +size_t ffmpeg_get_eaxma_virtual_size(int channels, off_t real_offset, size_t real_size, STREAMFILE *streamFile) { size_t virtual_size = 0; + size_t real_end_offset = real_offset + real_size; + /* EA-XMA always uses late XMA2 streams (2ch + ... + 1/2ch) */ + int num_streams = (channels / 2) + (channels % 2 ? 1 : 0); + /* count all SNS/EAXMA blocks size + padding size */ - while (real_offset < real_size) { - size_t data_size; - size_t block_size = read_32bitBE(real_offset, streamFile); - - data_size = (block_size & 0x00FFFFFF) - 0x0c; + while (real_offset < real_end_offset) { + int max_packets; + size_t block_size = read_32bitBE(real_offset + 0x00, streamFile); + /* 0x04(4): decoded samples */ + off_t packets_offset = real_offset + 0x08; if ((block_size & 0xFF000000) && !(block_size & 0x80000000)) { VGM_LOG("EA-XMA: unknown flag found at %lx\n", (off_t)real_offset); goto fail; } - real_offset += (block_size & 0x00FFFFFF); + max_packets = get_block_max_packets(num_streams, packets_offset, streamFile); + if (max_packets == 0) goto fail; - virtual_size += data_size; - if (data_size % EAXMA_XMA_BLOCK_SIZE) /* XMA block padding */ - virtual_size += EAXMA_XMA_BLOCK_SIZE - (data_size % EAXMA_XMA_BLOCK_SIZE); + /* fixed data_size per block for multichannel, see reads */ + virtual_size += max_packets * num_streams * EAXMA_XMA_PACKET_SIZE; + + real_offset += (block_size & 0x00FFFFFF); /* exit on last block just in case, though should reach real_size */ if (block_size & 0x80000000) @@ -147,7 +219,33 @@ size_t ffmpeg_get_eaxma_virtual_size(off_t real_offset, size_t real_size, STREAM fail: return 0; +} +/* a block can have N streams each with a varying number of packets, get max */ +static int get_block_max_packets(int num_streams, off_t packets_offset, STREAMFILE * streamfile) { + int s; + int max_packets = 0; + + for (s = 0; s < num_streams; s++) { + size_t packets_size; + size_t packets_size4 = read_32bitBE(packets_offset, streamfile); /* size * 4, no idea */ + int num_packets; + + if (packets_size4 == 0) { + VGM_LOG("EA XMA: null packets in stream %i at %lx\n", s, (off_t)packets_offset); + goto fail; + } + packets_size = (packets_size4 / 4) - 0x04; + + num_packets = (int)(packets_size / EAXMA_XMA_PACKET_SIZE) + 1; + if (num_packets > max_packets) + max_packets = num_packets; + } + + return max_packets; + +fail: + return 0; } #endif diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils_wwise_opus.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils_switch_opus.c similarity index 90% rename from Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils_wwise_opus.c rename to Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils_switch_opus.c index 377701328..d8ce46db4 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils_wwise_opus.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils_switch_opus.c @@ -44,7 +44,7 @@ fail: } -int ffmpeg_custom_read_wwise_opus(ffmpeg_codec_data *data, uint8_t *buf, int buf_size) { +int ffmpeg_custom_read_switch_opus(ffmpeg_codec_data *data, uint8_t *buf, int buf_size) { uint8_t v_buf[0x8000]; /* intermediate buffer, could be simplified */ int buf_done = 0; uint64_t real_offset = data->real_offset; @@ -98,7 +98,7 @@ int ffmpeg_custom_read_wwise_opus(ffmpeg_codec_data *data, uint8_t *buf, int buf return buf_size; } -int64_t ffmpeg_custom_seek_wwise_opus(ffmpeg_codec_data *data, int64_t virtual_offset) { +int64_t ffmpeg_custom_seek_switch_opus(ffmpeg_codec_data *data, int64_t virtual_offset) { int64_t real_offset, virtual_base; int64_t current_virtual_offset = data->virtual_offset; @@ -138,13 +138,13 @@ int64_t ffmpeg_custom_seek_wwise_opus(ffmpeg_codec_data *data, int64_t virtual_o return virtual_offset; } -int64_t ffmpeg_custom_size_wwise_opus(ffmpeg_codec_data *data) { +int64_t ffmpeg_custom_size_switch_opus(ffmpeg_codec_data *data) { uint64_t real_offset = data->real_start; - uint64_t real_size = data->real_size; + uint64_t real_end_offset = data->real_start + data->real_size; uint64_t virtual_size = data->header_size; /* count all Wwise Opus blocks size + OggS page size */ - while (real_offset < real_size) { + while (real_offset < real_end_offset) { size_t extra_size; size_t data_size = read_32bitBE(real_offset, data->streamfile); /* 0x00: data size, 0x04: ? (not a sequence or CRC), 0x08+: data */ @@ -159,7 +159,23 @@ int64_t ffmpeg_custom_size_wwise_opus(ffmpeg_codec_data *data) { return virtual_size; } +size_t switch_opus_get_samples(off_t offset, size_t data_size, int sample_rate, STREAMFILE *streamFile) { + size_t num_samples = 0; + off_t end_offset = offset + data_size; + /* count by reading all frames */ + while (offset < end_offset) { + uint8_t buf[4]; + size_t block_size = read_32bitBE(offset, streamFile); + + read_streamfile(buf, offset+4, 4, streamFile); + num_samples += get_opus_samples_per_frame(buf, sample_rate); + + offset += 0x08 + block_size; + } + + return num_samples; +} /* ************************************************** */ @@ -316,8 +332,8 @@ fail: static size_t make_opus_comment(uint8_t * buf, int buf_size) { size_t comment_size; int vendor_string_length, user_comment_0_length; - char * vendor_string = "libopus 1.0.2"; - char * user_comment_0_string = "ENCODER=opusenc from opus-tools 0.1.6"; + char * vendor_string = "vgmstream"; + char * user_comment_0_string = "vgmstream Opus converter"; vendor_string_length = strlen(vendor_string); user_comment_0_length = strlen(user_comment_0_string); @@ -342,5 +358,4 @@ fail: return 0; } - #endif diff --git a/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c index 47c69cd09..3a8e813a1 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c @@ -87,7 +87,7 @@ void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int chan } } -/* decodes u-law (ITU G.711 non-linear PCM) */ +/* decodes u-law (ITU G.711 non-linear PCM), from g711.c */ void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; @@ -119,6 +119,40 @@ void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, } } +/* decodes a-law (ITU G.711 non-linear PCM), from g711.c */ +void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + int sign, segment, quantization, sample; + + + for (i=first_sample,sample_count=0; ioffset+i,stream->streamfile); + + alawbyte ^= 0x55; + sign = (alawbyte & 0x80); + segment = (alawbyte & 0x70) >> 4; /* exponent */ + quantization = alawbyte & 0x0F; /* mantissa */ + + sample = (quantization << 4); + switch (segment) { + case 0: + sample += 8; + break; + case 1: + sample += 0x108; + break; + default: + sample += 0x108; + sample <<= segment - 1; + break; + } + sample = (sign) ? sample : -sample; + + outbuf[sample_count] = sample; + } +} + void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) { int i, sample_count; int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE; diff --git a/Frameworks/vgmstream/vgmstream/src/formats.c b/Frameworks/vgmstream/vgmstream/src/formats.c index 658bc7b53..259869641 100644 --- a/Frameworks/vgmstream/vgmstream/src/formats.c +++ b/Frameworks/vgmstream/vgmstream/src/formats.c @@ -32,6 +32,7 @@ static const char* extension_list[] = { //"aiff", //common "aix", "akb", + "al2", "amts", //fake extension (to be removed) "ao", //txth/reserved [Cloudphobia (PC)] "as4", @@ -200,6 +201,7 @@ static const char* extension_list[] = { "ogl", "oma", //FFmpeg, not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA) "omu", + "opus", "otm", "p1d", //txth/reserved [Farming Simulator 18 (3DS)] @@ -409,6 +411,7 @@ static const coding_info coding_info_list[] = { {coding_PCM8_int, "8-bit PCM with 1 byte interleave"}, {coding_PCM8_SB_int, "8-bit PCM with sign bit, 1 byte interleave"}, {coding_ULAW, "8-bit u-Law"}, + {coding_ALAW, "8-bit a-Law"}, {coding_PCMFLOAT, "32-bit float PCM"}, {coding_CRI_ADX, "CRI ADX 4-bit ADPCM"}, {coding_CRI_ADX_exp, "CRI ADX 4-bit ADPCM with exponential scale"}, @@ -638,9 +641,9 @@ static const meta_info meta_info_list[] = { {meta_FSB4, "FMOD Sample Bank (FSB4) Header"}, {meta_FSB5, "FMOD Sample Bank (FSB5) Header"}, {meta_RWX, "RWX Header"}, - {meta_XWB, "Microsoft XWB Header"}, + {meta_XWB, "Microsoft XWB header"}, {meta_PS2_XA30, "Reflections XA30 PS2 header"}, - {meta_MUSC, "MUSC Header"}, + {meta_MUSC, "Krome MUSC header"}, {meta_MUSX_V004, "MUSX / Version 004 Header"}, {meta_MUSX_V005, "MUSX / Version 005 Header"}, {meta_MUSX_V006, "MUSX / Version 006 Header"}, @@ -811,7 +814,7 @@ static const meta_info meta_info_list[] = { {meta_FFW, "Freedom Fighters BGM header"}, {meta_DSP_DSPW, "DSPW dsp header"}, {meta_PS2_JSTM, "JSTM Header"}, - {meta_PS3_XVAG, "XVAG Header"}, + {meta_XVAG, "Sony XVAG header"}, {meta_PS3_CPS, "tri-Crescendo CPS Header"}, {meta_SQEX_SCD, "Square-Enix SCD header"}, {meta_NGC_NST_DSP, "Animaniacs NST header"}, @@ -888,6 +891,8 @@ static const meta_info meta_info_list[] = { {meta_BINK, "RAD Game Tools Bink header"}, {meta_EA_SNU, "Electronic Arts SNU header"}, {meta_AWC, "Rockstar AWC header"}, + {meta_NSW_OPUS, ".OPUS header"}, + {meta_PC_AL2, "Illwinter Game Design AL2 raw header"}, #ifdef VGM_USE_VORBIS {meta_OGG_VORBIS, "Ogg Vorbis"}, diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_snu.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_snu.c index c21a72523..31fd41eb4 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ea_snu.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_snu.c @@ -18,15 +18,15 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { /* check header (the first 0x10 are BE/LE depending on platform) */ /* 0x00(1): related to sample rate? (03=48000) - * 0x01(1): flags? (when set seems to be a bank and has extra data before start_offset) //todo + * 0x01(1): flags/count? (when set has extra block data before start_offset) * 0x02(1): always 0? * 0x03(1): channels? (usually matches but rarely may be 0) * 0x04(4): some size, maybe >>2 ~= number of frames * 0x08(4): start offset - * 0x0c(4): some sub-offset? (0x20, found when 0x01 is set) */ + * 0x0c(4): some sub-offset? (0x20, found when @0x01 is set) */ - /* use start offset as endianness flag */ - if ((uint32_t)read_32bitLE(0x08,streamFile) > 0x00F00000) { + /* use start_offset as endianness flag */ + if ((uint32_t)read_32bitLE(0x08,streamFile) > 0x0000FFFF) { read_32bit = read_32bitBE; } else { read_32bit = read_32bitLE; @@ -48,6 +48,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { #if 0 //todo not working ok with blocks in XAS + //todo check if EA-XMA loops (Dante's Inferno doesn't) if (flags & 0x60) { /* full loop, seen in ambient tracks */ loop_flag = 1; loop_start = 0; @@ -81,7 +82,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { vgmstream->meta_type = meta_EA_SNU; switch(codec) { - case 0x04: /* "Xas1": EA-XAS (Dead Space) */ + case 0x04: /* "Xas1": EA-XAS (Dead Space PC/PS3) */ vgmstream->coding_type = coding_EA_XAS; vgmstream->layout_type = layout_ea_sns_blocked; break; @@ -112,8 +113,8 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { ffmpeg_custom_config cfg; stream_size = get_streamfile_size(streamFile) - start_offset; - virtual_size = ffmpeg_get_eaxma_virtual_size(start_offset,stream_size, streamFile); - block_size = 0x8000; /* ? */ + virtual_size = ffmpeg_get_eaxma_virtual_size(vgmstream->channels, start_offset,stream_size, streamFile); + block_size = 0x10000; /* todo unused and not correctly done by the parser */ block_count = stream_size / block_size + (stream_size % block_size ? 1 : 0); bytes = ffmpeg_make_riff_xma2(buf, 0x100, vgmstream->num_samples, virtual_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); @@ -122,6 +123,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { memset(&cfg, 0, sizeof(ffmpeg_custom_config)); cfg.type = FFMPEG_EA_XMA; cfg.virtual_size = virtual_size; + cfg.channels = vgmstream->channels; vgmstream->codec_data = init_ffmpeg_config(streamFile, buf,bytes, start_offset,stream_size, &cfg); if (!vgmstream->codec_data) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb.c index 733ae2932..cd84c40cf 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb.c @@ -332,7 +332,7 @@ VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) { uint8_t buf[FAKE_RIFF_BUFFER_SIZE]; size_t bytes, block_size, block_count; /* not accurate but not needed by FFmpeg */ - block_size = 2048; + block_size = 0x8000; /* FSB default */ block_count = fsbh.datasize / block_size; /* read_32bitLE(custom_data_offset +0x14) -1? */ /* make a fake riff so FFmpeg can parse the XMA2 */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c index f358cf31d..f6395b690 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c @@ -251,13 +251,13 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) { #ifdef VGM_USE_FFMPEG case 0x0A: {/* FMOD_SOUND_FORMAT_XMA */ - uint8_t buf[100]; + uint8_t buf[0x100]; int bytes, block_size, block_count; - block_size = 0x10000; /* XACT default */ + block_size = 0x8000; /* FSB default */ block_count = StreamSize / block_size + (StreamSize % block_size ? 1 : 0); - bytes = ffmpeg_make_riff_xma2(buf, 100, vgmstream->num_samples, StreamSize, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); + bytes = ffmpeg_make_riff_xma2(buf, 0x100, vgmstream->num_samples, StreamSize, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); if (bytes <= 0) goto fail; vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, StartOffset,StreamSize); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca.c b/Frameworks/vgmstream/vgmstream/src/meta/hca.c index 7417c225d..2f99ab2eb 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca.c @@ -94,8 +94,8 @@ fail: /* Tries to find the decryption key from a list. Simply decodes a few frames and checks if there aren't too many * clipped samples, as it's common for invalid keys (though possible with valid keys in poorly mastered files). */ static void find_hca_key(hca_codec_data * hca_data, clHCA * hca, uint8_t * buffer, int header_size, unsigned int * out_key1, unsigned int * out_key2) { - sample testbuf[clHCA_samplesPerBlock]; - int i; + sample *testbuf = NULL, *temp; + int i, j, bufsize = 0, tempsize; size_t keys_length = sizeof(hcakey_list) / sizeof(hcakey_info); int min_clip_count = -1; @@ -123,13 +123,23 @@ static void find_hca_key(hca_codec_data * hca_data, clHCA * hca, uint8_t * buffe clHCA_clear(hca, key1, key2); if (clHCA_Decode(hca, buffer, header_size, 0) < 0) continue; if (clHCA_getInfo(hca, &hca_data->info) < 0) continue; + if (hca_data->info.channelCount > 32) continue; /* nonsense don't alloc too much */ + tempsize = sizeof(sample) * clHCA_samplesPerBlock * hca_data->info.channelCount; + if (tempsize > bufsize) { /* should happen once */ + temp = (sample *)realloc(testbuf, tempsize); + if (!temp) goto end; + testbuf = temp; + bufsize = tempsize; + } /* test enough frames, but not too many */ while (f < HCA_KEY_MAX_TEST_FRAMES && f < hca_data->info.blockCount) { - decode_hca(hca_data, testbuf, clHCA_samplesPerBlock, hca_data->info.channelCount); + j = clHCA_samplesPerBlock; + decode_hca(hca_data, testbuf, j, hca_data->info.channelCount); - for (s = 0; s < clHCA_samplesPerBlock; s++) { + j *= hca_data->info.channelCount; + for (s = 0; s < j; s++) { if (testbuf[s] != 0x0000 && testbuf[s] != 0xFFFF) sample_count++; /* ignore upper/lower blank samples */ @@ -165,7 +175,9 @@ static void find_hca_key(hca_codec_data * hca_data, clHCA * hca, uint8_t * buffe hca_data->sample_ptr = clHCA_samplesPerBlock; read_streamfile(buffer, hca_data->start, header_size, hca_data->streamfile); +end: VGM_LOG("HCA: best key=%08x%08x (clips=%i)\n", best_key2,best_key1, min_clip_count); *out_key2 = best_key2; *out_key1 = best_key1; + free(testbuf);//free(temp); } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h index 3d1cba9b4..48ac33945 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h @@ -5,7 +5,11 @@ typedef struct { uint64_t key; } hcakey_info; -/* CRI's tools expect an unsigned 64 bit number, but keys are commonly found online in hex form */ +/** + * List of known keys, extracted from the game files (mostly found in 2ch.net). + * CRI's tools expect an unsigned 64 bit number string, but keys are commonly found online in hex form. + * Keys only use 56 bits though, so the upper 8 bits can be ignored. + */ static const hcakey_info hcakey_list[] = { // HCA Decoder default @@ -14,8 +18,6 @@ static const hcakey_info hcakey_list[] = { // Phantasy Star Online 2 (multi?) // used by most console games {0xCC55463930DBE1AB}, // CC55463930DBE1AB / 14723751768204501419 - // variation from VGAudio, but some 2ch poster says the above works with CRI's tools; seems to decode the same - {24002584467202475}, // 0055463930DBE1AB // Old Phantasy Star Online 2 (multi?) {61891147883431481}, // 30DBE1ABCC554639 diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h index fbbb0699c..a8da4c878 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -536,7 +536,7 @@ VGMSTREAM * init_vgmstream_dsp_dspw(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_ps2_jstm(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_ps3_xvag(STREAMFILE* streamFile); +VGMSTREAM * init_vgmstream_xvag(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_ps3_cps(STREAMFILE* streamFile); @@ -645,7 +645,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_x360_nub(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_nub_xma(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_x360_pasx(STREAMFILE *streamFile); @@ -682,4 +682,8 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_awc(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_nsw_opus(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_pc_al2(STREAMFILE * streamFile); + #endif /*_META_H*/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/musc.c b/Frameworks/vgmstream/vgmstream/src/meta/musc.c index c0483a7ee..0e80203bb 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/musc.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/musc.c @@ -1,73 +1,50 @@ #include "meta.h" #include "../util.h" +#include "../coding/coding.h" +#include "../layout/layout.h" -/* MUSC (near all Spyro games and many other using this) */ +/* MUSC - from Krome's PS2 games (The Legend of Spyro, Ty the Tasmanian Tiger) */ VGMSTREAM * init_vgmstream_musc(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - int loop_flag; - int channel_count; + int loop_flag, channel_count; off_t start_offset; + size_t data_size; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("mus",filename_extension(filename)) && - strcasecmp("musc",filename_extension(filename))) - goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x4D555343) /* MUSC */ - goto fail; - - /* check file size */ - if ((read_32bitLE(0x10,streamFile)+read_32bitLE(0x14,streamFile)) != (get_streamfile_size(streamFile))) - goto fail; - - loop_flag = 0; - channel_count = 2; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; + /* .mus is the real extension, .musc is the header ID */ + if (!check_extensions(streamFile,"mus,musc")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x4D555343) /* "MUSC" */ + goto fail; start_offset = read_32bitLE(0x10,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->channels = channel_count; - vgmstream->sample_rate = (uint16_t) read_16bitLE(0x06,streamFile); - - vgmstream->num_samples = read_32bitLE(0x14,streamFile)/channel_count/16*28; + data_size = read_32bitLE(0x14,streamFile); + if (start_offset + data_size != get_streamfile_size(streamFile)) + goto fail; + /* always does full loops unless it ends in silence */ + loop_flag = read_32bitBE(get_streamfile_size(streamFile) - 0x10,streamFile) != 0x0C000000; + channel_count = 2; -#if 0 - if (loop_flag) - { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = (read_32bitLE(0x14,streamFile))*28/16/channel_count; - } -#endif - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0x18,streamFile)/2; + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = (uint16_t)read_16bitLE(0x06,streamFile); + vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count); + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = vgmstream->num_samples; + vgmstream->meta_type = meta_MUSC; + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0x18,streamFile) / 2; - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - } - } + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/nsw_opus.c b/Frameworks/vgmstream/vgmstream/src/meta/nsw_opus.c new file mode 100644 index 000000000..9339d477d --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/nsw_opus.c @@ -0,0 +1,64 @@ +#include "meta.h" +#include "../util.h" +#include "../coding/coding.h" + +/* .OPUS - from Lego City Undercover (Switch) */ +VGMSTREAM * init_vgmstream_nsw_opus(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag = 0, channel_count; + + /* check extension, case insensitive */ + if ( !check_extensions(streamFile,"opus")) /* no relation to Ogg Opus */ + goto fail; + + if (read_32bitBE(0x00,streamFile) != 0x01000080) + goto fail; + + start_offset = 0x28; + channel_count = read_8bit(0x09,streamFile); /* assumed */ + /* other values in the header: no idea */ + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = read_32bitLE(0x0c,streamFile); + vgmstream->meta_type = meta_NSW_OPUS; + +#ifdef VGM_USE_FFMPEG + { + uint8_t buf[0x100]; + size_t bytes, skip, data_size; + ffmpeg_custom_config cfg; + + data_size = get_streamfile_size(streamFile) - start_offset; + skip = 0; //todo + + bytes = ffmpeg_make_opus_header(buf,0x100, vgmstream->channels, skip, vgmstream->sample_rate); + if (bytes <= 0) goto fail; + + memset(&cfg, 0, sizeof(ffmpeg_custom_config)); + cfg.type = FFMPEG_SWITCH_OPUS; + + vgmstream->codec_data = init_ffmpeg_config(streamFile, buf,bytes, start_offset,data_size, &cfg); + if (!vgmstream->codec_data) goto fail; + + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; + + vgmstream->num_samples = switch_opus_get_samples(start_offset, data_size, vgmstream->sample_rate, streamFile); + } +#else + goto fail; +#endif + + /* open the file for reading */ + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/x360_nub.c b/Frameworks/vgmstream/vgmstream/src/meta/nub_xma.c similarity index 95% rename from Frameworks/vgmstream/vgmstream/src/meta/x360_nub.c rename to Frameworks/vgmstream/vgmstream/src/meta/nub_xma.c index 3c4cae956..cb33d551c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/x360_nub.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/nub_xma.c @@ -2,7 +2,7 @@ #include "../coding/coding.h" /* Namco NUB xma - from Tekken 6, Galaga Legions DX */ -VGMSTREAM * init_vgmstream_x360_nub(STREAMFILE *streamFile) { +VGMSTREAM * init_vgmstream_nub_xma(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset, chunk_offset; size_t data_size, chunk_size; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/pc_al2.c b/Frameworks/vgmstream/vgmstream/src/meta/pc_al2.c new file mode 100644 index 000000000..33f01c9d9 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/pc_al2.c @@ -0,0 +1,40 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* AL" - headerless a-law, found in Conquest of Elysium 3 (PC) */ +VGMSTREAM * init_vgmstream_pc_al2(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag = 0, channel_count; + + + if ( !check_extensions(streamFile,"al2")) + goto fail; + + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = 22050; + vgmstream->coding_type = coding_ALAW; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x01; + vgmstream->meta_type = meta_PC_AL2; + vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(streamFile), channel_count, 8); + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + start_offset = 0; + + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_rxws.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_rxws.c index 93701d595..01b0ea904 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_rxws.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_rxws.c @@ -8,7 +8,7 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) { STREAMFILE * streamHeader = NULL; off_t start_offset, chunk_offset, name_offset = 0; size_t data_size, chunk_size; - int loop_flag = 0, channel_count, is_separate, type, sample_rate; + int loop_flag = 0, channel_count, is_separate = 0, type, sample_rate; int32_t loop_start, loop_end; int total_streams, target_stream = streamFile->stream_index; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c b/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c index e31ac99da..07cfba50d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c @@ -11,7 +11,7 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) { off_t start_offset, data_offset, chunk_offset, name_offset = 0; size_t data_size; - int is_sgx, is_sgb; + int is_sgx, is_sgb = 0; int loop_flag, channels, type; int sample_rate, num_samples, loop_start_sample, loop_end_sample; int total_streams, target_stream = streamFile->stream_index; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/vawx.c b/Frameworks/vgmstream/vgmstream/src/meta/vawx.c index 9812f50b1..befdaef21 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/vawx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/vawx.c @@ -1,14 +1,11 @@ #include "meta.h" #include "../coding/coding.h" -#define FAKE_RIFF_BUFFER_SIZE 100 -/** - * VAWX - found in feelplus games: No More Heroes Heroes Paradise, Moon Diver - */ +/* VAWX - found in feelplus games (No More Heroes Heroes Paradise, Moon Diver) */ VGMSTREAM * init_vgmstream_vawx(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - off_t start_offset, datasize; + off_t start_offset, data_size; int loop_flag = 0, channel_count, type; @@ -52,17 +49,17 @@ VGMSTREAM * init_vgmstream_vawx(STREAMFILE *streamFile) { #ifdef VGM_USE_FFMPEG case 1: { /* XMA2 */ ffmpeg_codec_data *ffmpeg_data = NULL; - uint8_t buf[FAKE_RIFF_BUFFER_SIZE]; + uint8_t buf[0x100]; int32_t bytes, block_size, block_count; - /* todo not accurate (needed for >2ch) */ - datasize = get_streamfile_size(streamFile)-start_offset; - block_size = 2048; - block_count = datasize / block_size; /* read_32bitLE(custom_data_offset +0x14) -1? */ - bytes = ffmpeg_make_riff_xma2(buf, FAKE_RIFF_BUFFER_SIZE, vgmstream->num_samples, datasize, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); + data_size = get_streamfile_size(streamFile)-start_offset; + block_size = 0x10000; /* VAWX default */ + block_count = (uint16_t)read_16bitBE(0x3A, streamFile); /* also at 0x56 */ + + bytes = ffmpeg_make_riff_xma2(buf,0x100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); if (bytes <= 0) goto fail; - ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,datasize); + ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size); if ( !ffmpeg_data ) goto fail; vgmstream->codec_data = ffmpeg_data; vgmstream->coding_type = coding_FFmpeg; @@ -75,22 +72,22 @@ VGMSTREAM * init_vgmstream_vawx(STREAMFILE *streamFile) { } case 7: { /* ATRAC3 */ - uint8_t buf[FAKE_RIFF_BUFFER_SIZE]; + uint8_t buf[0x100]; int32_t bytes, block_size, encoder_delay, joint_stereo, max_samples; - datasize = read_32bitBE(0x54,streamFile); + data_size = read_32bitBE(0x54,streamFile); block_size = 0x98 * vgmstream->channels; joint_stereo = 0; - max_samples = atrac3_bytes_to_samples(datasize, block_size); + max_samples = atrac3_bytes_to_samples(data_size, block_size); encoder_delay = 0x0; //max_samples - vgmstream->num_samples; /* todo not correct */ vgmstream->num_samples = max_samples; /* use calc samples since loop points are too, breaks looping in some files otherwise */ /* make a fake riff so FFmpeg can parse the ATRAC3 */ - bytes = ffmpeg_make_riff_atrac3(buf, FAKE_RIFF_BUFFER_SIZE, vgmstream->num_samples, datasize, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay); + bytes = ffmpeg_make_riff_atrac3(buf,0x100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay); if (bytes <= 0) goto fail; - vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,datasize); + vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c index 435377c9a..ace0ca29b 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c @@ -138,8 +138,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { case 0x0002: ww.codec = IMA; break; /* newer Wwise (conflicts with MSADPCM, probably means "platform's ADPCM") */ //case 0x0011: ww.codec = IMA; break; /* older Wwise (used?) */ case 0x0069: ww.codec = IMA; break; /* older Wwise (Spiderman Web of Shadows X360, LotR Conquest PC) */ - case 0x0161: ww.codec = XWMA; break; - case 0x0162: ww.codec = XWMA; break; + case 0x0161: ww.codec = XWMA; break; /* WMAv2 */ + case 0x0162: ww.codec = XWMA; break; /* WMAPro */ case 0x0165: ww.codec = XMA2; break; /* always with the "XMA2" chunk, Wwise doesn't use XMA1 */ case 0x0166: ww.codec = XMA2; break; case 0x3039: ww.codec = OPUS; break; @@ -265,6 +265,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { cfg.blocksize_1_exp = read_8bit(vorb_offset + block_offsets + 0x00, streamFile); /* small */ cfg.blocksize_0_exp = read_8bit(vorb_offset + block_offsets + 0x01, streamFile); /* big */ } + ww.data_size -= audio_offset; /* detect setup type: * - full inline: ~2009, ex. The King of Fighters XII X360, The Saboteur PC @@ -284,8 +285,6 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { } } - //ww.data_size -= audio_offset; //todo test - vgmstream->codec_data = init_vorbis_custom_codec_data(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg); if (!vgmstream->codec_data) goto fail; } @@ -319,6 +318,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { audio_offset = read_32bit(extra_offset + data_offsets + 0x04, streamFile); /* within data */ cfg.blocksize_1_exp = read_8bit(extra_offset + block_offsets + 0x00, streamFile); /* small */ cfg.blocksize_0_exp = read_8bit(extra_offset + block_offsets + 0x01, streamFile); /* big */ + ww.data_size -= audio_offset; /* Normal packets are used rarely (ex. Oddworld New 'n' Tasty! PSV). They are hard to detect (decoding * will mostly work with garbage results) but we'll try. Setup size and "fmt" bitrate fields may matter too. */ @@ -329,8 +329,6 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { cfg.packet_type = STANDARD; } - //ww.data_size -= audio_offset; //todo test - /* try with the selected codebooks */ vgmstream->codec_data = init_vorbis_custom_codec_data(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg); if (!vgmstream->codec_data) { @@ -436,6 +434,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; + /* manually find total samples, why don't they put this in the header is beyond me */ { ms_sample_data msd; @@ -446,11 +445,14 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { msd.data_size = ww.data_size; if (ww.format == 0x0162) - wmapro_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x0000); + wmapro_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x00E0); else - wma_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x0000); + wma_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x001F); - vgmstream->num_samples = ffmpeg_data->totalSamples; /* ffmpeg_data->totalSamples is approximate from avg-br */ + vgmstream->num_samples = msd.num_samples; + if (!vgmstream->num_samples) + vgmstream->num_samples = ffmpeg_data->totalSamples; /* very wrong, from avg-br */ + //num_samples seem to be found in the last "seek" table entry too, as: entry / channels / 2 } break; @@ -482,7 +484,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { size_t seek_size; vgmstream->num_samples += read_32bit(ww.fmt_offset + 0x18, streamFile); - //todo 0x1c and 0x20: related to samples/looping? + /* 0x1c: null? 0x20: data_size without seek_size */ seek_size = read_32bit(ww.fmt_offset + 0x24, streamFile); start_offset += seek_size; @@ -498,7 +500,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { if (bytes <= 0) goto fail; memset(&cfg, 0, sizeof(ffmpeg_custom_config)); - cfg.type = FFMPEG_WWISE_OPUS; + cfg.type = FFMPEG_SWITCH_OPUS; //cfg.big_endian = ww.big_endian; /* internally BE */ vgmstream->codec_data = init_ffmpeg_config(streamFile, buf,bytes, start_offset,ww.data_size, &cfg); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xma.c b/Frameworks/vgmstream/vgmstream/src/meta/xma.c index 82e495e1d..0dfca0814 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xma.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xma.c @@ -66,13 +66,12 @@ VGMSTREAM * init_vgmstream_xma(STREAMFILE *streamFile) { goto fail; - /* fix samples; for now only XMA1 is fixed, but xmaencode.exe doesn't seem to use XMA2 - * num_samples in the headers, and the values don't look exact */ + /* fix samples; for now only XMA1 is fixed, but XMA2 num_samples don't include skip samples and xmaencode.exe doesn't use it */ if (is_xma1) { ms_sample_data msd; memset(&msd,0,sizeof(ms_sample_data)); - msd.xma_version = 1; + msd.xma_version = is_xma1 ? 1 : 2; msd.channels = channel_count; msd.data_offset = start_offset; msd.data_size = data_size; @@ -81,14 +80,14 @@ VGMSTREAM * init_vgmstream_xma(STREAMFILE *streamFile) { msd.loop_end_b = loop_end_b; msd.loop_start_subframe = loop_subframe & 0xF; /* lower 4b: subframe where the loop starts, 0..4 */ msd.loop_end_subframe = loop_subframe >> 4; /* upper 4b: subframe where the loop ends, 0..3 */ + msd.chunk_offset= chunk_offset; xma_get_samples(&msd, streamFile); num_samples = msd.num_samples; - //skip_samples = msd.skip_samples; loop_start_sample = msd.loop_start_sample; loop_end_sample = msd.loop_end_sample; - /* XMA2 loop/num_samples don't seem to skip_samples */ + /* XMA2 loop/num_samples don't seem to use msd.skip_samples */ } @@ -146,7 +145,8 @@ fail: #if 0 /** * Get real XMA sample rate (from Microsoft docs). - * Info only, not for playback as the encoder adjusts sample rate for looping purposes (sample<>data align). + * Info only, not for playback as the encoder adjusts sample rate for looping purposes (sample<>data align), + * When converting to PCM, xmaencode does use the modified sample rate. */ static int32_t get_xma_sample_rate(int32_t general_rate) { int32_t xma_rate = 48000; /* default XMA */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps3_xvag.c b/Frameworks/vgmstream/vgmstream/src/meta/xvag.c similarity index 96% rename from Frameworks/vgmstream/vgmstream/src/meta/ps3_xvag.c rename to Frameworks/vgmstream/vgmstream/src/meta/xvag.c index 009376ee1..987db2f14 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps3_xvag.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xvag.c @@ -5,7 +5,7 @@ static int ps_adpcm_find_loop_offsets(STREAMFILE *streamFile, int channel_count, off_t start_offset, off_t * loop_start, off_t * loop_end); /* XVAG - Sony's (second party?) format (God of War III, Ratchet & Clank Future, The Last of Us, Uncharted) */ -VGMSTREAM * init_vgmstream_ps3_xvag(STREAMFILE *streamFile) { +VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; int loop_flag = 0, channel_count, codec; @@ -57,7 +57,7 @@ VGMSTREAM * init_vgmstream_ps3_xvag(STREAMFILE *streamFile) { vgmstream->sample_rate = sample_rate; vgmstream->num_samples = num_samples; - vgmstream->meta_type = meta_PS3_XVAG; + vgmstream->meta_type = meta_XVAG; switch (codec) { case 0x06: /* PS ADPCM: God of War III, Uncharted 1/2, Ratchet and Clank Future */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xwb.c b/Frameworks/vgmstream/vgmstream/src/meta/xwb.c index 99f251df1..83c44fe64 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xwb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xwb.c @@ -455,7 +455,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { } - start_offset = xwb.data_offset; + start_offset = xwb.stream_offset; if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) ) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c index 2ef7dbe0d..0c8715821 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c @@ -292,7 +292,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_ffw, init_vgmstream_dsp_dspw, init_vgmstream_ps2_jstm, - init_vgmstream_ps3_xvag, + init_vgmstream_xvag, init_vgmstream_ps3_cps, init_vgmstream_sqex_scd, init_vgmstream_ngc_nst_dsp, @@ -350,7 +350,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_wwise, init_vgmstream_ubi_raki, init_vgmstream_x360_pasx, - init_vgmstream_x360_nub, + init_vgmstream_nub_xma, init_vgmstream_xma, init_vgmstream_sxd, init_vgmstream_ogl, @@ -369,6 +369,8 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_stm, init_vgmstream_ea_snu, init_vgmstream_awc, + init_vgmstream_nsw_opus, + init_vgmstream_pc_al2, init_vgmstream_txth, /* should go at the end (lower priority) */ #ifdef VGM_USE_FFMPEG @@ -981,6 +983,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_PCM8_SB_int: case coding_PCM8_U_int: case coding_ULAW: + case coding_ALAW: case coding_PCMFLOAT: return 1; #ifdef VGM_USE_VORBIS @@ -1140,6 +1143,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_PCM8_SB_int: case coding_PCM8_U_int: case coding_ULAW: + case coding_ALAW: return 1; case coding_PCMFLOAT: return 4; @@ -1378,6 +1382,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do); } break; + case coding_ALAW: + for (chan=0;chanchannels;chan++) { + decode_alaw(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; case coding_PCMFLOAT: for (chan=0;chanchannels;chan++) { decode_pcmfloat(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.h b/Frameworks/vgmstream/vgmstream/src/vgmstream.h index d50a1e149..0f30d0151 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.h @@ -95,6 +95,7 @@ typedef enum { coding_PCM8_SB_int, /* 8-bit PCM, sign bit (others are 2's complement) with sample-level interleave */ coding_ULAW, /* 8-bit u-Law (non-linear PCM) */ + coding_ALAW, /* 8-bit a-Law (non-linear PCM) */ coding_PCMFLOAT, /* 32 bit float PCM */ @@ -361,7 +362,7 @@ typedef enum { meta_RWX, /* Air Force Delta Storm (XBOX) */ meta_XWB, /* Microsoft XACT framework (Xbox, X360, Windows) */ meta_PS2_XA30, /* Driver - Parallel Lines (PS2) */ - meta_MUSC, /* Spyro Games, possibly more */ + meta_MUSC, /* Krome PS2 games */ meta_MUSX_V004, /* Spyro Games, possibly more */ meta_MUSX_V005, /* Spyro Games, possibly more */ meta_MUSX_V006, /* Spyro Games, possibly more */ @@ -565,7 +566,7 @@ typedef enum { meta_SQEX_SCD, /* Square-Enix SCD */ meta_NGC_NST_DSP, /* Animaniacs [NGC] */ meta_BAF, /* Bizarre Creations (Blur, James Bond) */ - meta_PS3_XVAG, /* Ratchet & Clank Future: Quest for Booty (PS3) */ + meta_XVAG, /* Ratchet & Clank Future: Quest for Booty (PS3) */ meta_PS3_CPS, /* Eternal Sonata (PS3) */ meta_PS3_MSF, /* MSF header */ meta_NUB_VAG, /* Namco VAG from NUB archives */ @@ -635,6 +636,8 @@ typedef enum { meta_BINK, /* RAD Game Tools BINK audio/video */ meta_EA_SNU, /* Electronic Arts SNU (Dead Space) */ meta_AWC, /* Rockstar AWC (GTA5, RDR) */ + meta_NSW_OPUS, /* Lego City Undercover (Switch) */ + meta_PC_AL2, /* Conquest of Elysium 3 (PC) */ #ifdef VGM_USE_VORBIS meta_OGG_VORBIS, /* Ogg Vorbis */ @@ -1037,8 +1040,8 @@ typedef struct { /* Custom FFMPEG modes */ typedef enum { FFMPEG_STANDARD, /* default FFmpeg */ - FFMPEG_WWISE_OPUS, /* Opus without Ogg layer */ - FFMPEG_EA_XMA, /* XMA with padding removed in SNS blocks */ + FFMPEG_SWITCH_OPUS, /* Opus without Ogg layer */ + FFMPEG_EA_XMA, /* XMA with padding removed and custom streams in SNS blocks */ //FFMPEG_EA_SCHL, /* Normal header+data (ex. ATRAC3) in SCxx blocks */ //FFMPEG_SFH, /* ATRAC3plus header+data in SFH blocks */ //FFMPEG_AWC_XMA, /* XMA data in AWC blocks, 1 streams per channel */ @@ -1048,6 +1051,7 @@ typedef enum { typedef struct { int stream_index; /* FFmpeg's sub-stream (as opposed to an internal stream in custom read/seeks) */ int codec_endian; + int channels; ffmpeg_custom_t type; /* ffmpeg subtype */ size_t virtual_size; /* external value, if meta needs to know/supply it */