From 08c904c201c4ff37fd2c9eb370593ef0ec9bffc3 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Sat, 2 Sep 2023 20:56:12 -0700 Subject: [PATCH] Updated VGMStream to r1866-46-g883d796d Signed-off-by: Christopher Snowhill --- .../libvgmstream.xcodeproj/project.pbxproj | 126 +- .../vgmstream/vgmstream/src/base/decode.c | 16 +- .../vgmstream/vgmstream/src/base/mixing.c | 1076 +---------- .../vgmstream/src/base/mixing_commands.c | 254 +++ .../vgmstream/src/base/mixing_fades.h | 171 ++ .../vgmstream/src/base/mixing_macros.c | 578 ++++++ .../vgmstream/src/base/mixing_priv.h | 52 + .../vgmstream/vgmstream/src/base/render.c | 1 - .../vgmstream/src/coding/adx_decoder.c | 13 +- .../vgmstream/vgmstream/src/coding/coding.h | 4 +- .../vgmstream/src/coding/pcm_decoder.c | 15 + .../vgmstream/src/coding/speex_decoder.c | 34 +- .../vgmstream/src/coding/yamaha_decoder.c | 23 +- Frameworks/vgmstream/vgmstream/src/formats.c | 79 +- .../vgmstream/vgmstream/src/layout/blocked.c | 3 - .../vgmstream/src/layout/blocked_matx.c | 18 - .../vgmstream/vgmstream/src/layout/layout.h | 1 - Frameworks/vgmstream/vgmstream/src/meta/adm.c | 219 +++ .../vgmstream/vgmstream/src/meta/adm3.c | 152 -- Frameworks/vgmstream/vgmstream/src/meta/adx.c | 1 + .../vgmstream/vgmstream/src/meta/bg00.c | 46 + .../vgmstream/vgmstream/src/meta/bnk_sony.c | 1586 +++++++++++------ .../vgmstream/src/meta/{wii_bns.c => bns.c} | 10 +- .../vgmstream/vgmstream/src/meta/btsnd.c | 27 +- .../vgmstream/vgmstream/src/meta/dc_str.c | 165 -- .../vgmstream/vgmstream/src/meta/filp.c | 55 + .../vgmstream/vgmstream/src/meta/fsb5_fev.c | 15 +- .../vgmstream/vgmstream/src/meta/fsb_keys.h | 2 + .../vgmstream/src/meta/{gsp_gsb.c => gsnd.c} | 68 +- .../vgmstream/vgmstream/src/meta/hca_keys.h | 67 + .../vgmstream/vgmstream/src/meta/hgc1.c | 41 + .../vgmstream/vgmstream/src/meta/idtech.c | 126 +- .../vgmstream/vgmstream/src/meta/ivaud.c | 21 +- .../vgmstream/vgmstream/src/meta/meta.h | 26 +- .../vgmstream/vgmstream/src/meta/mus_krome.c | 56 + .../vgmstream/vgmstream/src/meta/ngc_tydsp.c | 72 - .../vgmstream/vgmstream/src/meta/ogg_vorbis.c | 45 +- .../vgmstream/vgmstream/src/meta/ps2_bg00.c | 65 - .../vgmstream/vgmstream/src/meta/ps2_filp.c | 67 - .../vgmstream/vgmstream/src/meta/ps2_hgc1.c | 64 - .../vgmstream/vgmstream/src/meta/ps2_sl3.c | 45 - .../vgmstream/vgmstream/src/meta/ps2_wad.c | 71 - .../vgmstream/vgmstream/src/meta/ps2_wb.c | 64 - .../vgmstream/vgmstream/src/meta/riff.c | 13 + .../vgmstream/vgmstream/src/meta/sdrh.c | 1 + .../vgmstream/vgmstream/src/meta/sgxd.c | 62 +- Frameworks/vgmstream/vgmstream/src/meta/sl3.c | 41 + .../vgmstream/vgmstream/src/meta/snds.c | 112 ++ .../vgmstream/src/meta/{sxd.c => sndx.c} | 6 +- .../vgmstream/vgmstream/src/meta/spsd.c | 39 +- .../vgmstream/vgmstream/src/meta/squeak.c | 446 +++++ .../vgmstream/vgmstream/src/meta/str_sega.c | 142 ++ .../vgmstream/vgmstream/src/meta/str_wav.c | 8 +- .../vgmstream/vgmstream/src/meta/txth.c | 23 +- .../vgmstream/src/meta/txth_streamfile.h | 8 +- .../vgmstream/vgmstream/src/meta/ubi_sb.c | 42 +- Frameworks/vgmstream/vgmstream/src/meta/vag.c | 22 +- Frameworks/vgmstream/vgmstream/src/meta/wb.c | 45 + .../vgmstream/vgmstream/src/meta/wii_mus.c | 124 -- Frameworks/vgmstream/vgmstream/src/meta/xa.c | 3 +- .../vgmstream/vgmstream/src/meta/xa_xa30.c | 7 +- .../vgmstream/vgmstream/src/meta/xbox_ims.c | 61 - Frameworks/vgmstream/vgmstream/src/meta/xss.c | 101 +- .../vgmstream/vgmstream/src/util/endianness.h | 6 +- .../vgmstream/src/util/layout_utils.c | 71 + .../vgmstream/src/util/layout_utils.h | 12 + .../vgmstream/vgmstream/src/util/sf_utils.c | 13 +- .../vgmstream/vgmstream/src/vgmstream.c | 25 +- .../vgmstream/vgmstream/src/vgmstream.h | 1 + .../vgmstream/vgmstream/src/vgmstream_types.h | 32 +- Info.plist.template | 11 +- 71 files changed, 4050 insertions(+), 3067 deletions(-) create mode 100644 Frameworks/vgmstream/vgmstream/src/base/mixing_commands.c create mode 100644 Frameworks/vgmstream/vgmstream/src/base/mixing_fades.h create mode 100644 Frameworks/vgmstream/vgmstream/src/base/mixing_macros.c create mode 100644 Frameworks/vgmstream/vgmstream/src/base/mixing_priv.h create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/adm.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/adm3.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/bg00.c rename Frameworks/vgmstream/vgmstream/src/meta/{wii_bns.c => bns.c} (97%) delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/dc_str.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/filp.c rename Frameworks/vgmstream/vgmstream/src/meta/{gsp_gsb.c => gsnd.c} (64%) create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/hgc1.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/mus_krome.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ngc_tydsp.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ps2_bg00.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ps2_filp.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ps2_hgc1.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ps2_sl3.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ps2_wb.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/sl3.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/snds.c rename Frameworks/vgmstream/vgmstream/src/meta/{sxd.c => sndx.c} (97%) create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/squeak.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/str_sega.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/wb.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/wii_mus.c create mode 100644 Frameworks/vgmstream/vgmstream/src/util/layout_utils.c create mode 100644 Frameworks/vgmstream/vgmstream/src/util/layout_utils.h diff --git a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj index 29b11c8ed..0bd971cd5 100644 --- a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj @@ -94,7 +94,7 @@ 831BA6191EAC61A500CF89B0 /* ogl.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA60F1EAC61A500CF89B0 /* ogl.c */; }; 831BA61A1EAC61A500CF89B0 /* ps2_vds_vdm.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6101EAC61A500CF89B0 /* ps2_vds_vdm.c */; }; 831BA61B1EAC61A500CF89B0 /* sgxd.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6111EAC61A500CF89B0 /* sgxd.c */; }; - 831BA61C1EAC61A500CF89B0 /* sxd.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6121EAC61A500CF89B0 /* sxd.c */; }; + 831BA61C1EAC61A500CF89B0 /* sndx.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6121EAC61A500CF89B0 /* sndx.c */; }; 831BA61D1EAC61A500CF89B0 /* ubi_raki.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6131EAC61A500CF89B0 /* ubi_raki.c */; }; 831BA61F1EAC61A500CF89B0 /* cxs.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6151EAC61A500CF89B0 /* cxs.c */; }; 831BA6211EAC61A500CF89B0 /* pasx.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6171EAC61A500CF89B0 /* pasx.c */; }; @@ -323,7 +323,7 @@ 836F46AE28208735005B9B87 /* blocked_tt_ad.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F46AD28208735005B9B87 /* blocked_tt_ad.c */; }; 836F46B22820874D005B9B87 /* tt_ad.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F46AF2820874D005B9B87 /* tt_ad.c */; }; 836F46B32820874D005B9B87 /* esf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F46B02820874D005B9B87 /* esf.c */; }; - 836F46B42820874D005B9B87 /* adm3.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F46B12820874D005B9B87 /* adm3.c */; }; + 836F46B42820874D005B9B87 /* adm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F46B12820874D005B9B87 /* adm.c */; }; 836F46B7282087A6005B9B87 /* cri_utf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F46B5282087A6005B9B87 /* cri_utf.c */; }; 836F46B8282087A6005B9B87 /* cri_utf.h in Headers */ = {isa = PBXBuildFile; fileRef = 836F46B6282087A6005B9B87 /* cri_utf.h */; }; 836F6B4718BDB8880095E648 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 836F6B4518BDB8880095E648 /* InfoPlist.strings */; }; @@ -375,7 +375,7 @@ 836F6F7918BDC2190095E648 /* dc_asd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E3D18BDC2180095E648 /* dc_asd.c */; }; 836F6F7B18BDC2190095E648 /* dc_idvi.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E3F18BDC2180095E648 /* dc_idvi.c */; }; 836F6F7C18BDC2190095E648 /* dc_kcey.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4018BDC2180095E648 /* dc_kcey.c */; }; - 836F6F7D18BDC2190095E648 /* dc_str.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4118BDC2180095E648 /* dc_str.c */; }; + 836F6F7D18BDC2190095E648 /* str_sega.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4118BDC2180095E648 /* str_sega.c */; }; 836F6F7F18BDC2190095E648 /* dmsg_segh.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4318BDC2180095E648 /* dmsg_segh.c */; }; 836F6F8218BDC2190095E648 /* ea_schl.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4618BDC2180095E648 /* ea_schl.c */; }; 836F6F8518BDC2190095E648 /* exakt_sc.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4918BDC2180095E648 /* exakt_sc.c */; }; @@ -385,7 +385,7 @@ 836F6F8918BDC2190095E648 /* gca.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4D18BDC2180095E648 /* gca.c */; }; 836F6F8A18BDC2190095E648 /* gcsw.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4E18BDC2180095E648 /* gcsw.c */; }; 836F6F8B18BDC2190095E648 /* genh.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4F18BDC2180095E648 /* genh.c */; }; - 836F6F8D18BDC2190095E648 /* gsp_gsb.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E5118BDC2180095E648 /* gsp_gsb.c */; }; + 836F6F8D18BDC2190095E648 /* gsnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E5118BDC2180095E648 /* gsnd.c */; }; 836F6F8E18BDC2190095E648 /* halpst.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E5218BDC2180095E648 /* halpst.c */; }; 836F6F8F18BDC2190095E648 /* his.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E5318BDC2180095E648 /* his.c */; }; 836F6F9118BDC2190095E648 /* ios_psnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E5518BDC2180095E648 /* ios_psnd.c */; }; @@ -419,7 +419,6 @@ 836F6FB518BDC2190095E648 /* ngc_pdt.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7918BDC2180095E648 /* ngc_pdt.c */; }; 836F6FB618BDC2190095E648 /* ngc_sck_dsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7A18BDC2180095E648 /* ngc_sck_dsp.c */; }; 836F6FB718BDC2190095E648 /* ngc_ssm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7B18BDC2180095E648 /* ngc_ssm.c */; }; - 836F6FB818BDC2190095E648 /* ngc_tydsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7C18BDC2180095E648 /* ngc_tydsp.c */; }; 836F6FBA18BDC2190095E648 /* ymf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7E18BDC2180095E648 /* ymf.c */; }; 836F6FBD18BDC2190095E648 /* nwa.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8118BDC2180095E648 /* nwa.c */; }; 836F6FBF18BDC2190095E648 /* otm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8318BDC2180095E648 /* otm.c */; }; @@ -432,14 +431,14 @@ 836F6FCB18BDC2190095E648 /* ads.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8F18BDC2180095E648 /* ads.c */; }; 836F6FCD18BDC2190095E648 /* ps2_ass.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9118BDC2180095E648 /* ps2_ass.c */; }; 836F6FD018BDC2190095E648 /* ps2_b1s.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9418BDC2180095E648 /* ps2_b1s.c */; }; - 836F6FD118BDC2190095E648 /* ps2_bg00.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9518BDC2180095E648 /* ps2_bg00.c */; }; + 836F6FD118BDC2190095E648 /* bg00.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9518BDC2180095E648 /* bg00.c */; }; 836F6FD218BDC2190095E648 /* ps2_bmdx.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9618BDC2180095E648 /* ps2_bmdx.c */; }; 836F6FD418BDC2190095E648 /* hxd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9818BDC2180095E648 /* hxd.c */; }; 836F6FD518BDC2190095E648 /* lp_ap_lep.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9918BDC2180095E648 /* lp_ap_lep.c */; }; - 836F6FD718BDC2190095E648 /* ps2_filp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9B18BDC2180095E648 /* ps2_filp.c */; }; + 836F6FD718BDC2190095E648 /* filp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9B18BDC2180095E648 /* filp.c */; }; 836F6FD818BDC2190095E648 /* ps2_gbts.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9C18BDC2180095E648 /* ps2_gbts.c */; }; 836F6FD918BDC2190095E648 /* ps2_gcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9D18BDC2180095E648 /* ps2_gcm.c */; }; - 836F6FDA18BDC2190095E648 /* ps2_hgc1.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9E18BDC2180095E648 /* ps2_hgc1.c */; }; + 836F6FDA18BDC2190095E648 /* hgc1.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9E18BDC2180095E648 /* hgc1.c */; }; 836F6FDB18BDC2190095E648 /* ps2_hsf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9F18BDC2180095E648 /* ps2_hsf.c */; }; 836F6FDC18BDC2190095E648 /* ps2_iab.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA018BDC2180095E648 /* ps2_iab.c */; }; 836F6FDE18BDC2190095E648 /* ild.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA218BDC2180095E648 /* ild.c */; }; @@ -452,7 +451,7 @@ 836F6FF218BDC2190095E648 /* ps2_rnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB618BDC2180095E648 /* ps2_rnd.c */; }; 836F6FF418BDC2190095E648 /* rws_80d.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB818BDC2180095E648 /* rws_80d.c */; }; 836F6FF618BDC2190095E648 /* ster.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBA18BDC2180095E648 /* ster.c */; }; - 836F6FF718BDC2190095E648 /* ps2_sl3.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBB18BDC2180095E648 /* ps2_sl3.c */; }; + 836F6FF718BDC2190095E648 /* sl3.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBB18BDC2180095E648 /* sl3.c */; }; 836F6FF818BDC2190095E648 /* smpl.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBC18BDC2180095E648 /* smpl.c */; }; 836F6FF918BDC2190095E648 /* ps2_snd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBD18BDC2180095E648 /* ps2_snd.c */; }; 836F6FFA18BDC2190095E648 /* spm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBE18BDC2190095E648 /* spm.c */; }; @@ -465,7 +464,7 @@ 836F700818BDC2190095E648 /* ps2_vms.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ECC18BDC2190095E648 /* ps2_vms.c */; }; 836F700918BDC2190095E648 /* voi.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ECD18BDC2190095E648 /* voi.c */; }; 836F700B18BDC2190095E648 /* ps2_wad.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ECF18BDC2190095E648 /* ps2_wad.c */; }; - 836F700C18BDC2190095E648 /* ps2_wb.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED018BDC2190095E648 /* ps2_wb.c */; }; + 836F700C18BDC2190095E648 /* wb.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED018BDC2190095E648 /* wb.c */; }; 836F700D18BDC2190095E648 /* ps2_wmus.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED118BDC2190095E648 /* ps2_wmus.c */; }; 836F700F18BDC2190095E648 /* ps2_xa30.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED318BDC2190095E648 /* ps2_xa30.c */; }; 836F701518BDC2190095E648 /* ps3_past.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED918BDC2190095E648 /* ps3_past.c */; }; @@ -497,8 +496,8 @@ 836F703918BDC2190095E648 /* vgs.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EFD18BDC2190095E648 /* vgs.c */; }; 836F703A18BDC2190095E648 /* vs.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EFE18BDC2190095E648 /* vs.c */; }; 836F703B18BDC2190095E648 /* vsf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EFF18BDC2190095E648 /* vsf.c */; }; - 836F703C18BDC2190095E648 /* wii_bns.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0018BDC2190095E648 /* wii_bns.c */; }; - 836F703D18BDC2190095E648 /* wii_mus.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0118BDC2190095E648 /* wii_mus.c */; }; + 836F703C18BDC2190095E648 /* bns.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0018BDC2190095E648 /* bns.c */; }; + 836F703D18BDC2190095E648 /* mus_krome.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0118BDC2190095E648 /* mus_krome.c */; }; 836F703E18BDC2190095E648 /* wii_ras.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0218BDC2190095E648 /* wii_ras.c */; }; 836F704018BDC2190095E648 /* wii_sng.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0418BDC2190095E648 /* wii_sng.c */; }; 836F704218BDC2190095E648 /* sts.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0618BDC2190095E648 /* sts.c */; }; @@ -663,6 +662,14 @@ 83B69B222845A26600D2435A /* bw_mp3_riff.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B69B212845A26600D2435A /* bw_mp3_riff.c */; }; 83B72E3A27904589006007A3 /* libfdk-aac.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 83B72E342790452C006007A3 /* libfdk-aac.2.dylib */; }; 83BAFB6C19F45EB3005DAB60 /* bfstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 83BAFB6B19F45EB3005DAB60 /* bfstm.c */; }; + 83C0C75D2AA435C60056AFD8 /* squeak.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C0C75C2AA435C60056AFD8 /* squeak.c */; }; + 83C0C7602AA436370056AFD8 /* layout_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C0C75E2AA436370056AFD8 /* layout_utils.c */; }; + 83C0C7612AA436370056AFD8 /* layout_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C0C75F2AA436370056AFD8 /* layout_utils.h */; }; + 83C0C7632AA436B90056AFD8 /* snds.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C0C7622AA436B90056AFD8 /* snds.c */; }; + 83C0C7682AA437E10056AFD8 /* mixing_priv.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C0C7642AA437E10056AFD8 /* mixing_priv.h */; }; + 83C0C7692AA437E10056AFD8 /* mixing_fades.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C0C7652AA437E10056AFD8 /* mixing_fades.h */; }; + 83C0C76A2AA437E10056AFD8 /* mixing_commands.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C0C7662AA437E10056AFD8 /* mixing_commands.c */; }; + 83C0C76B2AA437E10056AFD8 /* mixing_macros.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C0C7672AA437E10056AFD8 /* mixing_macros.c */; }; 83C7280F22BC893D00678B4A /* xwb_xsb.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C727FB22BC893800678B4A /* xwb_xsb.h */; }; 83C7281022BC893D00678B4A /* nps.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C727FC22BC893900678B4A /* nps.c */; }; 83C7281122BC893D00678B4A /* 9tav_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C727FD22BC893900678B4A /* 9tav_streamfile.h */; }; @@ -932,7 +939,7 @@ 831BA60F1EAC61A500CF89B0 /* ogl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ogl.c; sourceTree = ""; }; 831BA6101EAC61A500CF89B0 /* ps2_vds_vdm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_vds_vdm.c; sourceTree = ""; }; 831BA6111EAC61A500CF89B0 /* sgxd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sgxd.c; sourceTree = ""; }; - 831BA6121EAC61A500CF89B0 /* sxd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sxd.c; sourceTree = ""; }; + 831BA6121EAC61A500CF89B0 /* sndx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sndx.c; sourceTree = ""; }; 831BA6131EAC61A500CF89B0 /* ubi_raki.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ubi_raki.c; sourceTree = ""; }; 831BA6151EAC61A500CF89B0 /* cxs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cxs.c; sourceTree = ""; }; 831BA6171EAC61A500CF89B0 /* pasx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pasx.c; sourceTree = ""; }; @@ -1160,7 +1167,7 @@ 836F46AD28208735005B9B87 /* blocked_tt_ad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_tt_ad.c; sourceTree = ""; }; 836F46AF2820874D005B9B87 /* tt_ad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tt_ad.c; sourceTree = ""; }; 836F46B02820874D005B9B87 /* esf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = esf.c; sourceTree = ""; }; - 836F46B12820874D005B9B87 /* adm3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adm3.c; sourceTree = ""; }; + 836F46B12820874D005B9B87 /* adm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adm.c; sourceTree = ""; }; 836F46B5282087A6005B9B87 /* cri_utf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cri_utf.c; sourceTree = ""; }; 836F46B6282087A6005B9B87 /* cri_utf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cri_utf.h; sourceTree = ""; }; 836F6B3918BDB8880095E648 /* libvgmstream.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = libvgmstream.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1214,7 +1221,7 @@ 836F6E3D18BDC2180095E648 /* dc_asd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_asd.c; sourceTree = ""; }; 836F6E3F18BDC2180095E648 /* dc_idvi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_idvi.c; sourceTree = ""; }; 836F6E4018BDC2180095E648 /* dc_kcey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_kcey.c; sourceTree = ""; }; - 836F6E4118BDC2180095E648 /* dc_str.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_str.c; sourceTree = ""; }; + 836F6E4118BDC2180095E648 /* str_sega.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = str_sega.c; sourceTree = ""; }; 836F6E4318BDC2180095E648 /* dmsg_segh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dmsg_segh.c; sourceTree = ""; }; 836F6E4618BDC2180095E648 /* ea_schl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_schl.c; sourceTree = ""; }; 836F6E4918BDC2180095E648 /* exakt_sc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exakt_sc.c; sourceTree = ""; }; @@ -1224,7 +1231,7 @@ 836F6E4D18BDC2180095E648 /* gca.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gca.c; sourceTree = ""; }; 836F6E4E18BDC2180095E648 /* gcsw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gcsw.c; sourceTree = ""; }; 836F6E4F18BDC2180095E648 /* genh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = genh.c; sourceTree = ""; }; - 836F6E5118BDC2180095E648 /* gsp_gsb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gsp_gsb.c; sourceTree = ""; }; + 836F6E5118BDC2180095E648 /* gsnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gsnd.c; sourceTree = ""; }; 836F6E5218BDC2180095E648 /* halpst.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = halpst.c; sourceTree = ""; }; 836F6E5318BDC2180095E648 /* his.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = his.c; sourceTree = ""; }; 836F6E5518BDC2180095E648 /* ios_psnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ios_psnd.c; sourceTree = ""; }; @@ -1258,7 +1265,6 @@ 836F6E7918BDC2180095E648 /* ngc_pdt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_pdt.c; sourceTree = ""; }; 836F6E7A18BDC2180095E648 /* ngc_sck_dsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_sck_dsp.c; sourceTree = ""; }; 836F6E7B18BDC2180095E648 /* ngc_ssm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_ssm.c; sourceTree = ""; }; - 836F6E7C18BDC2180095E648 /* ngc_tydsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_tydsp.c; sourceTree = ""; }; 836F6E7E18BDC2180095E648 /* ymf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ymf.c; sourceTree = ""; }; 836F6E8118BDC2180095E648 /* nwa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nwa.c; sourceTree = ""; }; 836F6E8318BDC2180095E648 /* otm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = otm.c; sourceTree = ""; }; @@ -1271,14 +1277,14 @@ 836F6E8F18BDC2180095E648 /* ads.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ads.c; sourceTree = ""; }; 836F6E9118BDC2180095E648 /* ps2_ass.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_ass.c; sourceTree = ""; }; 836F6E9418BDC2180095E648 /* ps2_b1s.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_b1s.c; sourceTree = ""; }; - 836F6E9518BDC2180095E648 /* ps2_bg00.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_bg00.c; sourceTree = ""; }; + 836F6E9518BDC2180095E648 /* bg00.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bg00.c; sourceTree = ""; }; 836F6E9618BDC2180095E648 /* ps2_bmdx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_bmdx.c; sourceTree = ""; }; 836F6E9818BDC2180095E648 /* hxd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hxd.c; sourceTree = ""; }; 836F6E9918BDC2180095E648 /* lp_ap_lep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lp_ap_lep.c; sourceTree = ""; }; - 836F6E9B18BDC2180095E648 /* ps2_filp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_filp.c; sourceTree = ""; }; + 836F6E9B18BDC2180095E648 /* filp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filp.c; sourceTree = ""; }; 836F6E9C18BDC2180095E648 /* ps2_gbts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_gbts.c; sourceTree = ""; }; 836F6E9D18BDC2180095E648 /* ps2_gcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_gcm.c; sourceTree = ""; }; - 836F6E9E18BDC2180095E648 /* ps2_hgc1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_hgc1.c; sourceTree = ""; }; + 836F6E9E18BDC2180095E648 /* hgc1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hgc1.c; sourceTree = ""; }; 836F6E9F18BDC2180095E648 /* ps2_hsf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_hsf.c; sourceTree = ""; }; 836F6EA018BDC2180095E648 /* ps2_iab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_iab.c; sourceTree = ""; }; 836F6EA218BDC2180095E648 /* ild.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ild.c; sourceTree = ""; }; @@ -1291,7 +1297,7 @@ 836F6EB618BDC2180095E648 /* ps2_rnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rnd.c; sourceTree = ""; }; 836F6EB818BDC2180095E648 /* rws_80d.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rws_80d.c; sourceTree = ""; }; 836F6EBA18BDC2180095E648 /* ster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ster.c; sourceTree = ""; }; - 836F6EBB18BDC2180095E648 /* ps2_sl3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_sl3.c; sourceTree = ""; }; + 836F6EBB18BDC2180095E648 /* sl3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sl3.c; sourceTree = ""; }; 836F6EBC18BDC2180095E648 /* smpl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = smpl.c; sourceTree = ""; }; 836F6EBD18BDC2180095E648 /* ps2_snd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_snd.c; sourceTree = ""; }; 836F6EBE18BDC2190095E648 /* spm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = spm.c; sourceTree = ""; }; @@ -1304,7 +1310,7 @@ 836F6ECC18BDC2190095E648 /* ps2_vms.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_vms.c; sourceTree = ""; }; 836F6ECD18BDC2190095E648 /* voi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = voi.c; sourceTree = ""; }; 836F6ECF18BDC2190095E648 /* ps2_wad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_wad.c; sourceTree = ""; }; - 836F6ED018BDC2190095E648 /* ps2_wb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_wb.c; sourceTree = ""; }; + 836F6ED018BDC2190095E648 /* wb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wb.c; sourceTree = ""; }; 836F6ED118BDC2190095E648 /* ps2_wmus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_wmus.c; sourceTree = ""; }; 836F6ED318BDC2190095E648 /* ps2_xa30.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_xa30.c; sourceTree = ""; }; 836F6ED918BDC2190095E648 /* ps3_past.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_past.c; sourceTree = ""; }; @@ -1336,8 +1342,8 @@ 836F6EFD18BDC2190095E648 /* vgs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vgs.c; sourceTree = ""; }; 836F6EFE18BDC2190095E648 /* vs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vs.c; sourceTree = ""; }; 836F6EFF18BDC2190095E648 /* vsf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vsf.c; sourceTree = ""; }; - 836F6F0018BDC2190095E648 /* wii_bns.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wii_bns.c; sourceTree = ""; }; - 836F6F0118BDC2190095E648 /* wii_mus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wii_mus.c; sourceTree = ""; }; + 836F6F0018BDC2190095E648 /* bns.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bns.c; sourceTree = ""; }; + 836F6F0118BDC2190095E648 /* mus_krome.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mus_krome.c; sourceTree = ""; }; 836F6F0218BDC2190095E648 /* wii_ras.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wii_ras.c; sourceTree = ""; }; 836F6F0418BDC2190095E648 /* wii_sng.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wii_sng.c; sourceTree = ""; }; 836F6F0618BDC2190095E648 /* sts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sts.c; sourceTree = ""; }; @@ -1504,6 +1510,14 @@ 83B69B212845A26600D2435A /* bw_mp3_riff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bw_mp3_riff.c; sourceTree = ""; }; 83B72E342790452C006007A3 /* libfdk-aac.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libfdk-aac.2.dylib"; path = "../../ThirdParty/fdk-aac/lib/libfdk-aac.2.dylib"; sourceTree = ""; }; 83BAFB6B19F45EB3005DAB60 /* bfstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bfstm.c; sourceTree = ""; }; + 83C0C75C2AA435C60056AFD8 /* squeak.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = squeak.c; sourceTree = ""; }; + 83C0C75E2AA436370056AFD8 /* layout_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = layout_utils.c; sourceTree = ""; }; + 83C0C75F2AA436370056AFD8 /* layout_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = layout_utils.h; sourceTree = ""; }; + 83C0C7622AA436B90056AFD8 /* snds.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = snds.c; sourceTree = ""; }; + 83C0C7642AA437E10056AFD8 /* mixing_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mixing_priv.h; sourceTree = ""; }; + 83C0C7652AA437E10056AFD8 /* mixing_fades.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mixing_fades.h; sourceTree = ""; }; + 83C0C7662AA437E10056AFD8 /* mixing_commands.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mixing_commands.c; sourceTree = ""; }; + 83C0C7672AA437E10056AFD8 /* mixing_macros.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mixing_macros.c; sourceTree = ""; }; 83C727FB22BC893800678B4A /* xwb_xsb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xwb_xsb.h; sourceTree = ""; }; 83C727FC22BC893900678B4A /* nps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nps.c; sourceTree = ""; }; 83C727FD22BC893900678B4A /* 9tav_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 9tav_streamfile.h; sourceTree = ""; }; @@ -1699,6 +1713,11 @@ children = ( 833E82D92A2857F700CD0580 /* decode.c */, 833E82DC2A2857F700CD0580 /* decode.h */, + 833E82C52A28562E00CD0580 /* info.c */, + 83C0C7662AA437E10056AFD8 /* mixing_commands.c */, + 83C0C7652AA437E10056AFD8 /* mixing_fades.h */, + 83C0C7672AA437E10056AFD8 /* mixing_macros.c */, + 83C0C7642AA437E10056AFD8 /* mixing_priv.h */, 833E82E02A2857F700CD0580 /* mixing.c */, 833E82DD2A2857F700CD0580 /* mixing.h */, 833E82DE2A2857F700CD0580 /* plugins.c */, @@ -1706,7 +1725,6 @@ 833E82DA2A2857F700CD0580 /* render.c */, 833E82E12A2857F700CD0580 /* render.h */, 833E82DB2A2857F700CD0580 /* seek.c */, - 833E82C52A28562E00CD0580 /* info.c */, ); path = base; sourceTree = ""; @@ -1993,7 +2011,7 @@ 837CEAD623487E8300E62A4A /* acb.c */, 836F6E2B18BDC2180095E648 /* acm.c */, 83F2CCE125A5B41600F46FA8 /* acx.c */, - 836F46B12820874D005B9B87 /* adm3.c */, + 836F46B12820874D005B9B87 /* adm.c */, 83AA7F7A2519C042004C5298 /* adp_konami.c */, 83D26A7626E66D98001A9475 /* adp_wildfire.c */, 834FE0CF215C79E8000A5D3D /* adpcm_capcom.c */, @@ -2033,6 +2051,7 @@ 836F6E3718BDC2180095E648 /* bcstm.c */, 83BAFB6B19F45EB3005DAB60 /* bfstm.c */, 83A5F75E198DF021009AF94C /* bfwav.c */, + 836F6E9518BDC2180095E648 /* bg00.c */, 837CEAD723487E8300E62A4A /* bgw_streamfile.h */, 836F6E3818BDC2180095E648 /* bgw.c */, 8319018328F67F2B00B70711 /* bigrp.c */, @@ -2041,6 +2060,7 @@ 837CEAD423487E8300E62A4A /* bmp_konami.c */, 839FBFFA26C354E70016A78A /* bnk_relic.c */, 834FE0CA215C79E7000A5D3D /* bnk_sony.c */, + 836F6F0018BDC2190095E648 /* bns.c */, 8373342523F60CDC00DE14DC /* bnsf_keys.h */, 836F6E3918BDC2180095E648 /* bnsf.c */, 836F6E3A18BDC2180095E648 /* brstm.c */, @@ -2060,7 +2080,6 @@ 836F6E3D18BDC2180095E648 /* dc_asd.c */, 836F6E3F18BDC2180095E648 /* dc_idvi.c */, 836F6E4018BDC2180095E648 /* dc_kcey.c */, - 836F6E4118BDC2180095E648 /* dc_str.c */, 83C7280C22BC893D00678B4A /* dcs_wav.c */, 8373342123F60CDB00DE14DC /* deblock_streamfile.c */, 8373341E23F60CDB00DE14DC /* deblock_streamfile.h */, @@ -2095,6 +2114,7 @@ 83C7280022BC893A00678B4A /* ffdl.c */, 838BDB6D1D3B043C0022CA6F /* ffmpeg.c */, 836F6E4B18BDC2180095E648 /* ffw.c */, + 836F6E9B18BDC2180095E648 /* filp.c */, 8349A8FD1FE6257F00E26435 /* flx.c */, 83D20072248DDB760048BD24 /* fsb_encrypted_streamfile.h */, 83A21F81201D8981000F04B9 /* fsb_encrypted.c */, @@ -2112,7 +2132,7 @@ 836F6E4F18BDC2180095E648 /* genh.c */, 83709DFF1ECBC1A4005C03D3 /* ghs.c */, 8375737421F950EC00F01AF5 /* gin.c */, - 836F6E5118BDC2180095E648 /* gsp_gsb.c */, + 836F6E5118BDC2180095E648 /* gsnd.c */, 8342469020C4D22F00926E48 /* h4m.c */, 836F6E5218BDC2180095E648 /* halpst.c */, 835B9B8D2730BF2D00F87EE3 /* hca_bf.h */, @@ -2120,6 +2140,7 @@ 83AA5D211F6E2F9C0020821C /* hca_keys.h */, 8323894F1D2246C300482226 /* hca.c */, 834FE0DF215C79EB000A5D3D /* hd3_bd3.c */, + 836F6E9E18BDC2180095E648 /* hgc1.c */, 836F6E5318BDC2180095E648 /* his.c */, 836F6E9818BDC2180095E648 /* hxd.c */, 834FE0E0215C79EB000A5D3D /* idsp_ie.c */, @@ -2185,6 +2206,7 @@ 83D20073248DDB760048BD24 /* mups_streamfile.h */, 83D20077248DDB770048BD24 /* mups.c */, 836F6E6218BDC2180095E648 /* mus_acm.c */, + 836F6F0118BDC2190095E648 /* mus_krome.c */, 83C7280622BC893B00678B4A /* mus_vc.c */, 836F6E6318BDC2180095E648 /* musc.c */, 836F6E6418BDC2180095E648 /* musx.c */, @@ -2207,7 +2229,6 @@ 836F6E7A18BDC2180095E648 /* ngc_sck_dsp.c */, 836F6E7B18BDC2180095E648 /* ngc_ssm.c */, 8306B0BE2098458C000302D4 /* ngc_str_cauldron.c */, - 836F6E7C18BDC2180095E648 /* ngc_tydsp.c */, 83C727FC22BC893900678B4A /* nps.c */, 837CEAE223487F2A00E62A4A /* nub.c */, 832BF81B21E0514B006F50F1 /* nus3audio.c */, @@ -2243,12 +2264,9 @@ 836F6E8E18BDC2180095E648 /* ps2_adm.c */, 836F6E9118BDC2180095E648 /* ps2_ass.c */, 836F6E9418BDC2180095E648 /* ps2_b1s.c */, - 836F6E9518BDC2180095E648 /* ps2_bg00.c */, 836F6E9618BDC2180095E648 /* ps2_bmdx.c */, - 836F6E9B18BDC2180095E648 /* ps2_filp.c */, 836F6E9C18BDC2180095E648 /* ps2_gbts.c */, 836F6E9D18BDC2180095E648 /* ps2_gcm.c */, - 836F6E9E18BDC2180095E648 /* ps2_hgc1.c */, 836F6E9F18BDC2180095E648 /* ps2_hsf.c */, 836F6EA018BDC2180095E648 /* ps2_iab.c */, 836F6EA418BDC2180095E648 /* ps2_joe.c */, @@ -2259,7 +2277,6 @@ 836F6EB218BDC2180095E648 /* ps2_p2bt.c */, 8349A8F21FE6257D00E26435 /* ps2_pcm.c */, 836F6EB618BDC2180095E648 /* ps2_rnd.c */, - 836F6EBB18BDC2180095E648 /* ps2_sl3.c */, 836F6EBD18BDC2180095E648 /* ps2_snd.c */, 836F6EBF18BDC2190095E648 /* ps2_sps.c */, 836F6EC518BDC2190095E648 /* ps2_tec.c */, @@ -2270,7 +2287,6 @@ 836F6ECB18BDC2190095E648 /* ps2_vgv.c */, 836F6ECC18BDC2190095E648 /* ps2_vms.c */, 836F6ECF18BDC2190095E648 /* ps2_wad.c */, - 836F6ED018BDC2190095E648 /* ps2_wb.c */, 836F6ED118BDC2190095E648 /* ps2_wmus.c */, 836F6ED318BDC2190095E648 /* ps2_xa30.c */, 836F6ED918BDC2190095E648 /* ps3_past.c */, @@ -2319,12 +2335,15 @@ 831BA6111EAC61A500CF89B0 /* sgxd.c */, 83AA7F782519C042004C5298 /* silence.c */, 839E21EA1F2EDB0500EE54D7 /* sk_aud.c */, + 836F6EBB18BDC2180095E648 /* sl3.c */, 836F6EF218BDC2190095E648 /* sli.c */, 8306B0D32098458F000302D4 /* smc_smh.c */, 837CEAEB23487F2B00E62A4A /* smk.c */, 83F0AA5C21E2028B004BBC04 /* smp.c */, 836F6EBC18BDC2180095E648 /* smpl.c */, 8306B0C72098458D000302D4 /* smv.c */, + 83C0C7622AA436B90056AFD8 /* snds.c */, + 831BA6121EAC61A500CF89B0 /* sndx.c */, 835559FB2869102B005FE93A /* sndz.c */, 836F6EBE18BDC2190095E648 /* spm.c */, 83A21F82201D8981000F04B9 /* sps_n1.c */, @@ -2333,6 +2352,7 @@ 836F6EF418BDC2190095E648 /* sqex_scd.c */, 83A21F84201D8981000F04B9 /* sqex_sead.c */, 837CEAF023487F2C00E62A4A /* sqex_streamfile.h */, + 83C0C75C2AA435C60056AFD8 /* squeak.c */, 8396BE782935FC2F00CD0580 /* sscf_encrypted.c */, 8396BE792935FC2F00CD0580 /* sscf_encrypted.h */, 834FE0D6215C79E9000A5D3D /* sscf.c */, @@ -2341,6 +2361,7 @@ 836F6EBA18BDC2180095E648 /* ster.c */, 8306B0C12098458C000302D4 /* sthd.c */, 83AA5D231F6E2F9C0020821C /* stma.c */, + 836F6E4118BDC2180095E648 /* str_sega.c */, 836F6EF718BDC2190095E648 /* str_snds.c */, 834FE0C2215C79E6000A5D3D /* str_wav.c */, 83C7280722BC893B00678B4A /* strm_abylight.c */, @@ -2350,7 +2371,6 @@ 834FE0D7215C79EA000A5D3D /* svg.c */, 836F6EF918BDC2190095E648 /* svs.c */, 83D0381724A4129A004CF90F /* swav.c */, - 831BA6121EAC61A500CF89B0 /* sxd.c */, 83E7FD6425EF2B2400683FD2 /* tac.c */, 8373342E23F60D4100DE14DC /* tgc.c */, 836F6EFA18BDC2190095E648 /* thp.c */, @@ -2395,9 +2415,8 @@ 8306B0D02098458F000302D4 /* wave_segmented.c */, 8306B0C92098458E000302D4 /* wave.c */, 834FE0D0215C79E8000A5D3D /* wavebatch.c */, + 836F6ED018BDC2190095E648 /* wb.c */, 83349715275DD2AC00302E21 /* wbk.c */, - 836F6F0018BDC2190095E648 /* wii_bns.c */, - 836F6F0118BDC2190095E648 /* wii_mus.c */, 836F6F0218BDC2190095E648 /* wii_ras.c */, 836F6F0418BDC2190095E648 /* wii_sng.c */, 836F6F0718BDC2190095E648 /* wpd.c */, @@ -2476,6 +2495,8 @@ 836F46B5282087A6005B9B87 /* cri_utf.c */, 836F46B6282087A6005B9B87 /* cri_utf.h */, 83B46FD42707FB9A00847FC9 /* endianness.h */, + 83C0C75E2AA436370056AFD8 /* layout_utils.c */, + 83C0C75F2AA436370056AFD8 /* layout_utils.h */, 83D26A7D26E66DC2001A9475 /* log.c */, 83D26A7F26E66DC2001A9475 /* log.h */, 8315868826F586F900803A3A /* m2_psb.c */, @@ -2556,6 +2577,7 @@ 836F46B8282087A6005B9B87 /* cri_utf.h in Headers */, 83A21F87201D8981000F04B9 /* fsb_keys.h in Headers */, 83E7FD6325EF2B0C00683FD2 /* tac_decoder_lib_data.h in Headers */, + 83C0C7682AA437E10056AFD8 /* mixing_priv.h in Headers */, 83FBB17C2A4FF87200CD0580 /* sf_utils.h in Headers */, 832FC36C278FA4CB0056A860 /* ubi_ckd_cwav_streamfile.h in Headers */, 83E7FD6125EF2B0C00683FD2 /* tac_decoder_lib.h in Headers */, @@ -2574,6 +2596,7 @@ 833E82F22A28587D00CD0580 /* paths.h in Headers */, 8349A9111FE6258200E26435 /* bar_streamfile.h in Headers */, 83256CE128666C620036D9C0 /* sample.h in Headers */, + 83C0C7612AA436370056AFD8 /* layout_utils.h in Headers */, 83D2007A248DDB770048BD24 /* fsb_encrypted_streamfile.h in Headers */, 833E82E52A2857F700CD0580 /* decode.h in Headers */, 836F6F2718BDC2190095E648 /* g72x_state.h in Headers */, @@ -2610,6 +2633,7 @@ 83256CD128666C620036D9C0 /* mpg123lib_intern.h in Headers */, 83C7281622BC893D00678B4A /* xwma_konami_streamfile.h in Headers */, 839E21E81F2EDAF100EE54D7 /* mpeg_decoder.h in Headers */, + 83C0C7692AA437E10056AFD8 /* mixing_fades.h in Headers */, 839E21E51F2EDAF100EE54D7 /* vorbis_custom_decoder.h in Headers */, 833E82C82A28566700CD0580 /* channel_mappings.h in Headers */, 83256CC028666C620036D9C0 /* synth_8bit.h in Headers */, @@ -2833,6 +2857,7 @@ 8383A62C281203C60062E49E /* s3v.c in Sources */, 8301659B1F256BD000CA0941 /* ea_schl_fixed.c in Sources */, 8301659C1F256BD000CA0941 /* nds_strm_ffta2.c in Sources */, + 83C0C7632AA436B90056AFD8 /* snds.c in Sources */, 837CEA7923487E2500E62A4A /* ubi_adpcm_decoder.c in Sources */, 834FE0EB215C79ED000A5D3D /* str_wav.c in Sources */, 83269DD32399F5DE00F49FE3 /* ivag.c in Sources */, @@ -2853,8 +2878,8 @@ 836F6F7218BDC2190095E648 /* baf.c in Sources */, 83F5F8831908D0A400C8E65F /* fsb5.c in Sources */, 836F6FD418BDC2190095E648 /* hxd.c in Sources */, - 836F700C18BDC2190095E648 /* ps2_wb.c in Sources */, - 836F6F7D18BDC2190095E648 /* dc_str.c in Sources */, + 836F700C18BDC2190095E648 /* wb.c in Sources */, + 836F6F7D18BDC2190095E648 /* str_sega.c in Sources */, 83A5F75F198DF021009AF94C /* bfwav.c in Sources */, 8373341723F60C7B00DE14DC /* g7221_decoder_aes.c in Sources */, 83FBB1792A4FF71B00CD0580 /* rstm_rockstar.c in Sources */, @@ -2882,10 +2907,10 @@ 836F6FA118BDC2190095E648 /* myspd.c in Sources */, 8315868726F586E200803A3A /* psb.c in Sources */, 837CEB0123487F2C00E62A4A /* xmu.c in Sources */, - 836F6FD718BDC2190095E648 /* ps2_filp.c in Sources */, + 836F6FD718BDC2190095E648 /* filp.c in Sources */, 8346D97925BF838C00D1A8B0 /* idtech.c in Sources */, 83FF0EBC1E93282100C58054 /* wwise.c in Sources */, - 836F46B42820874D005B9B87 /* adm3.c in Sources */, + 836F46B42820874D005B9B87 /* adm.c in Sources */, 836F6F7018BDC2190095E648 /* apple_caff.c in Sources */, 836F6FB618BDC2190095E648 /* ngc_sck_dsp.c in Sources */, 836F6F2818BDC2190095E648 /* ima_decoder.c in Sources */, @@ -2915,7 +2940,7 @@ 8396BE7A2935FC2F00CD0580 /* sscf_encrypted.c in Sources */, 832389521D224C0800482226 /* hca_decoder.c in Sources */, 836F6F9418BDC2190095E648 /* ivb.c in Sources */, - 836F6F8D18BDC2190095E648 /* gsp_gsb.c in Sources */, + 836F6F8D18BDC2190095E648 /* gsnd.c in Sources */, 836F704518BDC2190095E648 /* wvs.c in Sources */, 839FBFFB26C354E70016A78A /* wxd_wxh.c in Sources */, 83EDE5D91A70951A005F5D84 /* btsnd.c in Sources */, @@ -2943,7 +2968,7 @@ 8349A91F1FE6258200E26435 /* naac.c in Sources */, 83AFABBE23795202002F3947 /* isb.c in Sources */, 836F6FD218BDC2190095E648 /* ps2_bmdx.c in Sources */, - 836F703C18BDC2190095E648 /* wii_bns.c in Sources */, + 836F703C18BDC2190095E648 /* bns.c in Sources */, 830EBE132004656E0023AA10 /* xnb.c in Sources */, 835027131ED119E000C25929 /* mta2_decoder.c in Sources */, 83A8BAE725667AA8000F5F3F /* sdrh.c in Sources */, @@ -3032,6 +3057,7 @@ 836F6F7F18BDC2190095E648 /* dmsg_segh.c in Sources */, 839FBFFC26C354E70016A78A /* mp4_faac.c in Sources */, 832BF81D21E0514B006F50F1 /* msf_tamasoft.c in Sources */, + 83C0C75D2AA435C60056AFD8 /* squeak.c in Sources */, 832BF7FF21E050B7006F50F1 /* circus_decoder.c in Sources */, 83709E071ECBC1A4005C03D3 /* mss.c in Sources */, 836F6F8F18BDC2190095E648 /* his.c in Sources */, @@ -3081,7 +3107,7 @@ 8306B0F120984590000302D4 /* ppst.c in Sources */, 832BF81C21E0514B006F50F1 /* xpcm.c in Sources */, 836F702B18BDC2190095E648 /* sdt.c in Sources */, - 836F6FDA18BDC2190095E648 /* ps2_hgc1.c in Sources */, + 836F6FDA18BDC2190095E648 /* hgc1.c in Sources */, 836F702C18BDC2190095E648 /* seg.c in Sources */, 836F700918BDC2190095E648 /* voi.c in Sources */, 836F6FE018BDC2190095E648 /* ps2_joe.c in Sources */, @@ -3111,6 +3137,7 @@ 8373342823F60CDC00DE14DC /* fda.c in Sources */, 836F6F6D18BDC2190095E648 /* aifc.c in Sources */, 836F702218BDC2190095E648 /* rsd.c in Sources */, + 83C0C7602AA436370056AFD8 /* layout_utils.c in Sources */, 8349A90D1FE6258200E26435 /* ubi_sb.c in Sources */, 83C7281D22BC893D00678B4A /* ikm.c in Sources */, 834FE0BB215C798C000A5D3D /* celt_fsb_decoder.c in Sources */, @@ -3126,7 +3153,7 @@ 83C7281022BC893D00678B4A /* nps.c in Sources */, 83E7FD6025EF2B0C00683FD2 /* tac_decoder_lib.c in Sources */, 83C7281E22BC893D00678B4A /* msf.c in Sources */, - 836F6FF718BDC2190095E648 /* ps2_sl3.c in Sources */, + 836F6FF718BDC2190095E648 /* sl3.c in Sources */, 8351F32D2212B57000A606E4 /* 208.c in Sources */, 836F6F3118BDC2190095E648 /* ngc_afc_decoder.c in Sources */, 836F6F9918BDC2190095E648 /* maxis_xa.c in Sources */, @@ -3156,7 +3183,6 @@ 83AA5D271F6E2F9C0020821C /* stma.c in Sources */, 831BA61D1EAC61A500CF89B0 /* ubi_raki.c in Sources */, 8306B0A520984552000302D4 /* blocked_ea_wve_au00.c in Sources */, - 836F6FB818BDC2190095E648 /* ngc_tydsp.c in Sources */, 836F701518BDC2190095E648 /* ps3_past.c in Sources */, 832BF80621E050DC006F50F1 /* blocked_vs_square.c in Sources */, 836F6F7C18BDC2190095E648 /* dc_kcey.c in Sources */, @@ -3190,10 +3216,10 @@ 832BF81F21E0514B006F50F1 /* ps2_va3.c in Sources */, 8349A91C1FE6258200E26435 /* mogg.c in Sources */, 834FE0F5215C79ED000A5D3D /* wv2.c in Sources */, - 836F703D18BDC2190095E648 /* wii_mus.c in Sources */, + 836F703D18BDC2190095E648 /* mus_krome.c in Sources */, 836F700D18BDC2190095E648 /* ps2_wmus.c in Sources */, 83031EC8243C50A800C3F3E0 /* circus_decoder_lib.c in Sources */, - 831BA61C1EAC61A500CF89B0 /* sxd.c in Sources */, + 831BA61C1EAC61A500CF89B0 /* sndx.c in Sources */, 836F6F9618BDC2190095E648 /* lsf.c in Sources */, 8306B0AB20984552000302D4 /* layered.c in Sources */, 833E82E92A2857F700CD0580 /* mixing.c in Sources */, @@ -3245,6 +3271,7 @@ 8306B0B220984552000302D4 /* blocked_mxch.c in Sources */, 837CEAFA23487F2C00E62A4A /* xa_04sw.c in Sources */, 836F6F8618BDC2190095E648 /* excitebots.c in Sources */, + 83C0C76B2AA437E10056AFD8 /* mixing_macros.c in Sources */, 8385D4E6245174C700FF8E67 /* diva.c in Sources */, 836F6FF418BDC2190095E648 /* rws_80d.c in Sources */, 834FE100215C79ED000A5D3D /* svg.c in Sources */, @@ -3267,6 +3294,7 @@ 832BF82621E0514B006F50F1 /* nwav.c in Sources */, 836F6F3018BDC2190095E648 /* nds_procyon_decoder.c in Sources */, 8349A8E81FE6253900E26435 /* blocked_dec.c in Sources */, + 83C0C76A2AA437E10056AFD8 /* mixing_commands.c in Sources */, 83852B0B2680247900378854 /* rxws.c in Sources */, 831BA6181EAC61A500CF89B0 /* adx.c in Sources */, 832BF82321E0514B006F50F1 /* imc.c in Sources */, @@ -3340,7 +3368,7 @@ 834FE111215C79ED000A5D3D /* ck.c in Sources */, 83D2007C248DDB770048BD24 /* ktsr.c in Sources */, 836F704E18BDC2190095E648 /* xss.c in Sources */, - 836F6FD118BDC2190095E648 /* ps2_bg00.c in Sources */, + 836F6FD118BDC2190095E648 /* bg00.c in Sources */, 83AA7F7F2519C042004C5298 /* bsf.c in Sources */, 836F6F4118BDC2190095E648 /* blocked.c in Sources */, 836F6F3B18BDC2190095E648 /* ws_decoder.c in Sources */, diff --git a/Frameworks/vgmstream/vgmstream/src/base/decode.c b/Frameworks/vgmstream/vgmstream/src/base/decode.c index f55c3275c..cd92ca140 100644 --- a/Frameworks/vgmstream/vgmstream/src/base/decode.c +++ b/Frameworks/vgmstream/vgmstream/src/base/decode.c @@ -367,6 +367,7 @@ int decode_get_samples_per_frame(VGMSTREAM* vgmstream) { case coding_PCMFLOAT: case coding_PCM24LE: case coding_PCM24BE: + case coding_PCM32LE: return 1; #ifdef VGM_USE_VORBIS case coding_OGG_VORBIS: @@ -422,10 +423,11 @@ int decode_get_samples_per_frame(VGMSTREAM* vgmstream) { case coding_APPLE_IMA4: return 64; case coding_MS_IMA: - case coding_REF_IMA: - return ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1;/* +1 from header sample */ + return ((vgmstream->frame_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1; /* +1 from header sample */ case coding_MS_IMA_mono: return ((vgmstream->frame_size - 0x04) * 2) + 1; /* +1 from header sample */ + case coding_REF_IMA: + return ((vgmstream->interleave_block_size - 0x04 * vgmstream->channels) * 2 / vgmstream->channels) + 1; /* +1 from header sample */ case coding_RAD_IMA: return (vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels; case coding_NDS_IMA: @@ -593,6 +595,7 @@ int decode_get_frame_size(VGMSTREAM* vgmstream) { case coding_ALAW: return 0x01; case coding_PCMFLOAT: + case coding_PCM32LE: return 0x04; case coding_PCM24LE: case coding_PCM24BE: @@ -787,7 +790,7 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_ for (ch = 0; ch < vgmstream->channels; ch++) { decode_adx(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, - vgmstream->interleave_block_size, vgmstream->coding_type); + vgmstream->interleave_block_size, vgmstream->coding_type, vgmstream->codec_config); } break; case coding_NGC_DSP: @@ -906,6 +909,13 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_ } break; + case coding_PCM32LE: + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_pcm32le(&vgmstream->ch[ch], buffer+ch, + vgmstream->channels, vgmstream->samples_into_block, samples_to_do); + } + break; + case coding_NDS_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_nds_ima(&vgmstream->ch[ch], buffer+ch, diff --git a/Frameworks/vgmstream/vgmstream/src/base/mixing.c b/Frameworks/vgmstream/vgmstream/src/base/mixing.c index 17ae43979..867f992d2 100644 --- a/Frameworks/vgmstream/vgmstream/src/base/mixing.c +++ b/Frameworks/vgmstream/vgmstream/src/base/mixing.c @@ -1,6 +1,8 @@ #include "../vgmstream.h" #include "../util/channel_mappings.h" #include "mixing.h" +#include "mixing_priv.h" +#include "mixing_fades.h" #include "plugins.h" #include #include @@ -49,215 +51,21 @@ * (and maybe improve memory cache?), though maybe it should call one function per operation. */ -#define VGMSTREAM_MAX_MIXING 512 -#define MIXING_PI 3.14159265358979323846f - - -/* mixing info */ -typedef enum { - MIX_SWAP, - MIX_ADD, - MIX_ADD_COPY, - MIX_VOLUME, - MIX_LIMIT, - MIX_UPMIX, - MIX_DOWNMIX, - MIX_KILLMIX, - MIX_FADE -} mix_command_t; - -typedef struct { - mix_command_t command; - /* common */ - int ch_dst; - int ch_src; - float vol; - - /* fade envelope */ - float vol_start; /* volume from pre to start */ - float vol_end; /* volume from end to post */ - char shape; /* curve type */ - int32_t time_pre; /* position before time_start where vol_start applies (-1 = beginning) */ - int32_t time_start; /* fade start position where vol changes from vol_start to vol_end */ - int32_t time_end; /* fade end position where vol changes from vol_start to vol_end */ - int32_t time_post; /* position after time_end where vol_end applies (-1 = end) */ -} mix_command_data; - -typedef struct { - int mixing_channels; /* max channels needed to mix */ - int output_channels; /* resulting channels after mixing */ - int mixing_on; /* mixing allowed */ - int mixing_count; /* mixing number */ - size_t mixing_size; /* mixing max */ - mix_command_data mixing_chain[VGMSTREAM_MAX_MIXING]; /* effects to apply (could be alloc'ed but to simplify...) */ - float* mixbuf; /* internal mixing buffer */ - - /* fades only apply at some points, other mixes are active */ - int has_non_fade; - int has_fade; -} mixing_data; - - /* ******************************************************************* */ -static int is_fade_active(mixing_data *data, int32_t current_start, int32_t current_end) { - int i; - - for (i = 0; i < data->mixing_count; i++) { - mix_command_data *mix = &data->mixing_chain[i]; - int32_t fade_start, fade_end; - float vol_start = mix->vol_start; - - if (mix->command != MIX_FADE) - continue; - - /* check is current range falls within a fade - * (assuming fades were already optimized on add) */ - if (mix->time_pre < 0 && vol_start == 1.0) { - fade_start = mix->time_start; /* ignore unused */ - } - else { - fade_start = mix->time_pre < 0 ? 0 : mix->time_pre; - } - fade_end = mix->time_post < 0 ? INT_MAX : mix->time_post; - - //;VGM_LOG("MIX: fade test, tp=%i, te=%i, cs=%i, ce=%i\n", mix->time_pre, mix->time_post, current_start, current_end); - if (current_start < fade_end && current_end > fade_start) { - //;VGM_LOG("MIX: fade active, cs=%i < fe=%i and ce=%i > fs=%i\n", current_start, fade_end, current_end, fade_start); - return 1; - } - } - - return 0; -} - -static int32_t get_current_pos(VGMSTREAM* vgmstream, int32_t sample_count) { - int32_t current_pos; - - if (vgmstream->config_enabled) { - return vgmstream->pstate.play_position; - } - - if (vgmstream->loop_flag && vgmstream->loop_count > 0) { - int loop_pre = vgmstream->loop_start_sample; /* samples before looping */ - int loop_into = (vgmstream->current_sample - vgmstream->loop_start_sample); /* samples after loop */ - int loop_samples = (vgmstream->loop_end_sample - vgmstream->loop_start_sample); /* looped section */ - - current_pos = loop_pre + (loop_samples * vgmstream->loop_count) + loop_into - sample_count; - } - else { - current_pos = (vgmstream->current_sample - sample_count); - } - - return current_pos; -} - -static float get_fade_gain_curve(char shape, float index) { - float gain; - - /* don't bother doing calcs near 0.0/1.0 */ - if (index <= 0.0001f || index >= 0.9999f) { - return index; - } - - //todo optimizations: interleave calcs, maybe use cosf, powf, etc? (with extra defines) - - /* (curve math mostly from SoX/FFmpeg) */ - switch(shape) { - /* 2.5f in L/E 'pow' is the attenuation factor, where 5.0 (100db) is common but a bit fast - * (alt calculations with 'exp' from FFmpeg use (factor)*ln(0.1) = -NN.N... */ - - case 'E': /* exponential (for fade-outs, closer to natural decay of sound) */ - //gain = pow(0.1f, (1.0f - index) * 2.5f); - gain = exp(-5.75646273248511f * (1.0f - index)); - break; - case 'L': /* logarithmic (inverse of the above, maybe for crossfades) */ - //gain = 1 - pow(0.1f, (index) * 2.5f); - gain = 1 - exp(-5.75646273248511f * (index)); - break; - - case 'H': /* raised sine wave or cosine wave (for more musical crossfades) */ - gain = (1.0f - cos(index * MIXING_PI)) / 2.0f; - break; - - case 'Q': /* quarter of sine wave (for musical fades) */ - gain = sin(index * MIXING_PI / 2.0f); - break; - - case 'p': /* parabola (maybe for crossfades) */ - gain = 1.0f - sqrt(1.0f - index); - break; - case 'P': /* inverted parabola (maybe for fades) */ - gain = (1.0f - (1.0f - index) * (1.0f - index)); - break; - - case 'T': /* triangular/linear (simpler/sharper fades) */ - default: - gain = index; - break; - } - - return gain; -} - -static int get_fade_gain(mix_command_data *mix, float *out_cur_vol, int32_t current_subpos) { - float cur_vol = 0.0f; - - if ((current_subpos >= mix->time_pre || mix->time_pre < 0) && current_subpos < mix->time_start) { - cur_vol = mix->vol_start; /* before */ - } - else if (current_subpos >= mix->time_end && (current_subpos < mix->time_post || mix->time_post < 0)) { - cur_vol = mix->vol_end; /* after */ - } - else if (current_subpos >= mix->time_start && current_subpos < mix->time_end) { - /* in between */ - float range_vol, range_dur, range_idx, index, gain; - - if (mix->vol_start < mix->vol_end) { /* fade in */ - range_vol = mix->vol_end - mix->vol_start; - range_dur = mix->time_end - mix->time_start; - range_idx = current_subpos - mix->time_start; - index = range_idx / range_dur; - } else { /* fade out */ - range_vol = mix->vol_end - mix->vol_start; - range_dur = mix->time_end - mix->time_start; - range_idx = mix->time_end - current_subpos; - index = range_idx / range_dur; - } - - /* Fading is done like this: - * - find current position within fade duration - * - get linear % (or rather, index from 0.0 .. 1.0) of duration - * - apply shape to % (from linear fade to curved fade) - * - get final volume for that point - * - * Roughly speaking some curve shapes are better for fades (decay rate is more natural - * sounding in that highest to mid/low happens faster but low to lowest takes more time, - * kinda like a gunshot or bell), and others for crossfades (decay of fade-in + fade-out - * is adjusted so that added volume level stays constant-ish). - * - * As curves can fade in two ways ('normal' and curving 'the other way'), they are adjusted - * to get 'normal' shape on both fades (by reversing index and making 1 - gain), thus some - * curves are complementary (exponential fade-in ~= logarithmic fade-out); the following - * are described taking fade-in = normal. +static void sbuf_copy_f32_to_s16(int16_t* buf_s16, float* buf_f32, int samples, int channels) { + for (int s = 0; s < samples * channels; s++) { + /* when casting float to int, value is simply truncated: + * - (int)1.7 = 1, (int)-1.7 = -1 + * alts for more accurate rounding could be: + * - (int)floor(f) + * - (int)(f < 0 ? f - 0.5f : f + 0.5f) + * - (((int) (f1 + 32768.5)) - 32768) + * - etc + * but since +-1 isn't really audible we'll just cast as it's the fastest */ - gain = get_fade_gain_curve(mix->shape, index); - - if (mix->vol_start < mix->vol_end) { /* fade in */ - cur_vol = mix->vol_start + range_vol * gain; - } else { /* fade out */ - cur_vol = mix->vol_end - range_vol * gain; //mix->vol_start - range_vol * (1 - gain); - } + buf_s16[s] = clamp16( (int32_t)buf_f32[s] ); } - else { - /* fade is outside reach */ - goto fail; - } - - *out_cur_vol = cur_vol; - return 1; -fail: - return 0; } void mix_vgmstream(sample_t *outbuf, int32_t sample_count, VGMSTREAM* vgmstream) { @@ -288,9 +96,19 @@ void mix_vgmstream(sample_t *outbuf, int32_t sample_count, VGMSTREAM* vgmstream) /* use advancing buffer pointers to simplify logic */ - temp_mixbuf = data->mixbuf; + temp_mixbuf = data->mixbuf; /* you'd think using a int32 temp buf would be faster but somehow it's slower? */ temp_outbuf = outbuf; + /* mixing ops are designed to apply in order, all channels per 1 sample 'step'. Since some ops change + * total channels, channel number meaning varies as ops move them around, ex: + * - 4ch w/ "1-2,2+3" = ch1<>ch3, ch2(old ch1)+ch3 = 4ch: ch2 ch1+ch3 ch3 ch4 + * - 4ch w/ "2+3,1-2" = ch2+ch3, ch1<>ch2(modified) = 4ch: ch2+ch3 ch1 ch3 ch4 + * - 2ch w/ "1+2,1u" = ch1+ch2, ch1(add and push rest) = 3ch: ch1' ch1+ch2 ch2 + * - 2ch w/ "1u,1+2" = ch1(add and push rest) = 3ch: ch1'+ch1 ch1 ch2 + * - 2ch w/ "1-2,1d" = ch1<>ch2, ch1(drop and move ch2(old ch1) to ch1) = ch1 + * - 2ch w/ "1d,1-2" = ch1(drop and pull rest), ch1(do nothing, ch2 doesn't exist now) = ch2 + */ + /* apply mixes in order per channel */ for (s = 0; s < sample_count; s++) { /* reset after new sample 'step'*/ @@ -304,15 +122,6 @@ void mix_vgmstream(sample_t *outbuf, int32_t sample_count, VGMSTREAM* vgmstream) for (m = 0; m < data->mixing_count; m++) { mix_command_data *mix = &data->mixing_chain[m]; - /* mixing ops are designed to apply in order, all channels per 1 sample 'step'. Since some ops change - * total channels, channel number meaning varies as ops move them around, ex: - * - 4ch w/ "1-2,2+3" = ch1<>ch3, ch2(old ch1)+ch3 = 4ch: ch2 ch1+ch3 ch3 ch4 - * - 4ch w/ "2+3,1-2" = ch2+ch3, ch1<>ch2(modified) = 4ch: ch2+ch3 ch1 ch3 ch4 - * - 2ch w/ "1+2,1u" = ch1+ch2, ch1(add and push rest) = 3ch: ch1' ch1+ch2 ch2 - * - 2ch w/ "1u,1+2" = ch1(add and push rest) = 3ch: ch1'+ch1 ch1 ch2 - * - 2ch w/ "1-2,1d" = ch1<>ch2, ch1(drop and move ch2(old ch1) to ch1) = ch1 - * - 2ch w/ "1d,1-2" = ch1(drop and pull rest), ch1(do nothing, ch2 doesn't exist now) = ch2 - */ switch(mix->command) { case MIX_SWAP: @@ -406,20 +215,8 @@ void mix_vgmstream(sample_t *outbuf, int32_t sample_count, VGMSTREAM* vgmstream) temp_outbuf += vgmstream->channels; } - /* copy resulting mix to output - * (you'd think using a int32 temp buf would be faster but somehow it's slower?) */ - for (s = 0; s < sample_count * data->output_channels; s++) { - /* when casting float to int, value is simply truncated: - * - (int)1.7 = 1, (int)-1.7 = -1 - * alts for more accurate rounding could be: - * - (int)floor(f) - * - (int)(f < 0 ? f - 0.5f : f + 0.5f) - * - (((int) (f1 + 32768.5)) - 32768) - * - etc - * but since +-1 isn't really audible we'll just cast as it's the fastest - */ - outbuf[s] = clamp16( (int32_t)data->mixbuf[s] ); - } + /* copy resulting temp mix to output */ + sbuf_copy_f32_to_s16(outbuf, data->mixbuf, sample_count, data->output_channels); } /* ******************************************************************* */ @@ -460,827 +257,6 @@ void mixing_update_channel(VGMSTREAM* vgmstream) { data->output_channels++; } -/* ******************************************************************* */ - -static int add_mixing(VGMSTREAM* vgmstream, mix_command_data *mix) { - mixing_data *data = vgmstream->mixing_data; - if (!data) return 0; - - - if (data->mixing_on) { - VGM_LOG("MIX: ignoring new mixes when mixing active\n"); - return 0; /* to avoid down/upmixing after activation */ - } - - if (data->mixing_count + 1 > data->mixing_size) { - VGM_LOG("MIX: too many mixes\n"); - return 0; - } - - data->mixing_chain[data->mixing_count] = *mix; /* memcpy */ - data->mixing_count++; - - - if (mix->command == MIX_FADE) { - data->has_fade = 1; - } - else { - data->has_non_fade = 1; - } - - //;VGM_LOG("MIX: total %i\n", data->mixing_count); - return 1; -} - - -void mixing_push_swap(VGMSTREAM* vgmstream, int ch_dst, int ch_src) { - mixing_data *data = vgmstream->mixing_data; - mix_command_data mix = {0}; - - if (ch_dst < 0 || ch_src < 0 || ch_dst == ch_src) return; - if (!data || ch_dst >= data->output_channels || ch_src >= data->output_channels) return; - mix.command = MIX_SWAP; - mix.ch_dst = ch_dst; - mix.ch_src = ch_src; - - add_mixing(vgmstream, &mix); -} - -void mixing_push_add(VGMSTREAM* vgmstream, int ch_dst, int ch_src, double volume) { - mixing_data *data = vgmstream->mixing_data; - mix_command_data mix = {0}; - if (!data) return; - - //if (volume < 0.0) return; /* negative volume inverts the waveform */ - if (volume == 0.0) return; /* ch_src becomes silent and nothing is added */ - if (ch_dst < 0 || ch_src < 0) return; - if (!data || ch_dst >= data->output_channels || ch_src >= data->output_channels) return; - - mix.command = (volume == 1.0) ? MIX_ADD_COPY : MIX_ADD; - mix.ch_dst = ch_dst; - mix.ch_src = ch_src; - mix.vol = volume; - - //;VGM_LOG("MIX: add %i+%i*%f\n", ch_dst,ch_src,volume); - add_mixing(vgmstream, &mix); -} - -void mixing_push_volume(VGMSTREAM* vgmstream, int ch_dst, double volume) { - mixing_data *data = vgmstream->mixing_data; - mix_command_data mix = {0}; - - //if (ch_dst < 0) return; /* means all channels */ - //if (volume < 0.0) return; /* negative volume inverts the waveform */ - if (volume == 1.0) return; /* no change */ - if (!data || ch_dst >= data->output_channels) return; - - mix.command = MIX_VOLUME; //if (volume == 0.0) MIX_VOLUME0 /* could simplify */ - mix.ch_dst = ch_dst; - mix.vol = volume; - - //;VGM_LOG("MIX: volume %i*%f\n", ch_dst,volume); - add_mixing(vgmstream, &mix); -} - -void mixing_push_limit(VGMSTREAM* vgmstream, int ch_dst, double volume) { - mixing_data *data = vgmstream->mixing_data; - mix_command_data mix = {0}; - - //if (ch_dst < 0) return; /* means all channels */ - if (volume < 0.0) return; - if (volume == 1.0) return; /* no actual difference */ - if (!data || ch_dst >= data->output_channels) return; - //if (volume == 0.0) return; /* dumb but whatevs */ - - mix.command = MIX_LIMIT; - mix.ch_dst = ch_dst; - mix.vol = volume; - - add_mixing(vgmstream, &mix); -} - -void mixing_push_upmix(VGMSTREAM* vgmstream, int ch_dst) { - mixing_data *data = vgmstream->mixing_data; - mix_command_data mix = {0}; - int ok; - - if (ch_dst < 0) return; - if (!data || ch_dst > data->output_channels || data->output_channels +1 > VGMSTREAM_MAX_CHANNELS) return; - /* dst can be == output_channels here, since we are inserting */ - - mix.command = MIX_UPMIX; - mix.ch_dst = ch_dst; - - ok = add_mixing(vgmstream, &mix); - if (ok) { - data->output_channels += 1; - if (data->mixing_channels < data->output_channels) - data->mixing_channels = data->output_channels; - } -} - -void mixing_push_downmix(VGMSTREAM* vgmstream, int ch_dst) { - mixing_data *data = vgmstream->mixing_data; - mix_command_data mix = {0}; - int ok; - - if (ch_dst < 0) return; - if (!data || ch_dst >= data->output_channels || data->output_channels - 1 < 1) return; - - mix.command = MIX_DOWNMIX; - mix.ch_dst = ch_dst; - - ok = add_mixing(vgmstream, &mix); - if (ok) { - data->output_channels -= 1; - } -} - -void mixing_push_killmix(VGMSTREAM* vgmstream, int ch_dst) { - mixing_data *data = vgmstream->mixing_data; - mix_command_data mix = {0}; - int ok; - - if (ch_dst <= 0) return; /* can't kill from first channel */ - if (!data || ch_dst >= data->output_channels) return; - - mix.command = MIX_KILLMIX; - mix.ch_dst = ch_dst; - - //;VGM_LOG("MIX: killmix %i\n", ch_dst); - ok = add_mixing(vgmstream, &mix); - if (ok) { - data->output_channels = ch_dst; /* clamp channels */ - } -} - - -static mix_command_data* get_last_fade(mixing_data *data, int target_channel) { - int i; - for (i = data->mixing_count; i > 0; i--) { - mix_command_data *mix = &data->mixing_chain[i-1]; - if (mix->command != MIX_FADE) - continue; - if (mix->ch_dst == target_channel) - return mix; - } - - return NULL; -} - - -void mixing_push_fade(VGMSTREAM* vgmstream, int ch_dst, double vol_start, double vol_end, char shape, - int32_t time_pre, int32_t time_start, int32_t time_end, int32_t time_post) { - mixing_data *data = vgmstream->mixing_data; - mix_command_data mix = {0}; - mix_command_data *mix_prev; - - - //if (ch_dst < 0) return; /* means all channels */ - if (!data || ch_dst >= data->output_channels) return; - if (time_pre > time_start || time_start > time_end || (time_post >= 0 && time_end > time_post)) return; - if (time_start < 0 || time_end < 0) return; - //if (time_pre < 0 || time_post < 0) return; /* special meaning of file start/end */ - //if (vol_start == vol_end) /* weird but let in case of being used to cancel others fades... maybe? */ - - if (shape == '{' || shape == '}') - shape = 'E'; - if (shape == '(' || shape == ')') - shape = 'H'; - - mix.command = MIX_FADE; - mix.ch_dst = ch_dst; - mix.vol_start = vol_start; - mix.vol_end = vol_end; - mix.shape = shape; - mix.time_pre = time_pre; - mix.time_start = time_start; - mix.time_end = time_end; - mix.time_post = time_post; - - - /* cancel fades and optimize a bit when using negative pre/post: - * - fades work like this: - * <----------|----------|----------> - * pre1 start1 end1 post1 - * - when pre and post are set nothing is done (fade is exact and multiple fades may overlap) - * - when previous fade's post or current fade's pre are negative (meaning file end/start) - * they should cancel each other (to allow chaining fade-in + fade-out + fade-in + etc): - * <----------|----------|----------| |----------|----------|----------> - * pre1 start1 end1 post1 pre2 start2 end2 post2 - * - other cases (previous fade is actually after/in-between current fade) are ignored - * as they're uncommon and hard to optimize - * fades cancel fades of the same channel, and 'all channel' (-1) fades also cancel 'all channels' - */ - mix_prev = get_last_fade(data, mix.ch_dst); - if (mix_prev == NULL) { - if (vol_start == 1.0 && time_pre < 0) - time_pre = time_start; /* fade-out helds default volume before fade start can be clamped */ - if (vol_end == 1.0 && time_post < 0) - time_post = time_end; /* fade-in helds default volume after fade end can be clamped */ - } - else if (mix_prev->time_post < 0 || mix.time_pre < 0) { - int is_prev = 1; - /* test if prev is really cancelled by this */ - if ((mix_prev->time_end > mix.time_start) || - (mix_prev->time_post >= 0 && mix_prev->time_post > mix.time_start) || - (mix.time_pre >= 0 && mix.time_pre < mix_prev->time_end)) - is_prev = 0; - - if (is_prev) { - /* change negative values to actual points */ - if (mix_prev->time_post < 0 && mix.time_pre < 0) { - mix_prev->time_post = mix_prev->time_end; - mix.time_pre = mix_prev->time_post; - } - - if (mix_prev->time_post >= 0 && mix.time_pre < 0) { - mix.time_pre = mix_prev->time_post; - } - else if (mix_prev->time_post < 0 && mix.time_pre >= 0) { - mix_prev->time_post = mix.time_pre; - } - /* else: both define start/ends, do nothing */ - } - /* should only modify prev if add_mixing but meh */ - } - - //;VGM_LOG("MIX: fade %i^%f~%f=%c@%i~%i~%i~%i\n", ch_dst, vol_start, vol_end, shape, time_pre, time_start, time_end, time_post); - add_mixing(vgmstream, &mix); -} - -/* ******************************************************************* */ - -#define MIX_MACRO_VOCALS 'v' -#define MIX_MACRO_EQUAL 'e' -#define MIX_MACRO_BGM 'b' - -void mixing_macro_volume(VGMSTREAM* vgmstream, double volume, uint32_t mask) { - mixing_data *data = vgmstream->mixing_data; - int ch; - - if (!data) - return; - - if (mask == 0) { - mixing_push_volume(vgmstream, -1, volume); - return; - } - - for (ch = 0; ch < data->output_channels; ch++) { - if (!((mask >> ch) & 1)) - continue; - mixing_push_volume(vgmstream, ch, volume); - } -} - -void mixing_macro_track(VGMSTREAM* vgmstream, uint32_t mask) { - mixing_data *data = vgmstream->mixing_data; - int ch; - - if (!data) - return; - - if (mask == 0) { - return; - } - - /* reverse remove all channels (easier this way as when removing channels numbers change) */ - for (ch = data->output_channels - 1; ch >= 0; ch--) { - if ((mask >> ch) & 1) - continue; - mixing_push_downmix(vgmstream, ch); - } -} - - -/* get highest channel count */ -static int get_layered_max_channels(VGMSTREAM* vgmstream) { - int i, max; - layered_layout_data* data; - - if (vgmstream->layout_type != layout_layered) - return 0; - - data = vgmstream->layout_data; - - max = 0; - for (i = 0; i < data->layer_count; i++) { - int output_channels = 0; - - mixing_info(data->layers[i], NULL, &output_channels); - - if (max < output_channels) - max = output_channels; - } - - return max; -} - -static int is_layered_auto(VGMSTREAM* vgmstream, int max, char mode) { - int i; - mixing_data *data = vgmstream->mixing_data; - layered_layout_data* l_data; - - - if (vgmstream->layout_type != layout_layered) - return 0; - - /* no channels set and only vocals for now */ - if (max > 0 || mode != MIX_MACRO_VOCALS) - return 0; - - /* no channel down/upmixing (cannot guess output) */ - for (i = 0; i < data->mixing_count; i++) { - mix_command_t mix = data->mixing_chain[i].command; - if (mix == MIX_UPMIX || mix == MIX_DOWNMIX || mix == MIX_KILLMIX) /*mix == MIX_SWAP || ??? */ - return 0; - } - - /* only previsible cases */ - l_data = vgmstream->layout_data; - for (i = 0; i < l_data->layer_count; i++) { - int output_channels = 0; - - mixing_info(l_data->layers[i], NULL, &output_channels); - - if (output_channels > 8) - return 0; - } - - return 1; -} - - -/* special layering, where channels are respected (so Ls only go to Ls), also more optimized */ -static void mixing_macro_layer_auto(VGMSTREAM* vgmstream, int max, char mode) { - layered_layout_data* ldata = vgmstream->layout_data; - int i, ch; - int target_layer = 0, target_chs = 0, ch_max, target_ch = 0, target_silence = 0; - int ch_num; - - /* With N layers like: (ch1 ch2) (ch1 ch2 ch3 ch4) (ch1 ch2), output is normally 2+4+2=8ch. - * We want to find highest layer (ch1..4) = 4ch, add other channels to it and drop them */ - - /* find target "main" channels (will be first most of the time) */ - ch_num = 0; - ch_max = 0; - for (i = 0; i < ldata->layer_count; i++) { - int layer_chs = 0; - - mixing_info(ldata->layers[i], NULL, &layer_chs); - - if (ch_max < layer_chs || (ch_max == layer_chs && target_silence)) { - target_ch = ch_num; - target_chs = layer_chs; - target_layer = i; - ch_max = layer_chs; - /* avoid using silence as main if possible for minor optimization */ - target_silence = (ldata->layers[i]->coding_type == coding_SILENCE); - } - - ch_num += layer_chs; - } - - /* all silences? */ - if (!target_chs) { - target_ch = 0; - target_chs = 0; - target_layer = 0; - mixing_info(ldata->layers[0], NULL, &target_chs); - } - - /* add other channels to target (assumes standard channel mapping to simplify) - * most of the time all layers will have same number of channels though */ - ch_num = 0; - for (i = 0; i < ldata->layer_count; i++) { - int layer_chs = 0; - - if (target_layer == i) { - ch_num += target_chs; - continue; - } - - mixing_info(ldata->layers[i], NULL, &layer_chs); - - if (ldata->layers[i]->coding_type == coding_SILENCE) { - ch_num += layer_chs; - continue; /* unlikely but sometimes in Wwise */ - } - - if (layer_chs == target_chs) { - /* 1:1 mapping */ - for (ch = 0; ch < layer_chs; ch++) { - mixing_push_add(vgmstream, target_ch + ch, ch_num + ch, 1.0); - } - } - else { - const double vol_sqrt = 1 / sqrt(2); - - /* extra mixing for better sound in some cases (assumes layer_chs is lower than target_chs) */ - switch(layer_chs) { - case 1: - mixing_push_add(vgmstream, target_ch + 0, ch_num + 0, vol_sqrt); - mixing_push_add(vgmstream, target_ch + 1, ch_num + 0, vol_sqrt); - break; - case 2: - mixing_push_add(vgmstream, target_ch + 0, ch_num + 0, 1.0); - mixing_push_add(vgmstream, target_ch + 1, ch_num + 1, 1.0); - break; - default: /* less common */ - //TODO add other mixes, depends on target_chs + mapping (ex. 4.0 to 5.0 != 5.1, 2.1 xiph to 5.1 != 5.1 xiph) - for (ch = 0; ch < layer_chs; ch++) { - mixing_push_add(vgmstream, target_ch + ch, ch_num + ch, 1.0); - } - break; - } - } - - ch_num += layer_chs; - } - - /* drop non-target channels */ - ch_num = 0; - for (i = 0; i < ldata->layer_count; i++) { - - if (i < target_layer) { /* least common, hopefully (slower to drop chs 1 by 1) */ - int layer_chs = 0; - mixing_info(ldata->layers[i], NULL, &layer_chs); - - for (ch = 0; ch < layer_chs; ch++) { - mixing_push_downmix(vgmstream, ch_num); //+ ch - } - - //ch_num += layer_chs; /* dropped channels change this */ - } - else if (i == target_layer) { - ch_num += target_chs; - } - else { /* most common, hopefully (faster) */ - mixing_push_killmix(vgmstream, ch_num); - break; - } - } -} - - -void mixing_macro_layer(VGMSTREAM* vgmstream, int max, uint32_t mask, char mode) { - mixing_data *data = vgmstream->mixing_data; - int current, ch, output_channels, selected_channels; - - if (!data) - return; - - if (is_layered_auto(vgmstream, max, mode)) { - //;VGM_LOG("MIX: auto layer mode\n"); - mixing_macro_layer_auto(vgmstream, max, mode); - return; - } - //;VGM_LOG("MIX: regular layer mode\n"); - - if (max == 0) /* auto calculate */ - max = get_layered_max_channels(vgmstream); - - if (max <= 0 || data->output_channels <= max) - return; - - /* set all channels (non-existant channels will be ignored) */ - if (mask == 0) { - mask = ~mask; - } - - /* save before adding fake channels */ - output_channels = data->output_channels; - - /* count possibly set channels */ - selected_channels = 0; - for (ch = 0; ch < output_channels; ch++) { - selected_channels += (mask >> ch) & 1; - } - - /* make N fake channels at the beginning for easier calcs */ - for (ch = 0; ch < max; ch++) { - mixing_push_upmix(vgmstream, 0); - } - - /* add all layers in this order: ch0: 0, 0+N, 0+N*2 ... / ch1: 1, 1+N ... */ - current = 0; - for (ch = 0; ch < output_channels; ch++) { - double volume = 1.0; - - if (!((mask >> ch) & 1)) - continue; - - /* MIX_MACRO_VOCALS: same volume for all layers (for layered vocals) */ - /* MIX_MACRO_EQUAL: volume adjusted equally for all layers (for generic downmixing) */ - /* MIX_MACRO_BGM: volume adjusted depending on layers (for layered bgm) */ - if (mode == MIX_MACRO_BGM && ch < max) { - /* reduce a bit main channels (see below) */ - int channel_mixes = selected_channels / max; - if (current < selected_channels % (channel_mixes * max)) /* may be simplified? */ - channel_mixes += 1; - channel_mixes -= 1; /* better formula? */ - if (channel_mixes <= 0) /* ??? */ - channel_mixes = 1; - - volume = 1 / sqrt(channel_mixes); - } - if ((mode == MIX_MACRO_BGM && ch >= max) || (mode == MIX_MACRO_EQUAL)) { - /* find how many will be mixed in current channel (earlier channels receive more - * mixes than later ones, ex: selected 8ch + max 3ch: ch0=0+3+6, ch1=1+4+7, ch2=2+5) */ - int channel_mixes = selected_channels / max; - if (channel_mixes <= 0) /* ??? */ - channel_mixes = 1; - if (current < selected_channels % (channel_mixes * max)) /* may be simplified? */ - channel_mixes += 1; - - volume = 1 / sqrt(channel_mixes); /* "power" add */ - } - //;VGM_LOG("MIX: layer ch=%i, cur=%i, v=%f\n", ch, current, volume); - - mixing_push_add(vgmstream, current, max + ch, volume); /* ch adjusted considering upmixed channels */ - current++; - if (current >= max) - current = 0; - } - - /* remove all mixed channels */ - mixing_push_killmix(vgmstream, max); -} - -void mixing_macro_crosstrack(VGMSTREAM* vgmstream, int max) { - mixing_data *data = vgmstream->mixing_data; - int current, ch, track, track_ch, track_num, output_channels; - int32_t change_pos, change_next, change_time; - - if (!data) - return; - if (max <= 0 || data->output_channels <= max) - return; - if (!vgmstream->loop_flag) /* maybe force loop? */ - return; - - /* this probably only makes sense for even channels so upmix before if needed) */ - output_channels = data->output_channels; - if (output_channels % 2) { - mixing_push_upmix(vgmstream, output_channels); - output_channels += 1; - } - - /* set loops to hear all track changes */ - track_num = output_channels / max; - if (vgmstream->config.loop_count < track_num) { - vgmstream->config.loop_count = track_num; - vgmstream->config.loop_count_set = 1; - vgmstream->config.config_set = 1; - } - - ch = 0; - for (track = 0; track < track_num; track++) { - double volume = 1.0; /* won't play at the same time, no volume change needed */ - - int loop_pre = vgmstream->loop_start_sample; - int loop_samples = vgmstream->loop_end_sample - vgmstream->loop_start_sample; - change_pos = loop_pre + loop_samples * track; - change_next = loop_pre + loop_samples * (track + 1); - change_time = 15.0 * vgmstream->sample_rate; /* in secs */ - - for (track_ch = 0; track_ch < max; track_ch++) { - if (track > 0) { /* fade-in when prev track fades-out */ - mixing_push_fade(vgmstream, ch + track_ch, 0.0, volume, '(', -1, change_pos, change_pos + change_time, -1); - } - - if (track + 1 < track_num) { /* fade-out when next track fades-in */ - mixing_push_fade(vgmstream, ch + track_ch, volume, 0.0, ')', -1, change_next, change_next + change_time, -1); - } - } - - ch += max; - } - - /* mix all tracks into first */ - current = 0; - for (ch = max; ch < output_channels; ch++) { - mixing_push_add(vgmstream, current, ch, 1.0); /* won't play at the same time, no volume change needed */ - - current++; - if (current >= max) - current = 0; - } - - /* remove unneeded channels */ - mixing_push_killmix(vgmstream, max); -} - -void mixing_macro_crosslayer(VGMSTREAM* vgmstream, int max, char mode) { - mixing_data *data = vgmstream->mixing_data; - int current, ch, layer, layer_ch, layer_num, loop, output_channels; - int32_t change_pos, change_time; - - if (!data) - return; - if (max <= 0 || data->output_channels <= max) - return; - if (!vgmstream->loop_flag) /* maybe force loop? */ - return; - - /* this probably only makes sense for even channels so upmix before if needed) */ - output_channels = data->output_channels; - if (output_channels % 2) { - mixing_push_upmix(vgmstream, output_channels); - output_channels += 1; - } - - /* set loops to hear all track changes */ - layer_num = output_channels / max; - if (vgmstream->config.loop_count < layer_num) { - vgmstream->config.loop_count = layer_num; - vgmstream->config.loop_count_set = 1; - vgmstream->config.config_set = 1; - } - - /* MIX_MACRO_VOCALS: constant volume - * MIX_MACRO_EQUAL: sets fades to successively lower/equalize volume per loop for each layer - * (to keep final volume constant-ish), ex. 3 layers/loops, 2 max: - * - layer0 (ch0+1): loop0 --[1.0]--, loop1 )=1.0..0.7, loop2 )=0.7..0.5, loop3 --[0.5/end]-- - * - layer1 (ch2+3): loop0 --[0.0]--, loop1 (=0.0..0.7, loop2 )=0.7..0.5, loop3 --[0.5/end]-- - * - layer2 (ch4+5): loop0 --[0.0]--, loop1 ---[0.0]--, loop2 (=0.0..0.5, loop3 --[0.5/end]-- - * MIX_MACRO_BGM: similar but 1st layer (main) has higher/delayed volume: - * - layer0 (ch0+1): loop0 --[1.0]--, loop1 )=1.0..1.0, loop2 )=1.0..0.7, loop3 --[0.7/end]-- - */ - for (loop = 1; loop < layer_num; loop++) { - double volume1 = 1.0; - double volume2 = 1.0; - - int loop_pre = vgmstream->loop_start_sample; - int loop_samples = vgmstream->loop_end_sample - vgmstream->loop_start_sample; - change_pos = loop_pre + loop_samples * loop; - change_time = 10.0 * vgmstream->sample_rate; /* in secs */ - - if (mode == MIX_MACRO_EQUAL) { - volume1 = 1 / sqrt(loop + 0); - volume2 = 1 / sqrt(loop + 1); - } - - ch = 0; - for (layer = 0; layer < layer_num; layer++) { - char type; - - if (mode == MIX_MACRO_BGM) { - if (layer == 0) { - volume1 = 1 / sqrt(loop - 1 <= 0 ? 1 : loop - 1); - volume2 = 1 / sqrt(loop + 0); - } - else { - volume1 = 1 / sqrt(loop + 0); - volume2 = 1 / sqrt(loop + 1); - } - } - - if (layer > loop) { /* not playing yet (volume is implicitly 0.0 from first fade in) */ - continue; - } else if (layer == loop) { /* fades in for the first time */ - volume1 = 0.0; - type = '('; - } else { /* otherwise fades out to match other layers's volume */ - type = ')'; - } - - //;VGM_LOG("MIX: loop=%i, layer %i, vol1=%f, vol2=%f\n", loop, layer, volume1, volume2); - - for (layer_ch = 0; layer_ch < max; layer_ch++) { - mixing_push_fade(vgmstream, ch + layer_ch, volume1, volume2, type, -1, change_pos, change_pos + change_time, -1); - } - - ch += max; - } - } - - /* mix all tracks into first */ - current = 0; - for (ch = max; ch < output_channels; ch++) { - mixing_push_add(vgmstream, current, ch, 1.0); - - current++; - if (current >= max) - current = 0; - } - - /* remove unneeded channels */ - mixing_push_killmix(vgmstream, max); -} - - -typedef enum { - pos_FL = 0, - pos_FR = 1, - pos_FC = 2, - pos_LFE = 3, - pos_BL = 4, - pos_BR = 5, - pos_FLC = 6, - pos_FRC = 7, - pos_BC = 8, - pos_SL = 9, - pos_SR = 10, -} mixing_position_t; - -void mixing_macro_downmix(VGMSTREAM* vgmstream, int max /*, mapping_t output_mapping*/) { - mixing_data *data = vgmstream->mixing_data; - int ch, output_channels, mp_in, mp_out, ch_in, ch_out; - channel_mapping_t input_mapping, output_mapping; - const double vol_max = 1.0; - const double vol_sqrt = 1 / sqrt(2); - const double vol_half = 1 / 2; - double matrix[16][16] = {{0}}; - - - if (!data) - return; - if (max <= 1 || data->output_channels <= max || max >= 8) - return; - - /* assume WAV defaults if not set */ - input_mapping = vgmstream->channel_layout; - if (input_mapping == 0) { - switch(data->output_channels) { - case 1: input_mapping = mapping_MONO; break; - case 2: input_mapping = mapping_STEREO; break; - case 3: input_mapping = mapping_2POINT1; break; - case 4: input_mapping = mapping_QUAD; break; - case 5: input_mapping = mapping_5POINT0; break; - case 6: input_mapping = mapping_5POINT1; break; - case 7: input_mapping = mapping_7POINT0; break; - case 8: input_mapping = mapping_7POINT1; break; - default: return; - } - } - - /* build mapping matrix[input channel][output channel] = volume, - * using standard WAV/AC3 downmix formulas - * - https://www.audiokinetic.com/library/edge/?source=Help&id=downmix_tables - * - https://www.audiokinetic.com/library/edge/?source=Help&id=standard_configurations - */ - switch(max) { - case 1: - output_mapping = mapping_MONO; - matrix[pos_FL][pos_FC] = vol_sqrt; - matrix[pos_FR][pos_FC] = vol_sqrt; - matrix[pos_FC][pos_FC] = vol_max; - matrix[pos_SL][pos_FC] = vol_half; - matrix[pos_SR][pos_FC] = vol_half; - matrix[pos_BL][pos_FC] = vol_half; - matrix[pos_BR][pos_FC] = vol_half; - break; - case 2: - output_mapping = mapping_STEREO; - matrix[pos_FL][pos_FL] = vol_max; - matrix[pos_FR][pos_FR] = vol_max; - matrix[pos_FC][pos_FL] = vol_sqrt; - matrix[pos_FC][pos_FR] = vol_sqrt; - matrix[pos_SL][pos_FL] = vol_sqrt; - matrix[pos_SR][pos_FR] = vol_sqrt; - matrix[pos_BL][pos_FL] = vol_sqrt; - matrix[pos_BR][pos_FR] = vol_sqrt; - break; - default: - /* not sure if +3ch would use FC/LFE, SL/BR and whatnot without passing extra config, so ignore for now */ - return; - } - - /* save and make N fake channels at the beginning for easier calcs */ - output_channels = data->output_channels; - for (ch = 0; ch < max; ch++) { - mixing_push_upmix(vgmstream, 0); - } - - /* downmix */ - ch_in = 0; - for (mp_in = 0; mp_in < 16; mp_in++) { - /* read input mapping (ex. 5.1) and find channel */ - if (!(input_mapping & (1< max) - break; - } - - ch_in++; - if (ch_in >= output_channels) - break; - } - - /* remove unneeded channels */ - mixing_push_killmix(vgmstream, max); -} /* ******************************************************************* */ diff --git a/Frameworks/vgmstream/vgmstream/src/base/mixing_commands.c b/Frameworks/vgmstream/vgmstream/src/base/mixing_commands.c new file mode 100644 index 000000000..44c138d90 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/base/mixing_commands.c @@ -0,0 +1,254 @@ +#include "../vgmstream.h" +#include "../util/channel_mappings.h" +#include "mixing.h" +#include "mixing_priv.h" +#include +#include + + +static int add_mixing(VGMSTREAM* vgmstream, mix_command_data *mix) { + mixing_data *data = vgmstream->mixing_data; + if (!data) return 0; + + + if (data->mixing_on) { + VGM_LOG("MIX: ignoring new mixes when mixing active\n"); + return 0; /* to avoid down/upmixing after activation */ + } + + if (data->mixing_count + 1 > data->mixing_size) { + VGM_LOG("MIX: too many mixes\n"); + return 0; + } + + data->mixing_chain[data->mixing_count] = *mix; /* memcpy */ + data->mixing_count++; + + + if (mix->command == MIX_FADE) { + data->has_fade = 1; + } + else { + data->has_non_fade = 1; + } + + //;VGM_LOG("MIX: total %i\n", data->mixing_count); + return 1; +} + + +void mixing_push_swap(VGMSTREAM* vgmstream, int ch_dst, int ch_src) { + mixing_data *data = vgmstream->mixing_data; + mix_command_data mix = {0}; + + if (ch_dst < 0 || ch_src < 0 || ch_dst == ch_src) return; + if (!data || ch_dst >= data->output_channels || ch_src >= data->output_channels) return; + mix.command = MIX_SWAP; + mix.ch_dst = ch_dst; + mix.ch_src = ch_src; + + add_mixing(vgmstream, &mix); +} + +void mixing_push_add(VGMSTREAM* vgmstream, int ch_dst, int ch_src, double volume) { + mixing_data *data = vgmstream->mixing_data; + mix_command_data mix = {0}; + if (!data) return; + + //if (volume < 0.0) return; /* negative volume inverts the waveform */ + if (volume == 0.0) return; /* ch_src becomes silent and nothing is added */ + if (ch_dst < 0 || ch_src < 0) return; + if (!data || ch_dst >= data->output_channels || ch_src >= data->output_channels) return; + + mix.command = (volume == 1.0) ? MIX_ADD_COPY : MIX_ADD; + mix.ch_dst = ch_dst; + mix.ch_src = ch_src; + mix.vol = volume; + + //;VGM_LOG("MIX: add %i+%i*%f\n", ch_dst,ch_src,volume); + add_mixing(vgmstream, &mix); +} + +void mixing_push_volume(VGMSTREAM* vgmstream, int ch_dst, double volume) { + mixing_data *data = vgmstream->mixing_data; + mix_command_data mix = {0}; + + //if (ch_dst < 0) return; /* means all channels */ + //if (volume < 0.0) return; /* negative volume inverts the waveform */ + if (volume == 1.0) return; /* no change */ + if (!data || ch_dst >= data->output_channels) return; + + mix.command = MIX_VOLUME; //if (volume == 0.0) MIX_VOLUME0 /* could simplify */ + mix.ch_dst = ch_dst; + mix.vol = volume; + + //;VGM_LOG("MIX: volume %i*%f\n", ch_dst,volume); + add_mixing(vgmstream, &mix); +} + +void mixing_push_limit(VGMSTREAM* vgmstream, int ch_dst, double volume) { + mixing_data *data = vgmstream->mixing_data; + mix_command_data mix = {0}; + + //if (ch_dst < 0) return; /* means all channels */ + if (volume < 0.0) return; + if (volume == 1.0) return; /* no actual difference */ + if (!data || ch_dst >= data->output_channels) return; + //if (volume == 0.0) return; /* dumb but whatevs */ + + mix.command = MIX_LIMIT; + mix.ch_dst = ch_dst; + mix.vol = volume; + + add_mixing(vgmstream, &mix); +} + +void mixing_push_upmix(VGMSTREAM* vgmstream, int ch_dst) { + mixing_data *data = vgmstream->mixing_data; + mix_command_data mix = {0}; + int ok; + + if (ch_dst < 0) return; + if (!data || ch_dst > data->output_channels || data->output_channels +1 > VGMSTREAM_MAX_CHANNELS) return; + /* dst can be == output_channels here, since we are inserting */ + + mix.command = MIX_UPMIX; + mix.ch_dst = ch_dst; + + ok = add_mixing(vgmstream, &mix); + if (ok) { + data->output_channels += 1; + if (data->mixing_channels < data->output_channels) + data->mixing_channels = data->output_channels; + } +} + +void mixing_push_downmix(VGMSTREAM* vgmstream, int ch_dst) { + mixing_data *data = vgmstream->mixing_data; + mix_command_data mix = {0}; + int ok; + + if (ch_dst < 0) return; + if (!data || ch_dst >= data->output_channels || data->output_channels - 1 < 1) return; + + mix.command = MIX_DOWNMIX; + mix.ch_dst = ch_dst; + + ok = add_mixing(vgmstream, &mix); + if (ok) { + data->output_channels -= 1; + } +} + +void mixing_push_killmix(VGMSTREAM* vgmstream, int ch_dst) { + mixing_data *data = vgmstream->mixing_data; + mix_command_data mix = {0}; + int ok; + + if (ch_dst <= 0) return; /* can't kill from first channel */ + if (!data || ch_dst >= data->output_channels) return; + + mix.command = MIX_KILLMIX; + mix.ch_dst = ch_dst; + + //;VGM_LOG("MIX: killmix %i\n", ch_dst); + ok = add_mixing(vgmstream, &mix); + if (ok) { + data->output_channels = ch_dst; /* clamp channels */ + } +} + + +static mix_command_data* get_last_fade(mixing_data *data, int target_channel) { + int i; + for (i = data->mixing_count; i > 0; i--) { + mix_command_data *mix = &data->mixing_chain[i-1]; + if (mix->command != MIX_FADE) + continue; + if (mix->ch_dst == target_channel) + return mix; + } + + return NULL; +} + + +void mixing_push_fade(VGMSTREAM* vgmstream, int ch_dst, double vol_start, double vol_end, char shape, + int32_t time_pre, int32_t time_start, int32_t time_end, int32_t time_post) { + mixing_data *data = vgmstream->mixing_data; + mix_command_data mix = {0}; + mix_command_data *mix_prev; + + + //if (ch_dst < 0) return; /* means all channels */ + if (!data || ch_dst >= data->output_channels) return; + if (time_pre > time_start || time_start > time_end || (time_post >= 0 && time_end > time_post)) return; + if (time_start < 0 || time_end < 0) return; + //if (time_pre < 0 || time_post < 0) return; /* special meaning of file start/end */ + //if (vol_start == vol_end) /* weird but let in case of being used to cancel others fades... maybe? */ + + if (shape == '{' || shape == '}') + shape = 'E'; + if (shape == '(' || shape == ')') + shape = 'H'; + + mix.command = MIX_FADE; + mix.ch_dst = ch_dst; + mix.vol_start = vol_start; + mix.vol_end = vol_end; + mix.shape = shape; + mix.time_pre = time_pre; + mix.time_start = time_start; + mix.time_end = time_end; + mix.time_post = time_post; + + + /* cancel fades and optimize a bit when using negative pre/post: + * - fades work like this: + * <----------|----------|----------> + * pre1 start1 end1 post1 + * - when pre and post are set nothing is done (fade is exact and multiple fades may overlap) + * - when previous fade's post or current fade's pre are negative (meaning file end/start) + * they should cancel each other (to allow chaining fade-in + fade-out + fade-in + etc): + * <----------|----------|----------| |----------|----------|----------> + * pre1 start1 end1 post1 pre2 start2 end2 post2 + * - other cases (previous fade is actually after/in-between current fade) are ignored + * as they're uncommon and hard to optimize + * fades cancel fades of the same channel, and 'all channel' (-1) fades also cancel 'all channels' + */ + mix_prev = get_last_fade(data, mix.ch_dst); + if (mix_prev == NULL) { + if (vol_start == 1.0 && time_pre < 0) + time_pre = time_start; /* fade-out helds default volume before fade start can be clamped */ + if (vol_end == 1.0 && time_post < 0) + time_post = time_end; /* fade-in helds default volume after fade end can be clamped */ + } + else if (mix_prev->time_post < 0 || mix.time_pre < 0) { + int is_prev = 1; + /* test if prev is really cancelled by this */ + if ((mix_prev->time_end > mix.time_start) || + (mix_prev->time_post >= 0 && mix_prev->time_post > mix.time_start) || + (mix.time_pre >= 0 && mix.time_pre < mix_prev->time_end)) + is_prev = 0; + + if (is_prev) { + /* change negative values to actual points */ + if (mix_prev->time_post < 0 && mix.time_pre < 0) { + mix_prev->time_post = mix_prev->time_end; + mix.time_pre = mix_prev->time_post; + } + + if (mix_prev->time_post >= 0 && mix.time_pre < 0) { + mix.time_pre = mix_prev->time_post; + } + else if (mix_prev->time_post < 0 && mix.time_pre >= 0) { + mix_prev->time_post = mix.time_pre; + } + /* else: both define start/ends, do nothing */ + } + /* should only modify prev if add_mixing but meh */ + } + + //;VGM_LOG("MIX: fade %i^%f~%f=%c@%i~%i~%i~%i\n", ch_dst, vol_start, vol_end, shape, time_pre, time_start, time_end, time_post); + add_mixing(vgmstream, &mix); +} diff --git a/Frameworks/vgmstream/vgmstream/src/base/mixing_fades.h b/Frameworks/vgmstream/vgmstream/src/base/mixing_fades.h new file mode 100644 index 000000000..dcf66d338 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/base/mixing_fades.h @@ -0,0 +1,171 @@ +#ifndef _MIXING_FADE_H_ +#define _MIXING_FADE_H_ + +#include "mixing_priv.h" +#include +#include + +#define MIXING_PI 3.14159265358979323846f + + +static inline int is_fade_active(mixing_data *data, int32_t current_start, int32_t current_end) { + int i; + + for (i = 0; i < data->mixing_count; i++) { + mix_command_data *mix = &data->mixing_chain[i]; + int32_t fade_start, fade_end; + float vol_start = mix->vol_start; + + if (mix->command != MIX_FADE) + continue; + + /* check is current range falls within a fade + * (assuming fades were already optimized on add) */ + if (mix->time_pre < 0 && vol_start == 1.0) { + fade_start = mix->time_start; /* ignore unused */ + } + else { + fade_start = mix->time_pre < 0 ? 0 : mix->time_pre; + } + fade_end = mix->time_post < 0 ? INT_MAX : mix->time_post; + + //;VGM_LOG("MIX: fade test, tp=%i, te=%i, cs=%i, ce=%i\n", mix->time_pre, mix->time_post, current_start, current_end); + if (current_start < fade_end && current_end > fade_start) { + //;VGM_LOG("MIX: fade active, cs=%i < fe=%i and ce=%i > fs=%i\n", current_start, fade_end, current_end, fade_start); + return 1; + } + } + + return 0; +} + +static inline int32_t get_current_pos(VGMSTREAM* vgmstream, int32_t sample_count) { + int32_t current_pos; + + if (vgmstream->config_enabled) { + return vgmstream->pstate.play_position; + } + + if (vgmstream->loop_flag && vgmstream->loop_count > 0) { + int loop_pre = vgmstream->loop_start_sample; /* samples before looping */ + int loop_into = (vgmstream->current_sample - vgmstream->loop_start_sample); /* samples after loop */ + int loop_samples = (vgmstream->loop_end_sample - vgmstream->loop_start_sample); /* looped section */ + + current_pos = loop_pre + (loop_samples * vgmstream->loop_count) + loop_into - sample_count; + } + else { + current_pos = (vgmstream->current_sample - sample_count); + } + + return current_pos; +} + +static inline float get_fade_gain_curve(char shape, float index) { + float gain; + + /* don't bother doing calcs near 0.0/1.0 */ + if (index <= 0.0001f || index >= 0.9999f) { + return index; + } + + //todo optimizations: interleave calcs, maybe use cosf, powf, etc? (with extra defines) + + /* (curve math mostly from SoX/FFmpeg) */ + switch(shape) { + /* 2.5f in L/E 'pow' is the attenuation factor, where 5.0 (100db) is common but a bit fast + * (alt calculations with 'exp' from FFmpeg use (factor)*ln(0.1) = -NN.N... */ + + case 'E': /* exponential (for fade-outs, closer to natural decay of sound) */ + //gain = pow(0.1f, (1.0f - index) * 2.5f); + gain = exp(-5.75646273248511f * (1.0f - index)); + break; + case 'L': /* logarithmic (inverse of the above, maybe for crossfades) */ + //gain = 1 - pow(0.1f, (index) * 2.5f); + gain = 1 - exp(-5.75646273248511f * (index)); + break; + + case 'H': /* raised sine wave or cosine wave (for more musical crossfades) */ + gain = (1.0f - cos(index * MIXING_PI)) / 2.0f; + break; + + case 'Q': /* quarter of sine wave (for musical fades) */ + gain = sin(index * MIXING_PI / 2.0f); + break; + + case 'p': /* parabola (maybe for crossfades) */ + gain = 1.0f - sqrt(1.0f - index); + break; + case 'P': /* inverted parabola (maybe for fades) */ + gain = (1.0f - (1.0f - index) * (1.0f - index)); + break; + + case 'T': /* triangular/linear (simpler/sharper fades) */ + default: + gain = index; + break; + } + + return gain; +} + +static int get_fade_gain(mix_command_data *mix, float *out_cur_vol, int32_t current_subpos) { + float cur_vol = 0.0f; + + if ((current_subpos >= mix->time_pre || mix->time_pre < 0) && current_subpos < mix->time_start) { + cur_vol = mix->vol_start; /* before */ + } + else if (current_subpos >= mix->time_end && (current_subpos < mix->time_post || mix->time_post < 0)) { + cur_vol = mix->vol_end; /* after */ + } + else if (current_subpos >= mix->time_start && current_subpos < mix->time_end) { + /* in between */ + float range_vol, range_dur, range_idx, index, gain; + + if (mix->vol_start < mix->vol_end) { /* fade in */ + range_vol = mix->vol_end - mix->vol_start; + range_dur = mix->time_end - mix->time_start; + range_idx = current_subpos - mix->time_start; + index = range_idx / range_dur; + } else { /* fade out */ + range_vol = mix->vol_end - mix->vol_start; + range_dur = mix->time_end - mix->time_start; + range_idx = mix->time_end - current_subpos; + index = range_idx / range_dur; + } + + /* Fading is done like this: + * - find current position within fade duration + * - get linear % (or rather, index from 0.0 .. 1.0) of duration + * - apply shape to % (from linear fade to curved fade) + * - get final volume for that point + * + * Roughly speaking some curve shapes are better for fades (decay rate is more natural + * sounding in that highest to mid/low happens faster but low to lowest takes more time, + * kinda like a gunshot or bell), and others for crossfades (decay of fade-in + fade-out + * is adjusted so that added volume level stays constant-ish). + * + * As curves can fade in two ways ('normal' and curving 'the other way'), they are adjusted + * to get 'normal' shape on both fades (by reversing index and making 1 - gain), thus some + * curves are complementary (exponential fade-in ~= logarithmic fade-out); the following + * are described taking fade-in = normal. + */ + gain = get_fade_gain_curve(mix->shape, index); + + if (mix->vol_start < mix->vol_end) { /* fade in */ + cur_vol = mix->vol_start + range_vol * gain; + } else { /* fade out */ + cur_vol = mix->vol_end - range_vol * gain; //mix->vol_start - range_vol * (1 - gain); + } + } + else { + /* fade is outside reach */ + goto fail; + } + + *out_cur_vol = cur_vol; + return 1; +fail: + return 0; +} + +#endif diff --git a/Frameworks/vgmstream/vgmstream/src/base/mixing_macros.c b/Frameworks/vgmstream/vgmstream/src/base/mixing_macros.c new file mode 100644 index 000000000..1df002ee6 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/base/mixing_macros.c @@ -0,0 +1,578 @@ +#include "../vgmstream.h" +#include "../util/channel_mappings.h" +#include "mixing.h" +#include "mixing_priv.h" +#include +#include + + +#define MIX_MACRO_VOCALS 'v' +#define MIX_MACRO_EQUAL 'e' +#define MIX_MACRO_BGM 'b' + +void mixing_macro_volume(VGMSTREAM* vgmstream, double volume, uint32_t mask) { + mixing_data *data = vgmstream->mixing_data; + int ch; + + if (!data) + return; + + if (mask == 0) { + mixing_push_volume(vgmstream, -1, volume); + return; + } + + for (ch = 0; ch < data->output_channels; ch++) { + if (!((mask >> ch) & 1)) + continue; + mixing_push_volume(vgmstream, ch, volume); + } +} + +void mixing_macro_track(VGMSTREAM* vgmstream, uint32_t mask) { + mixing_data *data = vgmstream->mixing_data; + int ch; + + if (!data) + return; + + if (mask == 0) { + return; + } + + /* reverse remove all channels (easier this way as when removing channels numbers change) */ + for (ch = data->output_channels - 1; ch >= 0; ch--) { + if ((mask >> ch) & 1) + continue; + mixing_push_downmix(vgmstream, ch); + } +} + + +/* get highest channel count */ +static int get_layered_max_channels(VGMSTREAM* vgmstream) { + int i, max; + layered_layout_data* data; + + if (vgmstream->layout_type != layout_layered) + return 0; + + data = vgmstream->layout_data; + + max = 0; + for (i = 0; i < data->layer_count; i++) { + int output_channels = 0; + + mixing_info(data->layers[i], NULL, &output_channels); + + if (max < output_channels) + max = output_channels; + } + + return max; +} + +static int is_layered_auto(VGMSTREAM* vgmstream, int max, char mode) { + int i; + mixing_data *data = vgmstream->mixing_data; + layered_layout_data* l_data; + + + if (vgmstream->layout_type != layout_layered) + return 0; + + /* no channels set and only vocals for now */ + if (max > 0 || mode != MIX_MACRO_VOCALS) + return 0; + + /* no channel down/upmixing (cannot guess output) */ + for (i = 0; i < data->mixing_count; i++) { + mix_command_t mix = data->mixing_chain[i].command; + if (mix == MIX_UPMIX || mix == MIX_DOWNMIX || mix == MIX_KILLMIX) /*mix == MIX_SWAP || ??? */ + return 0; + } + + /* only previsible cases */ + l_data = vgmstream->layout_data; + for (i = 0; i < l_data->layer_count; i++) { + int output_channels = 0; + + mixing_info(l_data->layers[i], NULL, &output_channels); + + if (output_channels > 8) + return 0; + } + + return 1; +} + + +/* special layering, where channels are respected (so Ls only go to Ls), also more optimized */ +static void mixing_macro_layer_auto(VGMSTREAM* vgmstream, int max, char mode) { + layered_layout_data* ldata = vgmstream->layout_data; + int i, ch; + int target_layer = 0, target_chs = 0, ch_max, target_ch = 0, target_silence = 0; + int ch_num; + + /* With N layers like: (ch1 ch2) (ch1 ch2 ch3 ch4) (ch1 ch2), output is normally 2+4+2=8ch. + * We want to find highest layer (ch1..4) = 4ch, add other channels to it and drop them */ + + /* find target "main" channels (will be first most of the time) */ + ch_num = 0; + ch_max = 0; + for (i = 0; i < ldata->layer_count; i++) { + int layer_chs = 0; + + mixing_info(ldata->layers[i], NULL, &layer_chs); + + if (ch_max < layer_chs || (ch_max == layer_chs && target_silence)) { + target_ch = ch_num; + target_chs = layer_chs; + target_layer = i; + ch_max = layer_chs; + /* avoid using silence as main if possible for minor optimization */ + target_silence = (ldata->layers[i]->coding_type == coding_SILENCE); + } + + ch_num += layer_chs; + } + + /* all silences? */ + if (!target_chs) { + target_ch = 0; + target_chs = 0; + target_layer = 0; + mixing_info(ldata->layers[0], NULL, &target_chs); + } + + /* add other channels to target (assumes standard channel mapping to simplify) + * most of the time all layers will have same number of channels though */ + ch_num = 0; + for (i = 0; i < ldata->layer_count; i++) { + int layer_chs = 0; + + if (target_layer == i) { + ch_num += target_chs; + continue; + } + + mixing_info(ldata->layers[i], NULL, &layer_chs); + + if (ldata->layers[i]->coding_type == coding_SILENCE) { + ch_num += layer_chs; + continue; /* unlikely but sometimes in Wwise */ + } + + if (layer_chs == target_chs) { + /* 1:1 mapping */ + for (ch = 0; ch < layer_chs; ch++) { + mixing_push_add(vgmstream, target_ch + ch, ch_num + ch, 1.0); + } + } + else { + const double vol_sqrt = 1 / sqrt(2); + + /* extra mixing for better sound in some cases (assumes layer_chs is lower than target_chs) */ + switch(layer_chs) { + case 1: + mixing_push_add(vgmstream, target_ch + 0, ch_num + 0, vol_sqrt); + mixing_push_add(vgmstream, target_ch + 1, ch_num + 0, vol_sqrt); + break; + case 2: + mixing_push_add(vgmstream, target_ch + 0, ch_num + 0, 1.0); + mixing_push_add(vgmstream, target_ch + 1, ch_num + 1, 1.0); + break; + default: /* less common */ + //TODO add other mixes, depends on target_chs + mapping (ex. 4.0 to 5.0 != 5.1, 2.1 xiph to 5.1 != 5.1 xiph) + for (ch = 0; ch < layer_chs; ch++) { + mixing_push_add(vgmstream, target_ch + ch, ch_num + ch, 1.0); + } + break; + } + } + + ch_num += layer_chs; + } + + /* drop non-target channels */ + ch_num = 0; + for (i = 0; i < ldata->layer_count; i++) { + + if (i < target_layer) { /* least common, hopefully (slower to drop chs 1 by 1) */ + int layer_chs = 0; + mixing_info(ldata->layers[i], NULL, &layer_chs); + + for (ch = 0; ch < layer_chs; ch++) { + mixing_push_downmix(vgmstream, ch_num); //+ ch + } + + //ch_num += layer_chs; /* dropped channels change this */ + } + else if (i == target_layer) { + ch_num += target_chs; + } + else { /* most common, hopefully (faster) */ + mixing_push_killmix(vgmstream, ch_num); + break; + } + } +} + + +void mixing_macro_layer(VGMSTREAM* vgmstream, int max, uint32_t mask, char mode) { + mixing_data *data = vgmstream->mixing_data; + int current, ch, output_channels, selected_channels; + + if (!data) + return; + + if (is_layered_auto(vgmstream, max, mode)) { + //;VGM_LOG("MIX: auto layer mode\n"); + mixing_macro_layer_auto(vgmstream, max, mode); + return; + } + //;VGM_LOG("MIX: regular layer mode\n"); + + if (max == 0) /* auto calculate */ + max = get_layered_max_channels(vgmstream); + + if (max <= 0 || data->output_channels <= max) + return; + + /* set all channels (non-existant channels will be ignored) */ + if (mask == 0) { + mask = ~mask; + } + + /* save before adding fake channels */ + output_channels = data->output_channels; + + /* count possibly set channels */ + selected_channels = 0; + for (ch = 0; ch < output_channels; ch++) { + selected_channels += (mask >> ch) & 1; + } + + /* make N fake channels at the beginning for easier calcs */ + for (ch = 0; ch < max; ch++) { + mixing_push_upmix(vgmstream, 0); + } + + /* add all layers in this order: ch0: 0, 0+N, 0+N*2 ... / ch1: 1, 1+N ... */ + current = 0; + for (ch = 0; ch < output_channels; ch++) { + double volume = 1.0; + + if (!((mask >> ch) & 1)) + continue; + + /* MIX_MACRO_VOCALS: same volume for all layers (for layered vocals) */ + /* MIX_MACRO_EQUAL: volume adjusted equally for all layers (for generic downmixing) */ + /* MIX_MACRO_BGM: volume adjusted depending on layers (for layered bgm) */ + if (mode == MIX_MACRO_BGM && ch < max) { + /* reduce a bit main channels (see below) */ + int channel_mixes = selected_channels / max; + if (current < selected_channels % (channel_mixes * max)) /* may be simplified? */ + channel_mixes += 1; + channel_mixes -= 1; /* better formula? */ + if (channel_mixes <= 0) /* ??? */ + channel_mixes = 1; + + volume = 1 / sqrt(channel_mixes); + } + if ((mode == MIX_MACRO_BGM && ch >= max) || (mode == MIX_MACRO_EQUAL)) { + /* find how many will be mixed in current channel (earlier channels receive more + * mixes than later ones, ex: selected 8ch + max 3ch: ch0=0+3+6, ch1=1+4+7, ch2=2+5) */ + int channel_mixes = selected_channels / max; + if (channel_mixes <= 0) /* ??? */ + channel_mixes = 1; + if (current < selected_channels % (channel_mixes * max)) /* may be simplified? */ + channel_mixes += 1; + + volume = 1 / sqrt(channel_mixes); /* "power" add */ + } + //;VGM_LOG("MIX: layer ch=%i, cur=%i, v=%f\n", ch, current, volume); + + mixing_push_add(vgmstream, current, max + ch, volume); /* ch adjusted considering upmixed channels */ + current++; + if (current >= max) + current = 0; + } + + /* remove all mixed channels */ + mixing_push_killmix(vgmstream, max); +} + +void mixing_macro_crosstrack(VGMSTREAM* vgmstream, int max) { + mixing_data *data = vgmstream->mixing_data; + int current, ch, track, track_ch, track_num, output_channels; + int32_t change_pos, change_next, change_time; + + if (!data) + return; + if (max <= 0 || data->output_channels <= max) + return; + if (!vgmstream->loop_flag) /* maybe force loop? */ + return; + + /* this probably only makes sense for even channels so upmix before if needed) */ + output_channels = data->output_channels; + if (output_channels % 2) { + mixing_push_upmix(vgmstream, output_channels); + output_channels += 1; + } + + /* set loops to hear all track changes */ + track_num = output_channels / max; + if (vgmstream->config.loop_count < track_num) { + vgmstream->config.loop_count = track_num; + vgmstream->config.loop_count_set = 1; + vgmstream->config.config_set = 1; + } + + ch = 0; + for (track = 0; track < track_num; track++) { + double volume = 1.0; /* won't play at the same time, no volume change needed */ + + int loop_pre = vgmstream->loop_start_sample; + int loop_samples = vgmstream->loop_end_sample - vgmstream->loop_start_sample; + change_pos = loop_pre + loop_samples * track; + change_next = loop_pre + loop_samples * (track + 1); + change_time = 15.0 * vgmstream->sample_rate; /* in secs */ + + for (track_ch = 0; track_ch < max; track_ch++) { + if (track > 0) { /* fade-in when prev track fades-out */ + mixing_push_fade(vgmstream, ch + track_ch, 0.0, volume, '(', -1, change_pos, change_pos + change_time, -1); + } + + if (track + 1 < track_num) { /* fade-out when next track fades-in */ + mixing_push_fade(vgmstream, ch + track_ch, volume, 0.0, ')', -1, change_next, change_next + change_time, -1); + } + } + + ch += max; + } + + /* mix all tracks into first */ + current = 0; + for (ch = max; ch < output_channels; ch++) { + mixing_push_add(vgmstream, current, ch, 1.0); /* won't play at the same time, no volume change needed */ + + current++; + if (current >= max) + current = 0; + } + + /* remove unneeded channels */ + mixing_push_killmix(vgmstream, max); +} + +void mixing_macro_crosslayer(VGMSTREAM* vgmstream, int max, char mode) { + mixing_data *data = vgmstream->mixing_data; + int current, ch, layer, layer_ch, layer_num, loop, output_channels; + int32_t change_pos, change_time; + + if (!data) + return; + if (max <= 0 || data->output_channels <= max) + return; + if (!vgmstream->loop_flag) /* maybe force loop? */ + return; + + /* this probably only makes sense for even channels so upmix before if needed) */ + output_channels = data->output_channels; + if (output_channels % 2) { + mixing_push_upmix(vgmstream, output_channels); + output_channels += 1; + } + + /* set loops to hear all track changes */ + layer_num = output_channels / max; + if (vgmstream->config.loop_count < layer_num) { + vgmstream->config.loop_count = layer_num; + vgmstream->config.loop_count_set = 1; + vgmstream->config.config_set = 1; + } + + /* MIX_MACRO_VOCALS: constant volume + * MIX_MACRO_EQUAL: sets fades to successively lower/equalize volume per loop for each layer + * (to keep final volume constant-ish), ex. 3 layers/loops, 2 max: + * - layer0 (ch0+1): loop0 --[1.0]--, loop1 )=1.0..0.7, loop2 )=0.7..0.5, loop3 --[0.5/end]-- + * - layer1 (ch2+3): loop0 --[0.0]--, loop1 (=0.0..0.7, loop2 )=0.7..0.5, loop3 --[0.5/end]-- + * - layer2 (ch4+5): loop0 --[0.0]--, loop1 ---[0.0]--, loop2 (=0.0..0.5, loop3 --[0.5/end]-- + * MIX_MACRO_BGM: similar but 1st layer (main) has higher/delayed volume: + * - layer0 (ch0+1): loop0 --[1.0]--, loop1 )=1.0..1.0, loop2 )=1.0..0.7, loop3 --[0.7/end]-- + */ + for (loop = 1; loop < layer_num; loop++) { + double volume1 = 1.0; + double volume2 = 1.0; + + int loop_pre = vgmstream->loop_start_sample; + int loop_samples = vgmstream->loop_end_sample - vgmstream->loop_start_sample; + change_pos = loop_pre + loop_samples * loop; + change_time = 10.0 * vgmstream->sample_rate; /* in secs */ + + if (mode == MIX_MACRO_EQUAL) { + volume1 = 1 / sqrt(loop + 0); + volume2 = 1 / sqrt(loop + 1); + } + + ch = 0; + for (layer = 0; layer < layer_num; layer++) { + char type; + + if (mode == MIX_MACRO_BGM) { + if (layer == 0) { + volume1 = 1 / sqrt(loop - 1 <= 0 ? 1 : loop - 1); + volume2 = 1 / sqrt(loop + 0); + } + else { + volume1 = 1 / sqrt(loop + 0); + volume2 = 1 / sqrt(loop + 1); + } + } + + if (layer > loop) { /* not playing yet (volume is implicitly 0.0 from first fade in) */ + continue; + } else if (layer == loop) { /* fades in for the first time */ + volume1 = 0.0; + type = '('; + } else { /* otherwise fades out to match other layers's volume */ + type = ')'; + } + + //;VGM_LOG("MIX: loop=%i, layer %i, vol1=%f, vol2=%f\n", loop, layer, volume1, volume2); + + for (layer_ch = 0; layer_ch < max; layer_ch++) { + mixing_push_fade(vgmstream, ch + layer_ch, volume1, volume2, type, -1, change_pos, change_pos + change_time, -1); + } + + ch += max; + } + } + + /* mix all tracks into first */ + current = 0; + for (ch = max; ch < output_channels; ch++) { + mixing_push_add(vgmstream, current, ch, 1.0); + + current++; + if (current >= max) + current = 0; + } + + /* remove unneeded channels */ + mixing_push_killmix(vgmstream, max); +} + + +typedef enum { + pos_FL = 0, + pos_FR = 1, + pos_FC = 2, + pos_LFE = 3, + pos_BL = 4, + pos_BR = 5, + pos_FLC = 6, + pos_FRC = 7, + pos_BC = 8, + pos_SL = 9, + pos_SR = 10, +} mixing_position_t; + +void mixing_macro_downmix(VGMSTREAM* vgmstream, int max /*, mapping_t output_mapping*/) { + mixing_data *data = vgmstream->mixing_data; + int ch, output_channels, mp_in, mp_out, ch_in, ch_out; + channel_mapping_t input_mapping, output_mapping; + const double vol_max = 1.0; + const double vol_sqrt = 1 / sqrt(2); + const double vol_half = 1 / 2; + double matrix[16][16] = {{0}}; + + + if (!data) + return; + if (max <= 1 || data->output_channels <= max || max >= 8) + return; + + /* assume WAV defaults if not set */ + input_mapping = vgmstream->channel_layout; + if (input_mapping == 0) { + switch(data->output_channels) { + case 1: input_mapping = mapping_MONO; break; + case 2: input_mapping = mapping_STEREO; break; + case 3: input_mapping = mapping_2POINT1; break; + case 4: input_mapping = mapping_QUAD; break; + case 5: input_mapping = mapping_5POINT0; break; + case 6: input_mapping = mapping_5POINT1; break; + case 7: input_mapping = mapping_7POINT0; break; + case 8: input_mapping = mapping_7POINT1; break; + default: return; + } + } + + /* build mapping matrix[input channel][output channel] = volume, + * using standard WAV/AC3 downmix formulas + * - https://www.audiokinetic.com/library/edge/?source=Help&id=downmix_tables + * - https://www.audiokinetic.com/library/edge/?source=Help&id=standard_configurations + */ + switch(max) { + case 1: + output_mapping = mapping_MONO; + matrix[pos_FL][pos_FC] = vol_sqrt; + matrix[pos_FR][pos_FC] = vol_sqrt; + matrix[pos_FC][pos_FC] = vol_max; + matrix[pos_SL][pos_FC] = vol_half; + matrix[pos_SR][pos_FC] = vol_half; + matrix[pos_BL][pos_FC] = vol_half; + matrix[pos_BR][pos_FC] = vol_half; + break; + case 2: + output_mapping = mapping_STEREO; + matrix[pos_FL][pos_FL] = vol_max; + matrix[pos_FR][pos_FR] = vol_max; + matrix[pos_FC][pos_FL] = vol_sqrt; + matrix[pos_FC][pos_FR] = vol_sqrt; + matrix[pos_SL][pos_FL] = vol_sqrt; + matrix[pos_SR][pos_FR] = vol_sqrt; + matrix[pos_BL][pos_FL] = vol_sqrt; + matrix[pos_BR][pos_FR] = vol_sqrt; + break; + default: + /* not sure if +3ch would use FC/LFE, SL/BR and whatnot without passing extra config, so ignore for now */ + return; + } + + /* save and make N fake channels at the beginning for easier calcs */ + output_channels = data->output_channels; + for (ch = 0; ch < max; ch++) { + mixing_push_upmix(vgmstream, 0); + } + + /* downmix */ + ch_in = 0; + for (mp_in = 0; mp_in < 16; mp_in++) { + /* read input mapping (ex. 5.1) and find channel */ + if (!(input_mapping & (1< max) + break; + } + + ch_in++; + if (ch_in >= output_channels) + break; + } + + /* remove unneeded channels */ + mixing_push_killmix(vgmstream, max); +} diff --git a/Frameworks/vgmstream/vgmstream/src/base/mixing_priv.h b/Frameworks/vgmstream/vgmstream/src/base/mixing_priv.h new file mode 100644 index 000000000..a21f83d86 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/base/mixing_priv.h @@ -0,0 +1,52 @@ +#ifndef _MIXING_PRIV_H_ +#define _MIXING_PRIV_H_ + +#include "../vgmstream.h" +#define VGMSTREAM_MAX_MIXING 512 + +/* mixing info */ +typedef enum { + MIX_SWAP, + MIX_ADD, + MIX_ADD_COPY, + MIX_VOLUME, + MIX_LIMIT, + MIX_UPMIX, + MIX_DOWNMIX, + MIX_KILLMIX, + MIX_FADE +} mix_command_t; + +typedef struct { + mix_command_t command; + /* common */ + int ch_dst; + int ch_src; + float vol; + + /* fade envelope */ + float vol_start; /* volume from pre to start */ + float vol_end; /* volume from end to post */ + char shape; /* curve type */ + int32_t time_pre; /* position before time_start where vol_start applies (-1 = beginning) */ + int32_t time_start; /* fade start position where vol changes from vol_start to vol_end */ + int32_t time_end; /* fade end position where vol changes from vol_start to vol_end */ + int32_t time_post; /* position after time_end where vol_end applies (-1 = end) */ +} mix_command_data; + +typedef struct { + int mixing_channels; /* max channels needed to mix */ + int output_channels; /* resulting channels after mixing */ + int mixing_on; /* mixing allowed */ + int mixing_count; /* mixing number */ + size_t mixing_size; /* mixing max */ + mix_command_data mixing_chain[VGMSTREAM_MAX_MIXING]; /* effects to apply (could be alloc'ed but to simplify...) */ + float* mixbuf; /* internal mixing buffer */ + + /* fades only apply at some points, other mixes are active */ + int has_non_fade; + int has_fade; +} mixing_data; + + +#endif diff --git a/Frameworks/vgmstream/vgmstream/src/base/render.c b/Frameworks/vgmstream/vgmstream/src/base/render.c index a7cc29de7..d8a1b07fd 100644 --- a/Frameworks/vgmstream/vgmstream/src/base/render.c +++ b/Frameworks/vgmstream/vgmstream/src/base/render.c @@ -274,7 +274,6 @@ int render_layout(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstream) { case layout_blocked_wsi: case layout_blocked_str_snds: case layout_blocked_ws_aud: - case layout_blocked_matx: case layout_blocked_dec: case layout_blocked_vs: case layout_blocked_mul: diff --git a/Frameworks/vgmstream/vgmstream/src/coding/adx_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/adx_decoder.c index 36e2099ec..732cd60d6 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/adx_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/adx_decoder.c @@ -1,7 +1,7 @@ #include "coding.h" #include "../util.h" -void decode_adx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int32_t frame_size, coding_t coding_type) { +void decode_adx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int32_t frame_size, coding_t coding_type, uint32_t codec_config) { uint8_t frame[0x12] = {0}; off_t frame_offset; int i, frames_in, sample_count = 0; @@ -9,6 +9,7 @@ void decode_adx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int scale, coef1, coef2; int32_t hist1 = stream->adpcm_history1_32; int32_t hist2 = stream->adpcm_history2_32; + int version = codec_config; /* external interleave (fixed size), mono */ @@ -50,7 +51,7 @@ void decode_adx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, break; case coding_CRI_ADX_enc_8: case coding_CRI_ADX_enc_9: - scale = ((scale ^ stream->adx_xor) & 0x1fff) + 1; + scale = ((scale ^ stream->adx_xor) & 0x1fff) + 1; /* this seems to be used even in unencrypted ADX (compatible) */ coef1 = stream->adpcm_coef[0]; coef2 = stream->adpcm_coef[1]; break; @@ -69,7 +70,13 @@ void decode_adx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, sample = i&1 ? /* high nibble first */ get_low_nibble_signed(nibbles): get_high_nibble_signed(nibbles); - sample = sample * scale + (coef1 * hist1 >> 12) + (coef2 * hist2 >> 12); + + /* Early (v3 ADX only) libs decode slightly differently (quieter?), while later libs (v4 ADX) tweaked it. V4 libs playing v3 files + * seem to behave like V4 though, so it's not detectable but not that common (ex. ports of old games reusing v3 ADX) */ + if (version == 0x0300) + sample = sample * scale + ((coef1 * hist1) >> 12) + ((coef2 * hist2) >> 12); /* V3 lib */ + else + sample = sample * scale + ((coef1 * hist1 + coef2 * hist2) >> 12); /* V4 lib */ sample = clamp16(sample); outbuf[sample_count] = sample; diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding.h b/Frameworks/vgmstream/vgmstream/src/coding/coding.h index aa52ce7da..7425dcf79 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/coding.h +++ b/Frameworks/vgmstream/vgmstream/src/coding/coding.h @@ -8,7 +8,7 @@ #include "hca_decoder_clhca.h" /* adx_decoder */ -void decode_adx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int32_t frame_bytes, coding_t coding_type); +void decode_adx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int32_t frame_bytes, coding_t coding_type, uint32_t codec_config); void adx_next_key(VGMSTREAMCHANNEL* stream); @@ -96,6 +96,7 @@ void decode_alaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, void decode_pcmfloat(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian); void decode_pcm24le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm24be(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_pcm32le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); int32_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample); int32_t pcm24_bytes_to_samples(size_t bytes, int channels); int32_t pcm16_bytes_to_samples(size_t bytes, int channels); @@ -588,6 +589,7 @@ void free_celt_fsb(celt_codec_data* data); typedef struct speex_codec_data speex_codec_data; speex_codec_data* init_speex_ea(int channels); +speex_codec_data* init_speex_torus(int channels); void decode_speex(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do); void reset_speex(speex_codec_data* data); void seek_speex(VGMSTREAM* vgmstream, int32_t num_sample); diff --git a/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c index 7a1e61e08..9b7dcccba 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c @@ -238,11 +238,26 @@ void decode_pcm24le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspaci } } +void decode_pcm32le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + + for (i=first_sample,sample_count=0; ioffset + i * 0x04; + int32_t v = read_s32le(offset, stream->streamfile); + outbuf[sample_count] = (v >> 16); + } +} + int32_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample) { if (channels <= 0 || bits_per_sample <= 0) return 0; return ((int64_t)bytes * 8) / channels / bits_per_sample; } +int32_t pcm32_bytes_to_samples(size_t bytes, int channels) { + return pcm_bytes_to_samples(bytes, channels, 32); +} + int32_t pcm24_bytes_to_samples(size_t bytes, int channels) { return pcm_bytes_to_samples(bytes, channels, 24); } diff --git a/Frameworks/vgmstream/vgmstream/src/coding/speex_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/speex_decoder.c index 5bac10387..85186f0f0 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/speex_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/speex_decoder.c @@ -10,15 +10,19 @@ #define SPEEX_DECODE_OK 0 /* -1 for end of stream, -2 corrupt stream */ +typedef enum { EA, TORUS } type_t; + /* opaque struct */ struct speex_codec_data { + type_t type; + /* config */ int channels; int samples_discard; int encoder_delay; uint8_t buf[SPEEX_MAX_FRAME_SIZE]; - uint8_t frame_size; + int frame_size; int16_t* samples; int frame_samples; @@ -32,7 +36,7 @@ struct speex_codec_data { /* raw SPEEX */ -speex_codec_data* init_speex_ea(int channels) { +static speex_codec_data* init_speex(type_t type, int channels) { int res, sample_rate; speex_codec_data* data = NULL; @@ -40,7 +44,9 @@ speex_codec_data* init_speex_ea(int channels) { data = calloc(1, sizeof(speex_codec_data)); if (!data) goto fail; - //TODO: EA uses N decoders, unknown layout (known samples are mono) + data->type = type; + + //TODO: unknown layout (known samples are mono, EA: N decoders, Torus: N too?) data->channels = channels; if (channels != 1) goto fail; @@ -78,6 +84,14 @@ fail: return NULL; } +speex_codec_data* init_speex_ea(int channels) { + return init_speex(EA, channels); +} + +speex_codec_data* init_speex_torus(int channels) { + return init_speex(TORUS, channels); +} + static int decode_frame(speex_codec_data* data) { int res; @@ -102,8 +116,18 @@ fail: static int read_frame(speex_codec_data* data, VGMSTREAMCHANNEL* stream) { size_t bytes; - data->frame_size = read_u8(stream->offset, stream->streamfile); - stream->offset += 0x01; + switch(data->type) { + case EA: + data->frame_size = read_u8(stream->offset, stream->streamfile); + stream->offset += 0x01; + break; + case TORUS: + data->frame_size = read_u16le(stream->offset, stream->streamfile); + stream->offset += 0x02; + break; + default: + break; + } if (data->frame_size == 0) goto fail; bytes = read_streamfile(data->buf, stream->offset, data->frame_size, stream->streamfile); diff --git a/Frameworks/vgmstream/vgmstream/src/coding/yamaha_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/yamaha_decoder.c index 18036396f..b37dc8348 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/yamaha_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/yamaha_decoder.c @@ -16,11 +16,6 @@ static const int scale_step_capcom[8] = { 58982, 58982, 58982, 58982, 78643, 104858, 131072, 157286, }; -/* look-up for 'mul' IMA's sign*((code&7) * 2 + 1) for every code */ -static const int scale_delta[16] = { - 1, 3, 5, 7, 9, 11, 13, 15, - -1, -3, -5, -7, -9,-11,-13,-15 -}; /* Yamaha ADPCM-B (aka DELTA-T) expand used in YM2608/YM2610/etc (cross referenced with various sources and .so) */ static void yamaha_adpcmb_expand_nibble(uint8_t byte, int shift, int32_t* hist1, int32_t* step_size, int16_t *out_sample) { @@ -43,14 +38,22 @@ static void yamaha_adpcmb_expand_nibble(uint8_t byte, int shift, int32_t* hist1, } /* Yamaha AICA expand, slightly filtered vs "ACM" Yamaha ADPCM, same as Creative ADPCM - * (some info from https://github.com/vgmrips/vgmplay, https://wiki.multimedia.cx/index.php/Creative_ADPCM) */ -static void yamaha_aica_expand_nibble(uint8_t byte, int shift, int32_t* hist1, int32_t* step_size, int16_t *out_sample) { + * (some info from https://github.com/superctr/adpcm/blob/master/ymz_codec.c, https://wiki.multimedia.cx/index.php/Creative_ADPCM) */ +static void yamaha_aica_expand_nibble(uint8_t byte, int shift, int16_t* hist1, int32_t* step_size, int16_t *out_sample) { int code, delta, sample; - *hist1 = *hist1 * 254 / 256; /* hist filter is vital to get correct waveform but not done in many emus */ + *hist1 = *hist1 * 254 / 256; /* hist filter seems used but may not be needed? (clamping delta is enough?)*/ code = (byte >> shift) & 0xf; - delta = (*step_size * scale_delta[code]) / 8; /* 'mul' IMA with table (not sure if part of encoder) */ + delta = ((((code & 0x7) * 2) + 1) * (*step_size)) >> 3; /* like 'mul' IMA */ + + /* supposedly from official encoder but possibly all YM chips do this, + * matters in some games to avoid random glitches (early/buggy encoders?), ex. GTA2 */ + if (delta > 32767) + delta = 32767; + + if (code & 8) + delta = -delta; sample = *hist1 + delta; sample = clamp16(sample); /* apparently done by official encoder */ @@ -112,7 +115,7 @@ static void yamaha_capcom_expand_nibble(uint8_t byte, int shift, int32_t* hist1, void decode_aica(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first) { int i, sample_count = 0; int16_t out_sample; - int32_t hist1 = stream->adpcm_history1_16; + int16_t hist1 = stream->adpcm_history1_16; int step_size = stream->adpcm_step_index; /* no header (external setup), pre-clamp for wrong values */ diff --git a/Frameworks/vgmstream/vgmstream/src/formats.c b/Frameworks/vgmstream/vgmstream/src/formats.c index 8d17e398a..80ea619b1 100644 --- a/Frameworks/vgmstream/vgmstream/src/formats.c +++ b/Frameworks/vgmstream/vgmstream/src/formats.c @@ -189,6 +189,7 @@ static const char* extension_list[] = { "fda", "ffw", "filp", + "fish", //"flac", //common "flx", "fsb", @@ -204,10 +205,11 @@ static const char* extension_list[] = { "gcw", "genh", "gin", + "gmd", //txth/semi [High Voltage games: Charlie and the Chocolate Factory (GC), Zathura (GC)] "gms", "grn", - "gsb", "gsf", + "gsp", "gtd", "gwm", @@ -217,7 +219,6 @@ static const char* extension_list[] = { "hd3", "hdr", "hdt", - "hgc1", "his", "hps", "hsf", @@ -326,7 +327,6 @@ static const char* extension_list[] = { "mab", "mad", "map", - "matx", "mc3", "mca", "mcadpcm", @@ -500,8 +500,6 @@ static const char* extension_list[] = { "sgb", "sgd", "sgt", - "sgx", - "sl3", "slb", //txth/reserved [THE Nekomura no Hitobito (PS2)] "sli", "smc", @@ -562,10 +560,10 @@ static const char* extension_list[] = { "tmx", "tra", "trk", + "trs", //txth/semi [Kamiwaza (PS2), Shinobido (PS2)] "tun", "txth", "txtp", - "tydsp", "u0", "ue4opus", @@ -653,6 +651,7 @@ static const char* extension_list[] = { "xa", "xa2", "xa30", + "xai", "xag", //txth/reserved [Tamsoft's PS2 games] "xau", "xav", @@ -769,6 +768,7 @@ static const coding_info coding_info_list[] = { {coding_PCMFLOAT, "32-bit float PCM"}, {coding_PCM24LE, "24-bit Little Endian PCM"}, {coding_PCM24BE, "24-bit Big Endian PCM"}, + {coding_PCM32LE, "32-bit Little Endian PCM"}, {coding_CRI_ADX, "CRI ADX 4-bit ADPCM"}, {coding_CRI_ADX_fixed, "CRI ADX 4-bit ADPCM (fixed coefficients)"}, @@ -932,7 +932,6 @@ static const layout_info layout_info_list[] = { {layout_blocked_xvas, "blocked (.xvas)"}, {layout_blocked_str_snds, "blocked (.str SNDS)"}, {layout_blocked_ws_aud, "blocked (Westwood Studios .aud)"}, - {layout_blocked_matx, "blocked (Matrix .matx)"}, {layout_blocked_dec, "blocked (DEC)"}, {layout_blocked_vs, "blocked (Melbourne House VS)"}, {layout_blocked_mul, "blocked (MUL)"}, @@ -966,16 +965,16 @@ static const meta_info meta_info_list[] = { {meta_SILENCE, "Silence"}, {meta_RSTM, "Nintendo RSTM header"}, {meta_STRM, "Nintendo STRM header"}, - {meta_ADX_03, "CRI ADX header type 03"}, - {meta_ADX_04, "CRI ADX header type 04"}, - {meta_ADX_05, "CRI ADX header type 05"}, + {meta_ADX_03, "CRI ADX header (type 03)"}, + {meta_ADX_04, "CRI ADX header (type 04)"}, + {meta_ADX_05, "CRI ADX header (type 05)"}, {meta_AIX, "CRI AIX header"}, {meta_AAX, "CRI AAX header"}, {meta_UTF_DSP, "CRI ADPCM_WII header"}, {meta_AGSC, "Retro Studios AGSC header"}, {meta_CSMP, "Retro Studios CSMP header"}, {meta_RFRM, "Retro Studios RFRM header"}, - {meta_DTK, "Nintendo DTK raw header"}, + {meta_DTK, "Nintendo .DTK raw header"}, {meta_RSF, "Retro Studios .RSF raw header"}, {meta_AFC, "Nintendo .AFC header"}, {meta_AST, "Nintendo .AST header"}, @@ -1016,7 +1015,7 @@ static const meta_info meta_info_list[] = { {meta_PWB, "Double Fine WB header"}, {meta_RAW_WAVM, "Xbox .wavm raw header"}, {meta_DSP_STR, "Cauldron .STR header"}, - {meta_EA_SCHL, "Electronic Arts SCHl header (variable)"}, + {meta_EA_SCHL, "Electronic Arts SCHl header"}, {meta_EA_SCHL_fixed, "Electronic Arts SCHl header (fixed)"}, {meta_CAF, "tri-Crescendo CAF Header"}, {meta_VPK, "SCE America VPK Header"}, @@ -1025,19 +1024,19 @@ static const meta_info meta_info_list[] = { {meta_SADL, "Procyon Studio SADL header"}, {meta_PS2_BMDX, "Beatmania .bmdx header"}, {meta_DSP_WSI, "Alone in the Dark .WSI header"}, - {meta_AIFC, "Apple AIFF-C (Audio Interchange File Format) header"}, - {meta_AIFF, "Apple AIFF (Audio Interchange File Format) header"}, + {meta_AIFC, "Apple AIFF-C header"}, + {meta_AIFF, "Apple AIFF header"}, {meta_STR_SNDS, "3DO SNDS header"}, {meta_WS_AUD, "Westwood Studios .AUD header"}, {meta_PS2_IVB, "IVB/BVII header"}, {meta_SVS, "Square SVS header"}, {meta_RIFF_WAVE, "RIFF WAVE header"}, - {meta_RIFF_WAVE_POS, "RIFF WAVE header and .pos for looping"}, + {meta_RIFF_WAVE_POS, "RIFF WAVE header (.pos looping)"}, {meta_NWA, "VisualArt's NWA header"}, {meta_NWA_NWAINFOINI, "VisualArt's NWA header (NWAINFO.INI looping)"}, {meta_NWA_GAMEEXEINI, "VisualArt's NWA header (Gameexe.ini looping)"}, {meta_XSS, "Dino Crisis 3 XSS File"}, - {meta_HGC1, "Knights of the Temple 2 hgC1 Header"}, + {meta_HGC1, "Cauldron HGC1 header"}, {meta_AUS, "Capcom AUS Header"}, {meta_RWS, "RenderWare RWS header"}, {meta_EA_1SNH, "Electronic Arts 1SNh header"}, @@ -1053,37 +1052,35 @@ static const meta_info meta_info_list[] = { {meta_PS2_XA30, "Reflections XA30 PS2 header"}, {meta_MUSC, "Krome MUSC header"}, {meta_MUSX, "Eurocom MUSX header"}, - {meta_FILP, "Bio Hazard - Gun Survivor FILp Header"}, + {meta_FILP, "cavia FILp Header"}, {meta_IKM, "MiCROViSiON IKM header"}, {meta_STER, "ALCHEMY STER header"}, - {meta_SAT_DVI, "Konami KCEN DVI. header"}, - {meta_DC_KCEY, "Konami KCEY KCEYCOMP header"}, - {meta_BG00, "Falcom BG00 Header"}, + {meta_SAT_DVI, "Konami DVI. header"}, + {meta_DC_KCEY, "Konami KCEY header"}, + {meta_BG00, "Cave BG00 header"}, {meta_RSTM_ROCKSTAR, "Rockstar Games RSTM Header"}, {meta_ACM, "InterPlay ACM Header"}, {meta_MUS_ACM, "InterPlay MUS ACM header"}, {meta_PS2_KCES, "Konami KCES Header"}, {meta_HXD, "Tecmo HXD Header"}, {meta_VSV, "Square Enix .vsv Header"}, - {meta_RIFF_WAVE_labl, "RIFF WAVE header with loop markers"}, - {meta_RIFF_WAVE_smpl, "RIFF WAVE header with sample looping info"}, - {meta_RIFF_WAVE_wsmp, "RIFF WAVE header with wsmp looping info"}, + {meta_RIFF_WAVE_labl, "RIFF WAVE header (labl looping)"}, + {meta_RIFF_WAVE_smpl, "RIFF WAVE header (smpl looping)"}, + {meta_RIFF_WAVE_wsmp, "RIFF WAVE header (wsmp looping)"}, {meta_RIFX_WAVE, "RIFX WAVE header"}, - {meta_RIFX_WAVE_smpl, "RIFX WAVE header with sample looping info"}, - {meta_XNB, "Microsoft XNA Game Studio 4.0 header"}, + {meta_RIFX_WAVE_smpl, "RIFX WAVE header (smpl looping)"}, + {meta_XNB, "Microsoft XNA Game Studio header"}, {meta_SCD_PCM, "Lunar: Eternal Blue .PCM header"}, - {meta_PS2_PCM, "Konami KCEJ East .PCM header"}, + {meta_PS2_PCM, "Konami .PCM header"}, {meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV PS2 header"}, {meta_PS2_VAS, "Konami .VAS header"}, {meta_LP_AP_LEP, "Konami LP/AP/LEP header"}, {meta_SDT, "High Voltage .sdt header"}, - {meta_NGC_TYDSP, ".tydsp Header"}, {meta_WVS, "Swingin' Ape .WVS header"}, - {meta_XBOX_MATX, "assumed Matrix file by .matx extension"}, - {meta_DEC, "Falcom DEC RIFF header"}, + {meta_DEC, "Falcom .DEC RIFF header"}, {meta_VS, "Melbourne House .VS header"}, - {meta_DC_STR, "Sega Stream Asset Builder header"}, - {meta_DC_STR_V2, "variant of Sega Stream Asset Builder header"}, + {meta_STR_SEGA, "Sega Stream Asset Builder header"}, + {meta_STR_SEGA_custom, "Sega Stream Asset Builder header (custom)"}, {meta_XMU, "Outrage XMU header"}, {meta_XVAS, "Konami .XVAS header"}, {meta_XA2_ACCLAIM, "Acclaim .XA2 Header"}, @@ -1093,7 +1090,7 @@ static const meta_info meta_info_list[] = { {meta_YMF, "Yuke's .YMF Header"}, {meta_FAG, "Radical .FAG Header"}, {meta_PS2_MIHB, "Sony MultiStream MIC header"}, - {meta_DSP_WII_MUS, "mus header"}, + {meta_MUS_KROME, "Krome .MUS header"}, {meta_WII_SNG, "SNG DSP Header"}, {meta_RSD, "Radical RSD header"}, {meta_DC_ASD, "ASD Header"}, @@ -1112,7 +1109,7 @@ static const meta_info meta_info_list[] = { {meta_GCA, "GCA DSP Header"}, {meta_SPT_SPD, "SPT+SPD DSP Header"}, {meta_ISH_ISD, "ISH+ISD DSP Header"}, - {meta_GSP_GSB, "Tecmo GSP+GSB Header"}, + {meta_GSND, "Tecmo GSND Header"}, {meta_YDSP, "Yuke's YDSP Header"}, {meta_NGC_SSM, "SSM DSP Header"}, {meta_PS2_JOE, "Asobo Studio .JOE header"}, @@ -1125,7 +1122,7 @@ static const meta_info meta_info_list[] = { {meta_PS2_P2BT, "Pop'n'Music 7 Header"}, {meta_PS2_GBTS, "Pop'n'Music 9 Header"}, {meta_NGC_DSP_IADP, "IADP Header"}, - {meta_RIFF_WAVE_MWV, "RIFF WAVE header with .mwv flavoring"}, + {meta_RIFF_WAVE_MWV, "RIFF WAVE header (ctrl looping)"}, {meta_FFCC_STR, "Final Fantasy: Crystal Chronicles STR header"}, {meta_SAT_BAKA, "Konami BAKA header"}, {meta_SWAV, "Nintendo SWAV header"}, @@ -1155,7 +1152,7 @@ static const meta_info meta_info_list[] = { {meta_SAB, "Sensaura SAB header"}, {meta_MAXIS_XA, "Maxis XA Header"}, {meta_EXAKT_SC, "assumed Activision / EXAKT SC by extension"}, - {meta_WII_BNS, "Nintendo BNS header"}, + {meta_BNS, "Nintendo BNS header"}, {meta_WII_WAS, "Sumo Digital iSWS header"}, {meta_XBOX_HLWAV, "Half-Life 2 .WAV header"}, {meta_MYSPD, "Punchers Impact .MYSPD header"}, @@ -1168,7 +1165,7 @@ static const meta_info meta_info_list[] = { {meta_NGC_DSP_AAAP, "Acclaim Austin AAAp DSP header"}, {meta_NGC_DSP_KONAMI, "Konami DSP header"}, {meta_BNSF, "Namco Bandai BNSF header"}, - {meta_PS2_WB, "Shooting Love. ~TRIZEAL~ WB header"}, + {meta_WB, "Triangle Service .WB header"}, {meta_S14, "Namco .S14 raw header"}, {meta_SSS, "Namco .SSS raw header"}, {meta_PS2_GCM, "Namco GCM header"}, @@ -1183,7 +1180,6 @@ static const meta_info meta_info_list[] = { {meta_DSP_STR_IG, "Infogrames .DSP header"}, {meta_EA_SWVR, "Electronic Arts SWVR header"}, {meta_PS2_B1S, "B1S header"}, - {meta_PS2_WAD, "WAD header"}, {meta_DSP_XIII, "XIII dsp header"}, {meta_DSP_CABELAS, "Cabelas games .DSP header"}, {meta_PS2_ADM, "Dragon Quest V .ADM raw header"}, @@ -1233,7 +1229,7 @@ static const meta_info meta_info_list[] = { {meta_KT_WIIBGM, "Koei Tecmo WiiBGM Header"}, {meta_KTSS, "Koei Tecmo KTSS header"}, {meta_IDSP_NAMCO, "Namco IDSP header"}, - {meta_WIIU_BTSND, "Nintendo Wii U Menu Boot Sound"}, + {meta_BTSND, "Nintendo Wii U Menu Boot Sound header"}, {meta_MCA, "Capcom MCA header"}, {meta_ADX_MONSTER, "Monster Games .ADX header"}, {meta_HCA, "CRI HCA header"}, @@ -1248,7 +1244,7 @@ static const meta_info meta_info_list[] = { {meta_ASTB, "Capcom ASTB header"}, {meta_WWISE_RIFF, "Audiokinetic Wwise RIFF header"}, {meta_UBI_RAKI, "Ubisoft RAKI header"}, - {meta_SXD, "Sony SXD header"}, + {meta_SNDX, "Sony SNDX header"}, {meta_OGL, "Shin'en OGL header"}, {meta_MC3, "Paradigm MC3 header"}, {meta_GHS, "Hexadrive GHS/S_P_STH header"}, @@ -1409,13 +1405,16 @@ static const meta_info meta_info_list[] = { {meta_SSPF, "Konami SSPF header"}, {meta_S3V, "Konami S3V header"}, {meta_ESF, "Eurocom ESF header"}, - {meta_ADM3, "Crankcase ADM3 header"}, + {meta_ADM, "Crankcase ADMx header"}, {meta_TT_AD, "Traveller's Tales AUDIO_DATA header"}, {meta_SNDZ, "Sony SNDZ header"}, {meta_VAB, "Sony VAB header"}, {meta_BIGRP, "Inti Creates .BIGRP header"}, {meta_DIC1, "Codemasters DIC1 header"}, {meta_AWD, "RenderWare Audio Wave Dictionary header"}, + {meta_SQUEAKSTREAM, "Torus SqueakStream header"}, + {meta_SQUEAKSAMPLE, "Torus SqueakSample header"}, + {meta_SNDS, "Sony SNDS header"}, }; void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) { diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked.c index bb7f65648..637502ee5 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked.c @@ -123,9 +123,6 @@ void block_update(off_t block_offset, VGMSTREAM* vgmstream) { case layout_blocked_ws_aud: block_update_ws_aud(block_offset,vgmstream); break; - case layout_blocked_matx: - block_update_matx(block_offset,vgmstream); - break; case layout_blocked_dec: block_update_dec(block_offset,vgmstream); break; diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_matx.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_matx.c index e69a05038..e69de29bb 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_matx.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_matx.c @@ -1,18 +0,0 @@ -#include "layout.h" -#include "../vgmstream.h" - -/* set up for the block at the given offset */ -void block_update_matx(off_t block_offset, VGMSTREAM * vgmstream) { - int i; - - vgmstream->current_block_offset = block_offset; - vgmstream->current_block_size = read_32bitLE( - vgmstream->current_block_offset, - vgmstream->ch[0].streamfile); - vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size + 8; - vgmstream->current_block_size/=vgmstream->channels; - - for (i=0;ichannels;i++) { - vgmstream->ch[i].offset = vgmstream->current_block_offset + 8; - } -} diff --git a/Frameworks/vgmstream/vgmstream/src/layout/layout.h b/Frameworks/vgmstream/vgmstream/src/layout/layout.h index 4f3e64d6f..11a7d9aa5 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/layout.h +++ b/Frameworks/vgmstream/vgmstream/src/layout/layout.h @@ -20,7 +20,6 @@ void block_update_caf(off_t block_offset, VGMSTREAM* vgmstream); void block_update_wsi(off_t block_offset, VGMSTREAM* vgmstream); void block_update_str_snds(off_t block_offset, VGMSTREAM* vgmstream); void block_update_ws_aud(off_t block_offset, VGMSTREAM* vgmstream); -void block_update_matx(off_t block_offset, VGMSTREAM* vgmstream); void block_update_dec(off_t block_offset, VGMSTREAM* vgmstream); void block_update_vs(off_t block_offset, VGMSTREAM* vgmstream); void block_update_mul(off_t block_offset, VGMSTREAM* vgmstream); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/adm.c b/Frameworks/vgmstream/vgmstream/src/meta/adm.c new file mode 100644 index 000000000..d38fd5989 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/adm.c @@ -0,0 +1,219 @@ +#include "meta.h" +#include "../coding/coding.h" + + +typedef struct { + int total_subsongs; + int target_subsong; + int version; + + uint32_t stream_offset; + uint32_t stream_size; + + int loop_flag; + int sample_rate; + int channels; + int32_t num_samples; +} adm_header_t; + +static int parse_adm(adm_header_t* adm, STREAMFILE* sf); + +static VGMSTREAM* init_vgmstream_adm(STREAMFILE* sf, int version); + +/* ADM2 - Crankcase Audio REV plugin file [The Grand Tour Game (PC)] */ +VGMSTREAM* init_vgmstream_adm2(STREAMFILE* sf) { + + /* checks */ + if (!is_id32be(0x00,sf, "ADM2")) + return NULL; + if (!check_extensions(sf, "wem")) + return NULL; + + return init_vgmstream_adm(sf, 2); +} + +/* ADM3 - Crankcase Audio REV plugin file [Cyberpunk 2077 (PC), MotoGP 21 (PC)] */ +VGMSTREAM* init_vgmstream_adm3(STREAMFILE* sf) { + + /* checks */ + if (!is_id32be(0x00,sf, "ADM3")) + return NULL; + if (!check_extensions(sf, "wem")) + return NULL; + + return init_vgmstream_adm(sf, 3); +} + +static VGMSTREAM* init_vgmstream_adm(STREAMFILE* sf, int version) { + VGMSTREAM* vgmstream = NULL; + adm_header_t adm = {0}; + + /* ADMx are files used with the Wwise Crankaudio plugin, that simulate engine noises with + * base internal samples and some internal RPM config (probably). Actual file seems to + * define some combo of samples, this only plays those separate samples. + * Decoder is basically Apple's IMA (internally just "ADPCMDecoder") but transforms to float + * each sample during decode by multiplying by 0.000030518509 */ + + adm.target_subsong = sf->stream_index; + if (adm.target_subsong == 0) adm.target_subsong = 1; + + adm.version = version; + + if (!parse_adm(&adm, sf)) + goto fail; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(adm.channels, adm.loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_ADM; + vgmstream->sample_rate = adm.sample_rate; + vgmstream->num_samples = adm.num_samples; /* slightly lower than bytes-to-samples */ + vgmstream->num_streams = adm.total_subsongs; + vgmstream->stream_size = adm.stream_size; + + vgmstream->coding_type = coding_APPLE_IMA4; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x22; + + if (!vgmstream_open_stream(vgmstream, sf, adm.stream_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + + +static int parse_type(adm_header_t* adm, STREAMFILE* sf, uint32_t offset) { + + /* ADM2 chunks */ + if (is_id32be(offset, sf, "GRN1")) { + /* 0x74: offset to floats? */ + offset = read_u32le(offset + 0x78, sf); /* to SMP1 */ + if (!parse_type(adm, sf, offset)) + goto fail; + } + else if (is_id32be(offset, sf, "SMP1")) { + adm->total_subsongs++; + + if (adm->target_subsong == adm->total_subsongs) { + /* 0x04 always 0 */ + /* 0x08 version? (0x00030000) */ + adm->channels = read_u16le(offset + 0x0c, sf); + /* 0x0e 0x0001? */ + /* 0x10 header size (0x2c) */ + adm->sample_rate = read_s32le(offset + 0x14, sf); + adm->num_samples = read_s32le(offset + 0x18, sf); + adm->stream_size = read_u32le(offset + 0x1c, sf); + adm->stream_offset = read_u32le(offset + 0x20, sf); + /* rest: null */ + VGM_LOG("so=%x %x\n", adm->stream_size, adm->stream_offset); + } + } + + /* ADM3 chunks */ + else if (is_id32be(offset, sf, "RMP1")) { + offset = read_u32le(offset + 0x1c, sf); + if (!parse_type(adm, sf, offset)) + goto fail; + /* 0x24: offset to GRN1 */ + } + else if (is_id32be(offset, sf, "SMB1")) { + uint32_t table_count = read_u32le(offset + 0x10, sf); + uint32_t table_offset = read_u32le(offset + 0x18, sf); + int i; + + for (i = 0; i < table_count; i++) { + uint32_t smp2_unk = read_u32le(table_offset + i * 0x08 + 0x00, sf); + uint32_t smp2_offset = read_u32le(table_offset + i * 0x08 + 0x04, sf); + + if (smp2_unk != 1) + goto fail; + + if (!parse_type(adm, sf, smp2_offset)) /* SMP2 */ + goto fail; + } + } + else if (is_id32be(offset, sf, "SMP2")) { + adm->total_subsongs++; + + if (adm->target_subsong == adm->total_subsongs) { + /* 0x04 always 0 */ + /* 0x08 version? (0x00040000) */ + adm->channels = read_u32le(offset + 0x0c, sf); /* usually 4, with different sounds*/ + /* 0x10 float pitch? */ + /* 0x14 int pitch? */ + /* 0x18 0x0001? */ + /* 0x1a header size (0x30) */ + adm->sample_rate = read_s32le(offset + 0x1c, sf); + adm->num_samples = read_s32le(offset + 0x20, sf); + adm->stream_size = read_u32le(offset + 0x24, sf); + /* 0x28 1? */ + adm->stream_offset = read_u32le(offset + 0x2c, sf); + } + } + else { + VGM_LOG("ADM: unknown at %x\n", offset); + goto fail; + } + + return 1; +fail: + return 0; +} + +static int parse_adm(adm_header_t* adm, STREAMFILE* sf) { + uint32_t offset; + + /* 0x04: null */ + /* 0x08: version? (ADM2: 0x00050000, ADM3: 0x00060000) */ + /* 0x0c: header size */ + /* 0x10: data start */ + /* rest unknown, looks mostly the same between files (some floats and stuff) */ + + switch(adm->version) { + case 2: + /* low to high */ + offset = read_u32le(0x104, sf); + if (!parse_type(adm, sf, offset)) goto fail; /* GRN1 */ + + /* high to low */ + offset = read_u32le(0x108, sf); + if (!parse_type(adm, sf, offset)) goto fail; /* GRN1 */ + + /* idle engine */ + offset = read_u32le(0x10c, sf); + if (!parse_type(adm, sf, offset)) goto fail; /* SMP1 */ + break; + + case 3: + /* higher ramp, N samples from low to high */ + offset = read_u32le(0x0FC, sf); + if (!parse_type(adm, sf, offset)) goto fail; /* RMP1 */ + if (read_u32le(0x100, sf) != 1) goto fail; + + /* lower ramp, also N samples */ + offset = read_u32le(0x104, sf); + if (!parse_type(adm, sf, offset)) goto fail; /* RMP1 */ + if (read_u32le(0x108, sf) != 1) goto fail; + + /* idle engine */ + offset = read_u32le(0x10c, sf); + if (!parse_type(adm, sf, offset)) goto fail; /* SMP2 */ + if (read_u32le(0x110, sf) != 1) goto fail; + break; + + default: + goto fail; + } + + if (adm->target_subsong < 0 || adm->target_subsong > adm->total_subsongs || adm->total_subsongs < 1) + goto fail; + + return 1; +fail: + return 0; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/adm3.c b/Frameworks/vgmstream/vgmstream/src/meta/adm3.c deleted file mode 100644 index f38ed06ba..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/adm3.c +++ /dev/null @@ -1,152 +0,0 @@ -#include "meta.h" -#include "../coding/coding.h" - - -typedef struct { - int total_subsongs; - int target_subsong; - - uint32_t stream_offset; - uint32_t stream_size; - - int loop_flag; - int sample_rate; - int channels; - int32_t num_samples; -} adm3_header_t; - -static int parse_adm3(adm3_header_t* adm3, STREAMFILE* sf); - - -/* ADM3 - Crankcase Audio REV plugin file [Cyberpunk 2077 (PC), MotoGP 21 (PC)] */ -VGMSTREAM* init_vgmstream_adm3(STREAMFILE* sf) { - VGMSTREAM* vgmstream = NULL; - adm3_header_t adm3 = {0}; - - - /* checks */ - if (!is_id32be(0x00,sf, "ADM3")) - goto fail; - if (!check_extensions(sf, "wem")) - goto fail; - - adm3.target_subsong = sf->stream_index; - if (adm3.target_subsong == 0) adm3.target_subsong = 1; - - /* ADM3 are files used with the Wwise Crankaudio plugin, that simulate engine noises with - * base internal samples and some internal RPM config (probably). Actual file seems to - * define some combo of samples, this only plays those separate samples. - * Decoder is basically Apple's IMA (internally just "ADPCMDecoder") but transforms to float - * each sample during decode by multiplying by 0.000030518509 */ - - if (!parse_adm3(&adm3, sf)) - goto fail; - - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(adm3.channels, adm3.loop_flag); - if (!vgmstream) goto fail; - - vgmstream->meta_type = meta_ADM3; - vgmstream->sample_rate = adm3.sample_rate; - vgmstream->num_samples = adm3.num_samples; /* slightly lower than bytes-to-samples */ - vgmstream->num_streams = adm3.total_subsongs; - vgmstream->stream_size = adm3.stream_size; - - vgmstream->coding_type = coding_APPLE_IMA4; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x22; - - if (!vgmstream_open_stream(vgmstream, sf, adm3.stream_offset)) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} - - -static int parse_type(adm3_header_t* adm3, STREAMFILE* sf, uint32_t offset) { - - if (is_id32be(offset, sf, "RMP1")) { - offset = read_u32le(offset + 0x1c, sf); - if (!parse_type(adm3, sf, offset)) - goto fail; - /* 0x24: offset to GRN1 */ - } - else if (is_id32be(offset, sf, "SMB1")) { - uint32_t table_count = read_u32le(offset + 0x10, sf); - uint32_t table_offset = read_u32le(offset + 0x18, sf); - int i; - - for (i = 0; i < table_count; i++) { - uint32_t smp2_unk = read_u32le(table_offset + i * 0x08 + 0x00, sf); - uint32_t smp2_offset = read_u32le(table_offset + i * 0x08 + 0x04, sf); - - if (smp2_unk != 1) - goto fail; - - if (!parse_type(adm3, sf, smp2_offset)) /* SMP2 */ - goto fail; - } - } - else if (is_id32be(offset, sf, "SMP2")) { - adm3->total_subsongs++; - - if (adm3->target_subsong == adm3->total_subsongs) { - /* 0x04 always 0 */ - /* 0x08 always 0x00040000 */ - adm3->channels = read_u32le(offset + 0x0c, sf); - /* 0x10 float pitch? */ - /* 0x14 int pitch? */ - /* 0x18 0x0001? */ - /* 0x1a 0x0030? (header size?) */ - adm3->sample_rate = read_s32le(offset + 0x1c, sf); - adm3->num_samples = read_s32le(offset + 0x20, sf); - adm3->stream_size = read_u32le(offset + 0x24, sf); - /* 0x28 1? */ - adm3->stream_offset = read_u32le(offset + 0x2c, sf); - } - } - else { - VGM_LOG("ADM3: unknown at %x\n", offset); - goto fail; - } - - return 1; -fail: - return 0; -} - -static int parse_adm3(adm3_header_t* adm3, STREAMFILE* sf) { - uint32_t offset; - - /* 0x04: null */ - /* 0x08: version? */ - /* 0x0c: header size */ - /* 0x10: data start */ - /* rest unknown, looks mostly the same between files */ - - /* higher ramp, N samples from low to high */ - offset = read_u32le(0x0FC, sf); - if (!parse_type(adm3, sf, offset)) goto fail; /* RMP1 */ - if (read_u32le(0x100, sf) != 1) goto fail; - - /* lower ramp, also N samples */ - offset = read_u32le(0x104, sf); - if (!parse_type(adm3, sf, offset)) goto fail; /* RMP1 */ - if (read_u32le(0x108, sf) != 1) goto fail; - - /* idle engine */ - offset = read_u32le(0x10c, sf); - if (!parse_type(adm3, sf, offset)) goto fail; /* SMP2 */ - if (read_u32le(0x110, sf) != 1) goto fail; - - if (adm3->target_subsong < 0 || adm3->target_subsong > adm3->total_subsongs || adm3->total_subsongs < 1) - goto fail; - - return 1; -fail: - return 0; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/adx.c b/Frameworks/vgmstream/vgmstream/src/meta/adx.c index 2e7091044..f972923ef 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/adx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/adx.c @@ -183,6 +183,7 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) { vgmstream->loop_start_sample = loop_start_sample; vgmstream->loop_end_sample = loop_end_sample; + vgmstream->codec_config = version; vgmstream->coding_type = coding_type; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = frame_size; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bg00.c b/Frameworks/vgmstream/vgmstream/src/meta/bg00.c new file mode 100644 index 000000000..7941e114a --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/bg00.c @@ -0,0 +1,46 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* BG00 - from Cave games [Ibara (PS2), Mushihime-sama (PS2)] */ +VGMSTREAM* init_vgmstream_bg00(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint32_t start_offset; + int channels, loop_flag = 0; + + + /* check */ + if (!is_id32be(0x00,sf, "BG00")) + return NULL; + + /* .bg00: header ID (no filenames or debug strings) */ + if (!check_extensions(sf,"bg00")) + return NULL; + + if (!is_id32be(0x40,sf, "VAGp")) + return NULL; + if (!is_id32be(0x70,sf, "VAGp")) + return NULL; + + loop_flag = 0; /* flag at 0x08? loop points seem external */ + channels = 2; /* mono files use regular VAG */ + start_offset = 0x800; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_BG00; + vgmstream->sample_rate = read_s32be(0x80,sf); + vgmstream->num_samples = ps_bytes_to_samples(read_32bitBE(0x4C,sf), 1); + + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0x10,sf); + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bnk_sony.c b/Frameworks/vgmstream/vgmstream/src/meta/bnk_sony.c index 56b66314d..0e10d4795 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/bnk_sony.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/bnk_sony.c @@ -3,591 +3,116 @@ #include "../coding/coding.h" #include "../util/endianness.h" -typedef enum { PSX, PCM16, ATRAC9, HEVAG } bnk_codec; +typedef enum { NONE, DUMMY, PSX, PCM16, ATRAC9, HEVAG, RIFF_ATRAC9 } bnk_codec; + +typedef struct { + bnk_codec codec; + int big_endian; + + /* bank related (internal)*/ + int sblk_version; + uint32_t sblk_offset; + uint32_t data_offset; + uint32_t data_size; + uint32_t zlsd_offset; + uint32_t zlsd_size; + + uint32_t table1_offset; /* usually sounds/cues (point to grains) */ + uint32_t table2_offset; /* usually grains/materials (point to waves) */ + uint32_t table3_offset; /* usually waves (point to streams) */ + uint32_t table4_offset; /* usually names */ + uint32_t sounds_entries; + uint32_t grains_entries; + uint32_t stream_entries; + uint32_t table1_suboffset; + uint32_t table2_suboffset; + uint32_t table1_entry_size; + uint32_t table2_entry_offset; + uint32_t table3_entry_offset; + + + /* stream related */ + int total_subsongs; + int target_subsong; + + int channels; + int loop_flag; + int sample_rate; + int32_t num_samples; + int32_t loop_start; + int32_t loop_end; + + uint32_t start_offset; + uint32_t stream_offset; + uint32_t bank_name_offset; + uint32_t stream_name_offset; + uint32_t stream_name_size; + + uint32_t stream_size; + uint32_t interleave; + + uint16_t stream_flags; + uint32_t atrac9_info; +} bnk_header_t; + +static bool parse_bnk_v3(STREAMFILE* sf, bnk_header_t* h); + /* .BNK - Sony's SCREAM bank format [The Sly Collection (PS3), Puyo Puyo Tetris (PS4), NekoBuro: Cats Block (Vita)] */ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; - uint32_t start_offset, stream_offset, name_offset = 0; - uint32_t stream_size, interleave = 0; - int channels = 0, loop_flag, sample_rate, big_endian; - int32_t loop_start = 0, loop_end = 0; - uint32_t center_note, center_fine, flags; - uint32_t atrac9_info = 0; - - int total_subsongs, target_subsong = sf->stream_index; - read_u16_t read_u16; - read_u32_t read_u32; - read_f32_t read_f32; - bnk_codec codec; - - - /* bnk/SCREAM tool version */ - if (read_u32be(0x00,sf) == 0x03) { /* PS3 */ - read_u32 = read_u32be; - read_u16 = read_u16be; - read_f32 = read_f32be; - big_endian = 1; - } - else if (read_u32le(0x00,sf) == 0x03) { /* PS2/Vita/PS4 */ - read_u32 = read_u32le; - read_u16 = read_u16le; - read_f32 = read_f32le; - big_endian = 0; - } - else { - return NULL; - } + char bank_name[STREAM_NAME_SIZE] /*[8]*/, stream_name[STREAM_NAME_SIZE] /*[16]*/; + bnk_header_t h = {0}; /* checks */ + if (!parse_bnk_v3(sf, &h)) + return NULL; if (!check_extensions(sf, "bnk")) return NULL; - uint32_t sblk_offset, data_offset, data_size; - int parts, sblk_version; - - parts = read_u32(0x04,sf); - if (parts < 2 || parts > 3) - return NULL; - /* in theory a bank can contain multiple blocks */ - - /* section sizes don't include padding (sometimes aligned to 0x10/0x800) */ - sblk_offset = read_u32(0x08,sf); - //sblk_size = read_u32(0x0c,sf); - data_offset = read_u32(0x10,sf); - data_size = read_u32(0x14,sf); - - /* ZLSD small footer, rare in earlier versions and more common later [Yakuza 6's Puyo Puyo (PS4)] */ - //if (sblk_offset >= 0x20) { - // zlsd_offset = read_u32(0x18,sf); - // zlsd_size = read_u32(0x1c,sf); - //} - - if (sblk_offset > 0x20) - return NULL; - - /* SE banks, also used for music. Most table fields seems reserved/defaults and - * don't change much between subsongs or files, so they aren't described in detail. - * Entry sizes are variable (usually flag + extra size xN) so table offsets are needed. */ - - - /* SBlk part: parse header */ - if (read_u32(sblk_offset+0x00,sf) != get_id32be("klBS")) /* SBlk = SFX block */ - return NULL; - sblk_version = read_u32(sblk_offset+0x04,sf); - /* 0x08: flags? (sblk_version>=0x0d?, 0x03=Vita, 0x06=PS4, 0x05=PS5) - * - 04: non-fixed bank? - * - 100: has names - * - 200: has user data */ - /* version < v0x1a: - * - 0x0c: block id - * - 0x10: block number - * - 0x11: padding - * version >= v0x1a: - * - 0x0c: hash (0x10) - * - 0x1c: filename (0x100?) */ - //;VGM_LOG("BNK: sblk_offset=%lx, data_offset=%lx, sblk_version %x\n", sblk_offset, data_offset, sblk_version); - - { - int i; - uint32_t table1_offset, table2_offset, table3_offset, table4_offset; - uint32_t section_entries, material_entries, stream_entries; - uint32_t table1_entry_size; - uint32_t table1_suboffset, table2_suboffset; - uint32_t table2_entry_offset = 0, table3_entry_offset = 0; - int table4_entry_id = -1; - uint32_t table4_entries_offset, table4_names_offset; - - - switch(sblk_version) { - case 0x01: /* Ratchet & Clank (PS2) */ - section_entries = read_u16(sblk_offset+0x16,sf); /* entry size: ~0x0c */ - material_entries = read_u16(sblk_offset+0x18,sf); /* entry size: ~0x28 */ - stream_entries = read_u16(sblk_offset+0x1a,sf); /* entry size: none (count) */ - table1_offset = sblk_offset + read_u32(sblk_offset+0x1c,sf); - table2_offset = sblk_offset + read_u32(sblk_offset+0x20,sf); - table3_offset = table2_offset; /* mixed table in this version */ - table4_offset = 0; /* not included */ - - table1_entry_size = 0; /* not used */ - table1_suboffset = 0; - table2_suboffset = 0; - break; - - case 0x03: /* Yu-Gi-Oh! GX - The Beginning of Destiny (PS2) */ - case 0x04: /* Test banks */ - case 0x05: /* Ratchet & Clank (PS3) */ - case 0x08: /* Playstation Home Arcade (Vita) */ - case 0x09: /* Puyo Puyo Tetris (PS4) */ - section_entries = read_u16(sblk_offset+0x16,sf); /* entry size: ~0x0c (NumSounds)*/ - material_entries = read_u16(sblk_offset+0x18,sf); /* entry size: ~0x08 (NumGrains) */ - stream_entries = read_u16(sblk_offset+0x1a,sf); /* entry size: ~0x18 + variable (NumWaveforms) */ - table1_offset = sblk_offset + read_u32(sblk_offset+0x1c,sf); /* sound offset */ - table2_offset = sblk_offset + read_u32(sblk_offset+0x20,sf); /* grain offset */ - /* 0x24: VAG address? */ - /* 0x28: data size */ - /* 0x2c: RAM size */ - /* 0x30: next block offset */ - table3_offset = sblk_offset + read_u32(sblk_offset+0x34,sf); /* grain data? */ - table4_offset = sblk_offset + read_u32(sblk_offset+0x38,sf); /* block names */ - /*0x3c: SFXUD? */ - - table1_entry_size = 0x0c; - table1_suboffset = 0x08; - table2_suboffset = 0x00; - break; - - case 0x0d: /* Polara (Vita), Crypt of the Necrodancer (Vita) */ - case 0x0e: /* Yakuza 6's Puyo Puyo (PS4) */ - case 0x0f: /* Ikaruga (PS4) */ - case 0x10: /* Ginga Force (PS4) */ - table1_offset = sblk_offset + read_u32(sblk_offset+0x18,sf); - table2_offset = sblk_offset + read_u32(sblk_offset+0x1c,sf); - table3_offset = sblk_offset + read_u32(sblk_offset+0x2c,sf); - table4_offset = sblk_offset + read_u32(sblk_offset+0x30,sf); - section_entries = read_u16(sblk_offset+0x38,sf); /* entry size: ~0x24 */ - material_entries = read_u16(sblk_offset+0x3a,sf); /* entry size: ~0x08 */ - stream_entries = read_u16(sblk_offset+0x3c,sf); /* entry size: ~0x5c + variable */ - - table1_entry_size = 0x24; - table1_suboffset = 0x0c; - table2_suboffset = 0x00; - break; - - case 0x1a: /* Demon's Souls (PS5) */ - case 0x23: /* The Last of Us (PC) */ - - default: - vgm_logi("BNK: unknown version %x (report)\n", sblk_version); - goto fail; - } - - //;VGM_LOG("BNK: table offsets=%x, %x, %x, %x\n", table1_offset,table2_offset,table3_offset,table4_offset); - //;VGM_LOG("BNK: table entries=%i, %i, %i\n", section_entries,material_entries,stream_entries); - - - /* table defs: - * - table1: sections, point to some materials (may be less than streams/materials) - * (a "sound" that has N grains, and is triggered by games like a cue) - * - table2: materials, point to all sounds or others subtypes (may be more than sounds) - * (a "grain" that does actions like play or changes volume) - * - table3: sounds, point to streams (multiple sounds can repeat stream) - * (a "waveform" being the actual stream) - * - table4: names define section names (not all sounds may have a name) - * - * approximate table parsing - * - check materials and skip non-sounds to get table3 offsets (since table3 entry size isn't always constant) - * - get stream offsets - * - find if one section points to the selected material, and get section name = stream name */ - - /* parse materials */ - total_subsongs = 0; - if (target_subsong == 0) target_subsong = 1; - - switch(sblk_version) { - case 0x01: - /* table2/3 has size 0x28 entries, seemingly: - * 0x00: subtype(01=sound) - * 0x08: same as other versions (pitch, flags, offset...) - * rest: padding - * 0x18: stream offset - * there is no stream size like in v0x03 - */ - - for (i = 0; i < material_entries; i++) { - uint32_t table2_type = read_u32(table2_offset + (i*0x28) + 0x00, sf); - - if (table2_type != 0x01) - continue; - - total_subsongs++; - if (total_subsongs == target_subsong) { - table2_entry_offset = 0; - table3_entry_offset = (i*0x28) + 0x08; - /* continue to count all subsongs*/ - } - - } - - break; - - default: - for (i = 0; i < material_entries; i++) { - uint32_t table2_value, table2_subinfo, table2_subtype; - - table2_value = read_u32(table2_offset+(i*0x08)+table2_suboffset+0x00,sf); - table2_subinfo = (table2_value >> 0) & 0xFFFF; - table2_subtype = (table2_value >> 16) & 0xFFFF; - if (table2_subtype != 0x0100) - continue; /* not sounds (ex. 1: waveform, 42: silence, 25: random, etc) */ - - total_subsongs++; - if (total_subsongs == target_subsong) { - table2_entry_offset = (i*0x08); - table3_entry_offset = table2_subinfo; - /* continue to count all subsongs*/ - } - } - - break; - } - - - //;VGM_LOG("BNK: subsongs %i, table2_entry=%x, table3_entry=%x\n", total_subsongs,table2_entry_offset,table3_entry_offset); - - if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; - /* this means some subsongs repeat streams, that can happen in some sfx banks, whatevs */ - if (total_subsongs != stream_entries) { - VGM_LOG("BNK: subsongs %i vs table3 %i don't match (repeated streams?)\n", total_subsongs, stream_entries); - /* TODO: find dupes? */ - } - - //;VGM_LOG("BNK: header entry at %lx\n", table3_offset+table3_entry_offset); - - /* parse sounds */ - switch(sblk_version) { - case 0x01: - case 0x03: - case 0x04: - case 0x05: - case 0x08: - case 0x09: - /* "tone" */ - /* 0x00: priority */ - /* 0x01: volume */ - center_note = read_u8 (table3_offset+table3_entry_offset+0x02,sf); - center_fine = read_u8 (table3_offset+table3_entry_offset+0x03,sf); - /* 0x04: pan */ - /* 0x06: map low */ - /* 0x07: map high */ - /* 0x08: pitch bend low */ - /* 0x09: pitch bend high */ - /* 0x0a: ADSR1 */ - /* 0x0c: ADSR2 */ - flags = read_u16(table3_offset+table3_entry_offset+0x0e,sf); - stream_offset = read_u32(table3_offset+table3_entry_offset+0x10,sf); - stream_size = read_u32(table3_offset+table3_entry_offset+0x14,sf); - - /* "base" sample rates, allowed by the tool (for other rates must use base + semitones, but aren't exact) */ - if (center_note == 0xC4 && center_fine == 0x00) - sample_rate = 48000; - else if (center_note == 0xC2 && center_fine == 0x42) - sample_rate = 44100; - else if (center_note == 0xb6 && center_fine == 0x42) - sample_rate = 22050; - else if (center_note == 0xaa && center_fine == 0x42) - sample_rate = 11025; - else if (center_note == 0xa4 && center_fine == 0x7c) - sample_rate = 8000; - else { - /* rough ("center") sample rates using semitone-to-hz formula: (rate) * 2 ^ ((pitch - base) / 12) */ - double curr_rate = 48000 * pow(2.0, (double)((int)center_note - 0xc4) / 12.0); - double prev_rate = 48000 * pow(2.0, (double)(((int)center_note - 1) - 0xc4) / 12.0); - /* partial semitone, from 0x00 = 0.0 to 0x7f = 1.0 of a semitone for current rate */ - float fine_pct = center_fine / 127.0f; - - //TODO improve (fine seems approximate and not sure how to calc current semitone hz value, so needs prev_rate) - sample_rate = curr_rate + (curr_rate - prev_rate) * fine_pct; - - /* some odd "beep" sfx in Sly 2/3 seems to go slightly higher after applying fine_pct, probably should resample */ - if (sample_rate > VGMSTREAM_MAX_SAMPLE_RATE) - sample_rate = VGMSTREAM_MAX_SAMPLE_RATE; - - /* waves can set base sample rate (48/44/22/11/8khz) + pitch in semitones, then converted to center+fine - * 48000 + pitch 0.0 > center=0xc4, fine=0x00 - * 48000 + pitch 0.10 > center=0xc4, fine=0x0c - * 48000 + pitch 0.50 > center=0xc4, fine=0x3f - * 48000 + pitch 0.99 > center=0xc4, fine=0x7d - * 48000 + pitch 1.00 > center=0xc5, fine=0x00 - * 48000 + pitch 12.0 > center=0xd0, fine=0x00 - * 48000 + pitch 24.0 > center=0xdc, fine=0x00 - * 48000 + pitch 56.0 > center=0xfc, fine=0x00 - * 48000 + pitch 68.0 > center=0x08, fine=0x00 > ? - * 48000 + pitch -12.0 > center=0xb8, fine=0x00 - * 48000 + pitch -0.10 > center=0xc3, fine=0x72 - * 48000 + pitch -0.001 > not allowed - * 8000 + pitch 1.00 > center=0xa4, fine=0x7c - * 8000 + pitch -12.00 > center=0x98, fine=0x7c - * 8000 + pitch -48.00 > center=0x74, fine=0x7c - */ - } - break; - - case 0x0d: - case 0x0e: - case 0x0f: - case 0x10: - flags = read_u8 (table3_offset+table3_entry_offset+0x12,sf); - stream_offset = read_u32(table3_offset+table3_entry_offset+0x44,sf); - stream_size = read_u32(table3_offset+table3_entry_offset+0x48,sf); - sample_rate = (int)read_f32(table3_offset+table3_entry_offset+0x4c,sf); - break; - - default: - VGM_LOG("BNK: missing version\n"); - goto fail; - } - - //;VGM_LOG("BNK: stream at %lx + %x\n", stream_offset, stream_size); - - /* parse names */ - switch(sblk_version) { - //case 0x03: /* different format? */ - //case 0x04: /* different format? */ - case 0x08: - case 0x09: - case 0x0d: - case 0x0e: - case 0x0f: - case 0x10: - /* find if this sound has an assigned name in table1 */ - for (i = 0; i < section_entries; i++) { - uint32_t entry_offset = read_u16(table1_offset+(i*table1_entry_size)+table1_suboffset+0x00,sf); - - /* rarely (ex. Polara sfx) one name applies to multiple materials, - * from current entry_offset to next entry_offset (section offsets should be in order) */ - if (entry_offset <= table2_entry_offset ) { - table4_entry_id = i; - //break; - } - } - - /* table4: */ - /* 0x00: bank name (optional) */ - /* 0x08: header size */ - /* 0x0c: table4 size */ - /* variable: entries */ - /* variable: names (null terminated) */ - table4_entries_offset = table4_offset + read_u32(table4_offset+0x08, sf); - table4_names_offset = table4_entries_offset + (0x10*section_entries); - //;VGM_LOG("BNK: t4_entries=%lx, t4_names=%lx\n", table4_entries_offset, table4_names_offset); - - /* get assigned name from table4 names */ - for (i = 0; i < section_entries; i++) { - int entry_id = read_u32(table4_entries_offset+(i*0x10)+0x0c, sf); - if (entry_id == table4_entry_id) { - name_offset = table4_names_offset + read_u32(table4_entries_offset+(i*0x10)+0x00, sf); - break; - } - } - - break; - default: - break; - } - - //;VGM_LOG("BNK: stream_offset=%lx, stream_size=%x, name_offset=%lx\n", stream_offset, stream_size, name_offset); - } - - - /* data part: parse extradata before the codec, if needed */ - { - int type, loop_length; - size_t extradata_size = 0, postdata_size = 0; - start_offset = data_offset + stream_offset; - - switch(sblk_version) { - case 0x01: - case 0x03: - case 0x04: - case 0x05: - channels = 1; - - /* early versions don't have PS-ADPCM size, could check next offset but it's all kind of loopy */ - if (sblk_version <= 0x03 && stream_size == 0 && (flags & 0x80) == 0) { - uint32_t offset; - uint32_t max_offset = get_streamfile_size(sf); - - stream_size += 0x10; - for (offset = data_offset + stream_offset + 0x10; offset < max_offset; offset += 0x10) { - - /* beginning frame (if file loops won't have end frame) */ - if (read_u32be(offset + 0x00, sf) == 0x00000000 && read_u32be(offset + 0x04, sf) == 0x00000000) - break; - - stream_size += 0x10; - - /* end frame */ - if (read_u32be(offset + 0x00, sf) == 0x00077777 && read_u32be(offset + 0x04, sf) == 0x77777777) - break; - } - - //;VGM_LOG("BNK: stream offset=%lx + %lx, new size=%x\n", data_offset, stream_offset, stream_size); - } - - - /* hack for PS3 files that use dual subsongs as stereo */ - if (total_subsongs == 2 && stream_size * 2 == data_size) { - channels = 2; - stream_size = stream_size*channels; - total_subsongs = 1; - } - interleave = stream_size / channels; - - /* PS Home Arcade has other flags? supposedly: - * 01 = reverb - * 02 = vol scale 20 - * 04 = vol scale 50 - * 06 = vol scale 100 - * 08 = noise - * 10 = no dry - * 20 = no steal - * 40 = loop VAG - * 80 = PCM - * 100 = has advanced packets - * 200 = send LFE - * 400 = send center - */ - if ((flags & 0x80) && sblk_version <= 3) { - codec = PCM16; /* rare [Wipeout HD (PS3)]-v3 */ - } - else { - loop_flag = ps_find_loop_offsets(sf, start_offset, stream_size, channels, interleave, &loop_start, &loop_end); - loop_flag = (flags & 0x40); /* only applies to PS-ADPCM flags */ - - codec = PSX; - } - - //postdata_size = 0x10; /* last frame may be garbage */ - break; - - case 0x08: - case 0x09: - type = read_u16(start_offset+0x00,sf); - extradata_size = 0x08 + read_u32(start_offset+0x04,sf); /* 0x14 for AT9 */ - - switch(type) { - case 0x00: - channels = 1; - codec = PSX; - interleave = 0x10; - break; - - case 0x01: - channels = 1; - codec = PCM16; - interleave = 0x01; - break; - - - case 0x02: /* ATRAC9 mono */ - case 0x05: /* ATRAC9 stereo */ - if (read_u32(start_offset+0x08,sf) + 0x08 != extradata_size) { /* repeat? */ - VGM_LOG("BNK: unknown subtype\n"); - goto fail; - } - channels = (type == 0x02) ? 1 : 2; - - atrac9_info = read_u32be(start_offset+0x0c,sf); - /* 0x10: null? */ - loop_length = read_u32(start_offset+0x14,sf); - loop_start = read_u32(start_offset+0x18,sf); - loop_end = loop_start + loop_length; /* loop_start is -1 if not set */ - - codec = ATRAC9; - break; - - default: - vgm_logi("BNK: unknown type %x (report)\n", type); - goto fail; - } - break; - - case 0x0d: - case 0x0e: - case 0x0f: - case 0x10: - type = read_u16(start_offset+0x00,sf); - if (read_u32(start_offset+0x04,sf) != 0x01) { /* type? */ - VGM_LOG("BNK: unknown subtype\n"); - goto fail; - } - extradata_size = 0x10 + read_u32(start_offset+0x08,sf); /* 0x80 for AT9, 0x10 for PCM/PS-ADPCM */ - /* 0x0c: null? */ - - switch(type) { - case 0x02: /* ATRAC9 mono */ - case 0x05: /* ATRAC9 stereo */ - if (read_u32(start_offset+0x10,sf) + 0x10 != extradata_size) /* repeat? */ - goto fail; - channels = (type == 0x02) ? 1 : 2; - - atrac9_info = read_u32be(start_offset+0x14,sf); - /* 0x18: null? */ - /* 0x1c: channels? */ - /* 0x20: null? */ - - loop_length = read_u32(start_offset+0x24,sf); - loop_start = read_u32(start_offset+0x28,sf); - loop_end = loop_start + loop_length; /* loop_start is -1 if not set */ - - codec = ATRAC9; - break; - - case 0x01: /* PCM16LE mono? (NekoBuro/Polara sfx) */ - case 0x04: /* PCM16LE stereo? (NekoBuro/Polara sfx) */ - /* 0x10: null? */ - channels = read_u32(start_offset+0x14,sf); - interleave = 0x02; - - loop_start = read_u32(start_offset+0x18,sf); - loop_length = read_u32(start_offset+0x1c,sf); - loop_end = loop_start + loop_length; /* loop_start is -1 if not set */ - - codec = PCM16; - break; - - case 0x00: /* HEVAG (test banks) */ - case 0x03: /* HEVAG (Ikaruga) */ - /* 0x10: null? */ - channels = read_u32(start_offset+0x14,sf); - interleave = 0x10; - - loop_start = read_u32(start_offset+0x18,sf); - loop_length = read_u32(start_offset+0x1c,sf); - loop_end = loop_start + loop_length; /* loop_start is -1 if not set */ - - codec = HEVAG; - //TODO: in v0x0f right before start_offset is the .vag filename, see if offset can be found - break; - - default: - vgm_logi("BNK: unknown type %x (report)\n", type); - goto fail; - } - break; - - default: - vgm_logi("BNK: unknown data version %x (report)\n", sblk_version); - goto fail; - } - - start_offset += extradata_size; - stream_size -= extradata_size; - stream_size -= postdata_size; - //;VGM_LOG("BNK: offset=%lx, size=%x\n", start_offset, stream_size); - } - - loop_flag = (loop_start >= 0) && (loop_end > 0); - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channels,loop_flag); + vgmstream = allocate_vgmstream(h.channels, h.loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = sample_rate; - vgmstream->num_streams = total_subsongs; - vgmstream->stream_size = stream_size; + vgmstream->sample_rate = h.sample_rate; + vgmstream->num_streams = h.total_subsongs; + vgmstream->stream_size = h.stream_size; vgmstream->meta_type = meta_BNK_SONY; - switch(codec) { + if (!h.stream_name_size) + h.stream_name_size = STREAM_NAME_SIZE; + + if (!h.bank_name_offset && h.stream_name_offset) { + read_string(vgmstream->stream_name, h.stream_name_size, h.stream_name_offset, sf); + } + else if (h.bank_name_offset && h.stream_name_offset) { + read_string(bank_name, h.stream_name_size, h.bank_name_offset, sf); + read_string(stream_name, h.stream_name_size, h.stream_name_offset, sf); + snprintf(vgmstream->stream_name, h.stream_name_size, "%s/%s", bank_name, stream_name); + } + + + switch(h.codec) { + case DUMMY: { + VGMSTREAM* temp_vs = NULL; + + temp_vs = init_vgmstream_silence_container(h.total_subsongs); + if (!temp_vs) goto fail; + + temp_vs->meta_type = vgmstream->meta_type; + + close_vgmstream(vgmstream); + return temp_vs; + } + #ifdef VGM_USE_ATRAC9 case ATRAC9: { atrac9_config cfg = {0}; cfg.channels = vgmstream->channels; - cfg.config_data = atrac9_info; + cfg.config_data = h.atrac9_info; //cfg.encoder_delay = 0x00; //todo vgmstream->codec_data = init_atrac9(&cfg); @@ -595,51 +120,69 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) { vgmstream->coding_type = coding_ATRAC9; vgmstream->layout_type = layout_none; - vgmstream->num_samples = atrac9_bytes_to_samples(stream_size, vgmstream->codec_data); - vgmstream->loop_start_sample = loop_start; - vgmstream->loop_end_sample = loop_end; + vgmstream->num_samples = atrac9_bytes_to_samples(h.stream_size, vgmstream->codec_data); + vgmstream->loop_start_sample = h.loop_start; + vgmstream->loop_end_sample = h.loop_end; break; - } + } + + case RIFF_ATRAC9: { + VGMSTREAM* temp_vs = NULL; + STREAMFILE* temp_sf = NULL; + + + temp_sf = setup_subfile_streamfile(sf, h.start_offset, h.stream_size, "at9"); + if (!temp_sf) goto fail; + + temp_vs = init_vgmstream_riff(temp_sf); + close_streamfile(temp_sf); + if (!temp_vs) goto fail; + + temp_vs->num_streams = vgmstream->num_streams; + temp_vs->stream_size = vgmstream->stream_size; + temp_vs->meta_type = vgmstream->meta_type; + strcpy(temp_vs->stream_name, vgmstream->stream_name); + + close_vgmstream(vgmstream); + return temp_vs; + } #endif case PCM16: - vgmstream->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE; + vgmstream->coding_type = h.big_endian ? coding_PCM16BE : coding_PCM16LE; vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = interleave; + vgmstream->interleave_block_size = h.interleave; - vgmstream->num_samples = pcm_bytes_to_samples(stream_size, vgmstream->channels, 16); - vgmstream->loop_start_sample = loop_start; - vgmstream->loop_end_sample = loop_end; + vgmstream->num_samples = pcm_bytes_to_samples(h.stream_size, vgmstream->channels, 16); + vgmstream->loop_start_sample = h.loop_start; + vgmstream->loop_end_sample = h.loop_end; break; case PSX: vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = interleave; + vgmstream->interleave_block_size = h.interleave; - vgmstream->num_samples = ps_bytes_to_samples(stream_size,channels); - vgmstream->loop_start_sample = loop_start; - vgmstream->loop_end_sample = loop_end; + vgmstream->num_samples = ps_bytes_to_samples(h.stream_size, h.channels); + vgmstream->loop_start_sample = h.loop_start; + vgmstream->loop_end_sample = h.loop_end; break; case HEVAG: vgmstream->coding_type = coding_HEVAG; vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = interleave; + vgmstream->interleave_block_size = h.interleave; - vgmstream->num_samples = ps_bytes_to_samples(stream_size,channels); - vgmstream->loop_start_sample = loop_start; - vgmstream->loop_end_sample = loop_end; + vgmstream->num_samples = ps_bytes_to_samples(h.stream_size, h.channels); + vgmstream->loop_start_sample = h.loop_start; + vgmstream->loop_end_sample = h.loop_end; break; default: goto fail; } - if (name_offset) - read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,sf); - - if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + if (!vgmstream_open_stream(vgmstream, sf, h.start_offset)) goto fail; return vgmstream; fail: @@ -667,3 +210,876 @@ fail: return NULL; } #endif + +static const uint16_t note_pitch_table[12] = { + 0x8000, 0x879C, 0x8FAC, 0x9837, 0xA145, 0xAADC, + 0xB504, 0xBFC8, 0xCB2F, 0xD744, 0xE411, 0xF1A1 +}; + +static const uint16_t fine_pitch_table[128] = { + 0x8000, 0x800E, 0x801D, 0x802C, 0x803B, 0x804A, 0x8058, 0x8067, + 0x8076, 0x8085, 0x8094, 0x80A3, 0x80B1, 0x80C0, 0x80CF, 0x80DE, + 0x80ED, 0x80FC, 0x810B, 0x811A, 0x8129, 0x8138, 0x8146, 0x8155, + 0x8164, 0x8173, 0x8182, 0x8191, 0x81A0, 0x81AF, 0x81BE, 0x81CD, + 0x81DC, 0x81EB, 0x81FA, 0x8209, 0x8218, 0x8227, 0x8236, 0x8245, + 0x8254, 0x8263, 0x8272, 0x8282, 0x8291, 0x82A0, 0x82AF, 0x82BE, + 0x82CD, 0x82DC, 0x82EB, 0x82FA, 0x830A, 0x8319, 0x8328, 0x8337, + 0x8346, 0x8355, 0x8364, 0x8374, 0x8383, 0x8392, 0x83A1, 0x83B0, + 0x83C0, 0x83CF, 0x83DE, 0x83ED, 0x83FD, 0x840C, 0x841B, 0x842A, + 0x843A, 0x8449, 0x8458, 0x8468, 0x8477, 0x8486, 0x8495, 0x84A5, + 0x84B4, 0x84C3, 0x84D3, 0x84E2, 0x84F1, 0x8501, 0x8510, 0x8520, + 0x852F, 0x853E, 0x854E, 0x855D, 0x856D, 0x857C, 0x858B, 0x859B, + 0x85AA, 0x85BA, 0x85C9, 0x85D9, 0x85E8, 0x85F8, 0x8607, 0x8617, + 0x8626, 0x8636, 0x8645, 0x8655, 0x8664, 0x8674, 0x8683, 0x8693, + 0x86A2, 0x86B2, 0x86C1, 0x86D1, 0x86E0, 0x86F0, 0x8700, 0x870F, + 0x871F, 0x872E, 0x873E, 0x874E, 0x875D, 0x876D, 0x877D, 0x878C +}; + +static uint16_t ps_note_to_pitch(uint16_t center_note, uint16_t center_fine, uint16_t note, int16_t fine) { + /* Derived from OpenGOAL, Copyright (c) 2020-2022 OpenGOAL Team, ISC License + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + int fine_adjust, fine_idx, note_adjust, note_idx; + int unk1, unk2, unk3; /* TODO: better variable names */ + uint16_t pitch; + + fine_idx = fine + center_fine; + + fine_adjust = fine_idx; + if (fine_idx < 0) + fine_adjust = fine_idx + 0x7F; + + fine_adjust /= 128; + note_adjust = note + fine_adjust - center_note; + unk3 = note_adjust / 6; + + if (note_adjust < 0) + unk3--; + + fine_idx -= fine_adjust * 128; + + if (note_adjust < 0) + unk2 = -1; + else + unk2 = 0; + if (unk3 < 0) + unk3--; + + unk2 = (unk3 / 2) - unk2; + unk1 = unk2 - 2; + note_idx = note_adjust - (unk2 * 12); + + if ((note_idx < 0) || ((note_idx == 0) && (fine_idx < 0))) { + note_idx += 12; + unk1 = unk2 - 3; + } + + if (fine_idx < 0) { + note_idx = (note_idx - 1) + fine_adjust; + fine_idx += (fine_adjust + 1) * 128; + } + + pitch = (note_pitch_table[note_idx] * fine_pitch_table[fine_idx]) >> 16; + + if (unk1 < 0) + pitch = (pitch + (1 << (-unk1 - 1))) >> -unk1; + + return pitch; +} + + +/* base part: read section info */ +static bool process_tables(STREAMFILE* sf, bnk_header_t* h) { + read_u16_t read_u16 = h->big_endian ? read_u16be : read_u16le; + read_u32_t read_u32 = h->big_endian ? read_u32be : read_u32le; + + /* - table1: sections, point to some materials (may be less than streams/materials) + * (a "sound" that has N grains, and is triggered by games like a cue) + * - table2: materials, point to all sounds or others subtypes (may be more than sounds) + * (a "grain" that does actions like play or changes volume) + * - table3: sounds, point to streams (multiple sounds can repeat stream) + * (a "waveform" being the actual stream) + * - table4: names define section names (not all sounds may have a name) + * + * approximate table parsing + * - check materials and skip non-sounds to get table3 offsets (since table3 entry size isn't always constant) + * - get stream offsets + * - find if one section points to the selected material, and get section name = stream name */ + + switch(h->sblk_version) { + case 0x01: /* Ratchet & Clank (PS2) */ + h->sounds_entries = read_u16(h->sblk_offset+0x16,sf); /* entry size: ~0x0c */ + h->grains_entries = read_u16(h->sblk_offset+0x18,sf); /* entry size: ~0x28 */ + h->stream_entries = read_u16(h->sblk_offset+0x1a,sf); /* entry size: none (count) */ + h->table1_offset = h->sblk_offset + read_u32(h->sblk_offset+0x1c,sf); + h->table2_offset = h->sblk_offset + read_u32(h->sblk_offset+0x20,sf); + h->table3_offset = h->table2_offset; /* mixed table in this version */ + h->table4_offset = 0; /* not included */ + + h->table1_entry_size = 0; /* not used */ + h->table1_suboffset = 0; + h->table2_suboffset = 0; + break; + + case 0x03: /* Yu-Gi-Oh! GX - The Beginning of Destiny (PS2) */ + case 0x04: /* Test banks */ + case 0x05: /* Ratchet & Clank (PS3) */ + case 0x08: /* Playstation Home Arcade (Vita) */ + case 0x09: /* Puyo Puyo Tetris (PS4) */ + h->sounds_entries = read_u16(h->sblk_offset+0x16,sf); /* entry size: ~0x0c (NumSounds) */ + h->grains_entries = read_u16(h->sblk_offset+0x18,sf); /* entry size: ~0x08 (NumGrains) */ + h->stream_entries = read_u16(h->sblk_offset+0x1a,sf); /* entry size: ~0x18 + variable (NumWaveforms) */ + h->table1_offset = h->sblk_offset + read_u32(h->sblk_offset+0x1c,sf); /* sound offset */ + h->table2_offset = h->sblk_offset + read_u32(h->sblk_offset+0x20,sf); /* grain offset */ + /* 0x24: VAG address? */ + /* 0x28: data size */ + /* 0x2c: RAM size */ + /* 0x30: next block offset */ + h->table3_offset = h->sblk_offset + read_u32(h->sblk_offset+0x34,sf); /* grain data? */ + h->table4_offset = h->sblk_offset + read_u32(h->sblk_offset+0x38,sf); /* block names */ + /* 0x3c: SFXUD? */ + + h->table1_entry_size = 0x0c; + h->table1_suboffset = 0x08; + h->table2_suboffset = 0x00; + break; + + case 0x0d: /* Polara (Vita), Crypt of the Necrodancer (Vita) */ + case 0x0e: /* Yakuza 6's Puyo Puyo (PS4) */ + case 0x0f: /* Ikaruga (PS4) */ + case 0x10: /* Ginga Force (PS4) */ + h->table1_offset = h->sblk_offset + read_u32(h->sblk_offset+0x18,sf); + h->table2_offset = h->sblk_offset + read_u32(h->sblk_offset+0x1c,sf); + h->table3_offset = h->sblk_offset + read_u32(h->sblk_offset+0x2c,sf); + h->table4_offset = h->sblk_offset + read_u32(h->sblk_offset+0x30,sf); + h->sounds_entries = read_u16(h->sblk_offset+0x38,sf); /* entry size: ~0x24 */ + h->grains_entries = read_u16(h->sblk_offset+0x3a,sf); /* entry size: ~0x08 */ + h->stream_entries = read_u16(h->sblk_offset+0x3c,sf); /* entry size: ~0x5c + variable */ + + h->table1_entry_size = 0x24; + h->table1_suboffset = 0x0c; + h->table2_suboffset = 0x00; + break; + + /* later version have a few more tables (some optional) and work slightly differently (header is part of wave) */ + case 0x1a: /* Demon's Souls (PS5) */ + case 0x23: { /* The Last of Us (PC) */ + uint32_t tables_offset = h->sblk_offset + (h->sblk_version <= 0x1a ? 0x120 : 0x128); + uint32_t counts_offset = tables_offset + (h->sblk_version <= 0x1a ? 0x98 : 0xb0); + + //h->table1_offset = h->sblk_offset + read_u32(tables_offset+0x00,sf); /* sounds/cues */ + //h->table2_offset = 0; + h->table3_offset = h->sblk_offset + read_u32(tables_offset+0x08,sf); /* wave offsets with info (integrated grains+waves?)*/ + //h->sounds_entries = read_u16(counts_offset+0x00,sf); + //h->grains_entries = read_u16(counts_offset+0x02,sf); + h->stream_entries = read_u16(counts_offset+0x06,sf); + break; + } + + default: + vgm_logi("BNK: unknown version %x (report)\n", h->sblk_version); + goto fail; + } + + //;VGM_LOG("BNK: table offsets=%x, %x, %x, %x\n", h->table1_offset, h->table2_offset, h->table3_offset, h->table4_offset); + //;VGM_LOG("BNK: table entries=%i, %i, %i\n", h->sounds_entries, h->grains_entries, h->stream_entries); + + return true; +fail: + return false; +} + +/* header part: read wave info */ +static bool process_headers(STREAMFILE* sf, bnk_header_t* h) { + read_u16_t read_u16 = h->big_endian ? read_u16be : read_u16le; + read_u32_t read_u32 = h->big_endian ? read_u32be : read_u32le; + read_f32_t read_f32 = h->big_endian ? read_f32be : read_f32le; + int i; + uint32_t sndh_offset; + + /* parse materials */ + h->total_subsongs = 0; + h->target_subsong = sf->stream_index; + if (h->target_subsong == 0) h->target_subsong = 1; + + switch(h->sblk_version) { + case 0x01: + /* table2/3 has size 0x28 entries, seemingly: + * 0x00: subtype(01=sound) + * 0x08: same as other versions (pitch, flags, offset...) + * rest: padding + * 0x18: stream offset + * there is no stream size like in v0x03 + */ + + for (i = 0; i < h->grains_entries; i++) { + uint32_t table2_type = read_u32(h->table2_offset + (i*0x28) + 0x00, sf); + + if (table2_type != 0x01) + continue; + + h->total_subsongs++; + if (h->total_subsongs == h->target_subsong) { + h->table2_entry_offset = 0; + h->table3_entry_offset = (i*0x28) + 0x08; + /* continue to count all subsongs */ + } + + } + + break; + + case 0x1a: + case 0x23: + h->total_subsongs = h->stream_entries; + h->table3_entry_offset = (h->target_subsong - 1) * 0x08; + break; + + default: + for (i = 0; i < h->grains_entries; i++) { + uint32_t table2_value, table2_subinfo, table2_subtype; + + table2_value = read_u32(h->table2_offset+(i*0x08) + h->table2_suboffset + 0x00,sf); + table2_subinfo = (table2_value >> 0) & 0xFFFF; + table2_subtype = (table2_value >> 16) & 0xFFFF; + if (table2_subtype != 0x0100) + continue; /* not sounds (ex. 1: waveform, 42: silence, 25: random, etc) */ + + h->total_subsongs++; + if (h->total_subsongs == h->target_subsong) { + h->table2_entry_offset = (i*0x08); + h->table3_entry_offset = table2_subinfo; + /* continue to count all subsongs */ + } + } + + break; + } + + + //;VGM_LOG("BNK: subsongs %i, table2_entry=%x, table3_entry=%x\n", h->total_subsongs, h->table2_entry_offset, h->table3_entry_offset); + if (h->target_subsong < 0 || h->target_subsong > h->total_subsongs || h->total_subsongs < 1) + goto fail; + /* this means some subsongs repeat streams, that can happen in some sfx banks, whatevs */ + if (h->total_subsongs != h->stream_entries) { + VGM_LOG("BNK: subsongs %i vs table3 %i don't match (repeated streams?)\n", h->total_subsongs, h->stream_entries); + /* TODO: find dupes? */ + } + + //;VGM_LOG("BNK: header entry at %x\n", h->table3_offset + h->table3_entry_offset); + + sndh_offset = h->table3_offset + h->table3_entry_offset; + + /* parse sounds */ + switch(h->sblk_version) { + case 0x01: + case 0x03: + case 0x04: + case 0x05: + case 0x08: + case 0x09: { + uint16_t center_note, center_fine, pitch; + bool is_negative; + + /* "tone" */ + /* 0x00: priority */ + /* 0x01: volume */ + center_note = read_u8 (sndh_offset + 0x02,sf); + center_fine = read_u8 (sndh_offset + 0x03,sf); + /* 0x04: pan */ + /* 0x06: map low */ + /* 0x07: map high */ + /* 0x08: pitch bend low */ + /* 0x09: pitch bend high */ + /* 0x0a: ADSR1 */ + /* 0x0c: ADSR2 */ + h->stream_flags = read_u16(sndh_offset + 0x0e,sf); + h->stream_offset = read_u32(sndh_offset + 0x10,sf); + h->stream_size = read_u32(sndh_offset + 0x14,sf); + + /* if it isn't, then it's treated as 44100 base? (PS1?) */ + is_negative = center_note >> 7; /* center_note & 0x80; */ + + if (is_negative) + center_note = 0x100 - center_note; + + /* note/fine seems to always be set to 0x3C/0x00 */ + pitch = ps_note_to_pitch(center_note, center_fine, 0x3C, 0x00); + + if (pitch > 0x4000) + pitch = 0x4000; /* 192000 Hz max */ + + if (!is_negative) /* PS1 mode? */ + pitch = (pitch * 44100) / 48000; + + h->sample_rate = (pitch * 48000) / 0x1000; + + /* waves can set base sample rate (48/44/22/11/8khz) + pitch in semitones, then converted to center+fine + * 48000 + pitch 0.00 > center=0xc4, fine=0x00 + * 48000 + pitch 0.10 > center=0xc4, fine=0x0c + * 48000 + pitch 0.50 > center=0xc4, fine=0x3f + * 48000 + pitch 0.99 > center=0xc4, fine=0x7d + * 48000 + pitch 1.00 > center=0xc5, fine=0x00 + * 48000 + pitch 12.00 > center=0xd0, fine=0x00 + * 48000 + pitch 24.00 > center=0xdc, fine=0x00 + * 48000 + pitch 56.00 > center=0xfc, fine=0x00 + * 48000 + pitch 68.00 > center=0x08, fine=0x00 > ? + * 48000 + pitch -12.00 > center=0xb8, fine=0x00 + * 48000 + pitch -0.10 > center=0xc3, fine=0x72 + * 48000 + pitch -0.001 > not allowed + * 8000 + pitch 1.00 > center=0xa4, fine=0x7c + * 8000 + pitch -12.00 > center=0x98, fine=0x7c + * 8000 + pitch -48.00 > center=0x74, fine=0x7c + */ + break; + } + + case 0x0d: + case 0x0e: + case 0x0f: + case 0x10: + h->stream_flags = read_u8 (sndh_offset+0x12,sf); + h->stream_offset = read_u32(sndh_offset+0x44,sf); + h->stream_size = read_u32(sndh_offset+0x48,sf); + h->sample_rate = (int)read_f32(sndh_offset+0x4c,sf); + break; + + case 0x1a: /* Demon's Souls (PS5) */ + case 0x23: /* The Last of Us (PC) */ + h->stream_offset = read_u32(sndh_offset+0x00,sf); + /* rest is part of data, handled later */ + break; + + default: + VGM_LOG("BNK: missing version\n"); + goto fail; + } + + //;VGM_LOG("BNK: stream at %lx + %x\n", h->stream_offset, h->stream_size); + + return true; +fail: + return false; +} + +/* name part: read names */ +static bool process_names(STREAMFILE* sf, bnk_header_t* h) { + read_u16_t read_u16 = h->big_endian ? read_u16be : read_u16le; + read_u32_t read_u32 = h->big_endian ? read_u32be : read_u32le; + + /* table4 can be nonexistent */ + if (h->table4_offset <= h->sblk_offset) + return true; + + int i; + int table4_entry_id = -1; + uint32_t table4_entry_idx, table4_entries_offset, table4_names_offset; + uint32_t entry_offset, entry_count; + + switch (h->sblk_version) { + case 0x03: + for (i = 0; i < h->sounds_entries; i++) { + entry_offset = read_u32(h->table1_offset + (i * h->table1_entry_size) + 0x08, sf); + entry_count = read_u8(h->table1_offset + (i * h->table1_entry_size) + 0x04, sf); + + /* is table2_entry_offset in the range of the expected section */ + if (h->table2_entry_offset >= entry_offset && h->table2_entry_offset < entry_offset + (entry_count * 0x08)) { + table4_entry_id = i; + break; + } + } + + /* table4: + * 0x00: bank name (optional) + * 0x08: name section offset + * 0x0C-0x14: 3 null pointers (reserved?) + * 0x18-0x58: 32 name chunk offset indices + */ + + /* Name chunks are organised as + * (name[0] + name[4] + name[8] + name[12]) & 0x1F; + * and using that as the index for the chunk offsets + * name_sect_offset + (chunk_idx[result] * 0x14); + */ + if (read_u8(h->table4_offset, sf)) + h->bank_name_offset = h->table4_offset; + + table4_entries_offset = h->table4_offset + 0x18; + table4_names_offset = h->table4_offset + read_u32(h->table4_offset + 0x08, sf); + + for (i = 0; i < 32; i++) { + table4_entry_idx = read_u16(table4_entries_offset + (i * 2), sf); + h->stream_name_offset = table4_names_offset + (table4_entry_idx * 0x14); + /* searches the chunk until it finds the target name/index, or breaks at empty name */ + while (read_u8(h->stream_name_offset, sf)) { + /* in case it goes somewhere out of bounds unexpectedly */ + if (((read_u8(h->stream_name_offset + 0x00, sf) + read_u8(h->stream_name_offset + 0x04, sf) + + read_u8(h->stream_name_offset + 0x08, sf) + read_u8(h->stream_name_offset + 0x0C, sf)) & 0x1F) != i) + goto fail; + if (read_u16(h->stream_name_offset + 0x10, sf) == table4_entry_id) + goto loop_break; /* to break out of the for+while loop simultaneously */ + //break; + h->stream_name_offset += 0x14; + } + } + //goto fail; /* didn't find any valid index? */ + h->stream_name_offset = 0; + loop_break: + break; + + case 0x04: + case 0x05: + /* a mix of v3 table1 parsing + v8-v16 table4 parsing */ + for (i = 0; i < h->sounds_entries; i++) { + entry_offset = read_u32(h->table1_offset + (i * h->table1_entry_size) + 0x08, sf); + entry_count = read_u8(h->table1_offset + (i * h->table1_entry_size) + 0x04, sf); + + if (h->table2_entry_offset >= entry_offset && h->table2_entry_offset < entry_offset + (entry_count * 0x08)) { + table4_entry_id = i; + break; + } + } + + /* table4: + * 0x00: bank name (optional) + * 0x08: name entries offset + * 0x0C: name section offset + * + * name entries offset: + * 0x00: name offset in name section + * 0x04: name hash(?) + * 0x08: ? (2x int16) + * 0x0C: section index (int16) + */ + if (read_u8(h->table4_offset, sf)) + h->bank_name_offset = h->table4_offset; + + table4_entries_offset = h->table4_offset + read_u32(h->table4_offset + 0x08, sf); + table4_names_offset = h->table4_offset + read_u32(h->table4_offset + 0x0C, sf); + + for (i = 0; i < h->sounds_entries; i++) { + if (read_u16(table4_entries_offset + (i * 0x10) + 0x0C, sf) == table4_entry_id) { + h->stream_name_offset = table4_names_offset + read_u32(table4_entries_offset + (i * 0x10), sf); + break; + } + } + break; + + case 0x08: + case 0x09: + case 0x0d: + case 0x0e: + case 0x0f: + case 0x10: + /* find if this sound has an assigned name in table1 */ + for (i = 0; i < h->sounds_entries; i++) { + entry_offset = read_u16(h->table1_offset + (i * h->table1_entry_size) + h->table1_suboffset + 0x00, sf); + + /* rarely (ex. Polara sfx) one name applies to multiple materials, + * from current entry_offset to next entry_offset (section offsets should be in order) */ + if (entry_offset <= h->table2_entry_offset) { + table4_entry_id = i; + //break; + } + } + + /* table4: */ + /* 0x00: bank name (optional) */ + /* 0x08: header size */ + /* 0x0c: table4 size */ + /* variable: entries */ + /* variable: names (null terminated) */ + if (read_u8(h->table4_offset, sf)) + h->bank_name_offset = h->table4_offset; + + table4_entries_offset = h->table4_offset + read_u32(h->table4_offset + 0x08, sf); + table4_names_offset = table4_entries_offset + (0x10 * h->sounds_entries); + //;VGM_LOG("BNK: t4_entries=%lx, t4_names=%lx\n", table4_entries_offset, table4_names_offset); + + /* get assigned name from table4 names */ + for (i = 0; i < h->sounds_entries; i++) { + int entry_id = read_u32(table4_entries_offset + (i * 0x10) + 0x0c, sf); + if (entry_id == table4_entry_id) { + h->stream_name_offset = table4_names_offset + read_u32(table4_entries_offset + (i * 0x10) + 0x00, sf); + break; + } + } + break; + + default: + break; + } + + //;VGM_LOG("BNK: stream_offset=%lx, stream_size=%x, stream_name_offset=%lx\n", h->stream_offset, h->stream_size, h->stream_name_offset); + + return true; +fail: + return false; +} + +/* data part: parse extradata before the codec */ +static bool process_data(STREAMFILE* sf, bnk_header_t* h) { + read_u16_t read_u16 = h->big_endian ? read_u16be : read_u16le; + read_u32_t read_u32 = h->big_endian ? read_u32be : read_u32le; + read_s32_t read_s32 = h->big_endian ? read_s32be : read_s32le; + read_u64_t read_u64 = h->big_endian ? read_u64be : read_u64le; + + int subtype, loop_length; + uint32_t extradata_size = 0, postdata_size = 0; + + h->start_offset = h->data_offset + h->stream_offset; + uint32_t info_offset = h->start_offset; + + switch(h->sblk_version) { + case 0x01: + case 0x03: + case 0x04: + case 0x05: + h->channels = 1; + + /* early versions don't have PS-ADPCM size, could check next offset but it's all kind of loopy */ + if (h->sblk_version <= 0x03 && h->stream_size == 0 && (h->stream_flags & 0x80) == 0) { + uint32_t offset; + uint32_t max_offset = get_streamfile_size(sf); + + h->stream_size += 0x10; + for (offset = h->data_offset + h->stream_offset + 0x10; offset < max_offset; offset += 0x10) { + + /* beginning frame (if file loops won't have end frame) + * checking the entire 16 byte block, as it is possible + * for just the first 8 bytes to be empty [Bully (PS2)] */ + if (read_u32be(offset + 0x00, sf) == 0x00000000 && read_u32be(offset + 0x04, sf) == 0x00000000 && + read_u32be(offset + 0x08, sf) == 0x00000000 && read_u32be(offset + 0x0C, sf) == 0x00000000) + break; + + h->stream_size += 0x10; + + /* end frame */ + if (read_u32be(offset + 0x00, sf) == 0x00077777 && read_u32be(offset + 0x04, sf) == 0x77777777) + break; + } + + //;VGM_LOG("BNK: stream offset=%lx + %lx, new size=%x\n", h->data_offset, stream_offset, stream_size); + } + + + /* hack for PS3 files that use dual subsongs as stereo */ + if (h->total_subsongs == 2 && h->stream_size * 2 == h->data_size) { + h->channels = 2; + h->stream_size = h->stream_size * h->channels; + h->total_subsongs = 1; + h->start_offset -= h->stream_offset; /* also channels may be inverted [Fat Princess (PS3)] */ + } + h->interleave = h->stream_size / h->channels; + + /* PS Home Arcade has other flags? supposedly: + * 01 = reverb + * 02 = vol scale 20 + * 04 = vol scale 50 + * 06 = vol scale 100 + * 08 = noise + * 10 = no dry + * 20 = no steal + * 40 = loop VAG + * 80 = PCM + * 100 = has advanced packets + * 200 = send LFE + * 400 = send center + */ + if ((h->stream_flags & 0x80) && h->sblk_version <= 3) { + h->codec = PCM16; /* rare [Wipeout HD (PS3)]-v3 */ + } + else { + h->loop_flag = ps_find_loop_offsets(sf, h->start_offset, h->stream_size, h->channels, h->interleave, &h->loop_start, &h->loop_end); + h->loop_flag = (h->stream_flags & 0x40); /* only applies to PS-ADPCM flags */ + + h->codec = PSX; + } + + //postdata_size = 0x10; /* last frame may be garbage */ + break; + + case 0x08: + case 0x09: + subtype = read_u16(h->start_offset+0x00,sf); + extradata_size = 0x08 + read_u32(h->start_offset+0x04,sf); /* 0x14 for AT9 */ + + switch(subtype) { + case 0x00: + h->channels = 1; + h->codec = PSX; + h->interleave = 0x10; + break; + + case 0x01: + h->channels = 1; + h->codec = PCM16; + h->interleave = 0x01; + break; + + + case 0x02: /* ATRAC9 mono */ + case 0x05: /* ATRAC9 stereo */ + if (read_u32(h->start_offset+0x08,sf) + 0x08 != extradata_size) { /* repeat? */ + VGM_LOG("BNK: unknown subtype\n"); + goto fail; + } + h->channels = (subtype == 0x02) ? 1 : 2; + + h->atrac9_info = read_u32be(h->start_offset+0x0c,sf); + /* 0x10: null? */ + loop_length = read_u32(h->start_offset+0x14,sf); + h->loop_start = read_u32(h->start_offset+0x18,sf); + h->loop_end = h->loop_start + loop_length; /* loop_start is -1 if not set */ + + h->codec = ATRAC9; + break; + + default: + vgm_logi("BNK: unknown subtype %x (report)\n", subtype); + goto fail; + } + break; + + case 0x0d: + case 0x0e: + case 0x0f: + case 0x10: + subtype = read_u16(h->start_offset+0x00,sf); + if (read_u32(h->start_offset+0x04,sf) != 0x01) { /* type? */ + VGM_LOG("BNK: unknown subtype\n"); + goto fail; + } + extradata_size = 0x10 + read_u32(h->start_offset+0x08,sf); /* 0x80 for AT9, 0x10 for PCM/PS-ADPCM */ + /* 0x0c: null? */ + + switch(subtype) { + case 0x02: /* ATRAC9 mono */ + case 0x05: /* ATRAC9 stereo */ + if (read_u32(h->start_offset+0x10,sf) + 0x10 != extradata_size) /* repeat? */ + goto fail; + h->channels = (subtype == 0x02) ? 1 : 2; + + h->atrac9_info = read_u32be(h->start_offset+0x14,sf); + /* 0x18: null? */ + /* 0x1c: channels? */ + /* 0x20: null? */ + + loop_length = read_u32(h->start_offset+0x24,sf); + h->loop_start = read_u32(h->start_offset+0x28,sf); + h->loop_end = h->loop_start + loop_length; /* loop_start is -1 if not set */ + + h->codec = ATRAC9; + break; + + case 0x01: /* PCM16LE mono? (NekoBuro/Polara sfx) */ + case 0x04: /* PCM16LE stereo? (NekoBuro/Polara sfx) */ + /* 0x10: null? */ + h->channels = read_u32(h->start_offset+0x14,sf); + h->interleave = 0x02; + + h->loop_start = read_u32(h->start_offset+0x18,sf); + loop_length = read_u32(h->start_offset+0x1c,sf); + h->loop_end = h->loop_start + loop_length; /* loop_start is -1 if not set */ + + h->codec = PCM16; + break; + + case 0x00: /* HEVAG (test banks) */ + case 0x03: /* HEVAG (Ikaruga) */ + /* 0x10: null? */ + h->channels = read_u32(h->start_offset+0x14,sf); + h->interleave = 0x10; + + h->loop_start = read_u32(h->start_offset+0x18,sf); + loop_length = read_u32(h->start_offset+0x1c,sf); + h->loop_end = h->loop_start + loop_length; /* loop_start is -1 if not set */ + + h->codec = HEVAG; + //TODO: in v0x0f right before start_offset is the .vag filename, see if offset can be found + break; + + default: + vgm_logi("BNK: unknown subtype %x (report)\n", subtype); + goto fail; + } + break; + + case 0x1a: + case 0x23: + if (h->stream_offset == 0xFFFFFFFF) { + h->channels = 1; + h->codec = DUMMY; + break; + } + + /* pre-info */ + h->stream_name_size = read_u64(info_offset+0x00,sf); + h->stream_name_offset = info_offset + 0x08; + info_offset += h->stream_name_size + 0x08; + + h->stream_size = read_u64(info_offset + 0x00,sf); /* after this offset */ + h->stream_size += 0x08 + h->stream_name_size + 0x08; + /* 0x08: max block/etc size? (0x00010000/00030000) */ + /* 0x0c: always 1? */ + extradata_size = read_u64(info_offset + 0x10,sf) + 0x08 + h->stream_name_size + 0x18; + info_offset += 0x18; + + /* actual stream info */ + /* 0x00: extradata size (without pre-info, also above) */ + h->atrac9_info = read_u32be(info_offset+0x04,sf); + h->num_samples = read_s32(info_offset+0x08,sf); + h->channels = read_u32(info_offset+0x0c,sf); + h->loop_start = read_s32(info_offset+0x10,sf); + h->loop_end = read_s32(info_offset+0x14,sf); + /* 0x18: loop flag (0=loop, -1=no) */ + /* rest: null */ + /* no sample rate (probably fixed to 48000/system's, but seen in RIFF) */ + h->sample_rate = 48000; + + h->codec = RIFF_ATRAC9; /* unsure how other codecs would work */ + break; + + default: + vgm_logi("BNK: unknown data version %x (report)\n", h->sblk_version); + goto fail; + } + + h->start_offset += extradata_size; + h->stream_size -= extradata_size; + h->stream_size -= postdata_size; + //;VGM_LOG("BNK: offset=%x, size=%x\n", h->start_offset, h->stream_size); + + return true; +fail: + return false; +} + + +/* zlsd part: parse extra footer (vox?) data */ +static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { + if (!h->zlsd_offset) + return true; + + read_u32_t read_u32 = h->big_endian ? read_u32be : read_u32le; + + if (read_u32(h->zlsd_offset+0x00,sf) != get_id32be("DSLZ")) + return false; + + /* 0x04: version? (1) */ + int zlsd_count = read_u32(h->zlsd_offset+0x08,sf); + /* 0x0c: start */ + /* rest: null */ + + if (zlsd_count) { + vgm_logi("BNK: unsupported ZLSD subsongs found\n"); + goto fail; + } + + /* per entry (for v23) + * 00: crc (not referenced elsewhere) + * 04: stream offset (from this offset) + * 08: null (part of offset?) + * 0c: stream size + * 10: offset/size? + * 14: null */ + /* known streams are standard XVAG (no subsongs) */ + + return true; +fail: + return false; +} + + +/* parse SCREAM bnk (usually SFX but also used for music) */ +static bool parse_bnk_v3(STREAMFILE* sf, bnk_header_t* h) { + + /* bnk/SCREAM tool version (v2 is a bit different, not seen v1) */ + if (read_u32be(0x00,sf) == 0x03) { /* PS3 */ + h->big_endian = 1; + } + else if (read_u32le(0x00,sf) == 0x03) { /* PS2/PSP/Vita/PS4 */ + h->big_endian = 0; + } + else { + return false; + } + + read_u32_t read_u32 = h->big_endian ? read_u32be : read_u32le; + + int sections = read_u32(0x04,sf); /* SBlk, data, ZLSD */ + if (sections < 2 || sections > 3) + return false; + /* in theory a bank can contain multiple blocks but only those are used */ + + /* section sizes don't include padding (sometimes aligned to 0x10/0x800) */ + h->sblk_offset = read_u32(0x08,sf); + //h->sblk_size = read_u32(0x0c,sf); + h->data_offset = read_u32(0x10,sf); + h->data_size = read_u32(0x14,sf); + /* ZLSD footer, rare in earlier versions and common later (often empty) [Yakuza 6's Puyo Puyo (PS4)] */ + if (sections >= 3) { + h->zlsd_offset = read_u32(0x18,sf); + h->zlsd_size = read_u32(0x1c,sf); + } + + if (h->sblk_offset > 0x20) + return false; + + /* Most table fields seems reserved/defaults and don't change much between subsongs or files, + * so they aren't described in detail. Entry sizes are variable (usually flag + extra size xN) + * so table offsets are needed. */ + + + /* SBlk part: parse header */ + if (read_u32(h->sblk_offset+0x00,sf) != get_id32be("klBS")) /* SBlk = SFX block */ + return false; + h->sblk_version = read_u32(h->sblk_offset+0x04,sf); + /* 0x08: flags? (h->sblk_version>=0x0d?, 0x03=Vita, 0x06=PS4, 0x05=PS5, 0x07=PS5) + * - 04: non-fixed bank? + * - 100: 'has names' + * - 200: 'has user data' */ + /* version < v0x1a: + * - 0x0c: block id + * - 0x10: block number + * - 0x11: padding + * version >= v0x1a: + * - 0x0c: hash (0x10) + * - 0x1c: filename (0x100?) + * version ~= v0x23: + * - 0x0c: null (depends on flags? v1a=0x05, v23=0x07) + * - 0x10: hash (0x10) + * - 0x20: filename (0x100?) + */ + //;VGM_LOG("BNK: h->sblk_offset=%lx, h->data_offset=%lx, h->sblk_version %x\n", h->sblk_offset, h->data_offset, h->sblk_version); + //TODO handle, in rare cases may contain subsongs (unsure how are referenced but has its own number) + + if (!process_tables(sf, h)) + goto fail; + if (!process_headers(sf, h)) + goto fail; + if (!process_names(sf, h)) + goto fail; + if (!process_data(sf, h)) + goto fail; + if (!process_zlsd(sf, h)) + goto fail; + + h->loop_flag = (h->loop_start >= 0) && (h->loop_end > 0); + + return true; +fail: + return false; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wii_bns.c b/Frameworks/vgmstream/vgmstream/src/meta/bns.c similarity index 97% rename from Frameworks/vgmstream/vgmstream/src/meta/wii_bns.c rename to Frameworks/vgmstream/vgmstream/src/meta/bns.c index 12fc35c3c..c184f59ee 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/wii_bns.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/bns.c @@ -3,7 +3,7 @@ #include "../util.h" /* BNS - Wii "Banner Sound" disc jingle */ -VGMSTREAM* init_vgmstream_wii_bns(STREAMFILE* sf) { +VGMSTREAM* init_vgmstream_bns(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; off_t bns_offset; uint32_t info_offset = 0, data_offset = 0; @@ -15,7 +15,7 @@ VGMSTREAM* init_vgmstream_wii_bns(STREAMFILE* sf) { /* .bin: actual extension * .bns: header id */ if (!check_extensions(sf, "bin,lbin,bns")) - goto fail; + return NULL; bns_offset = 0; if (is_id32be(bns_offset + 0x40, sf, "IMET")) { @@ -32,9 +32,9 @@ VGMSTREAM* init_vgmstream_wii_bns(STREAMFILE* sf) { } if (!is_id32be(bns_offset + 0x00,sf, "BNS ")) - goto fail; + return NULL; if (read_u32be(bns_offset + 0x04,sf) != 0xFEFF0100u) - goto fail; + return NULL; /* find chunks */ { @@ -110,7 +110,7 @@ VGMSTREAM* init_vgmstream_wii_bns(STREAMFILE* sf) { vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; - vgmstream->meta_type = meta_WII_BNS; + vgmstream->meta_type = meta_BNS; vgmstream->sample_rate = sample_rate; vgmstream->num_samples = sample_count; vgmstream->loop_start_sample = loop_start; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/btsnd.c b/Frameworks/vgmstream/vgmstream/src/meta/btsnd.c index 8a670140f..97f5fd289 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/btsnd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/btsnd.c @@ -11,30 +11,37 @@ VGMSTREAM* init_vgmstream_btsnd(STREAMFILE* sf) { /* checks */ if (!check_extensions(sf, "btsnd")) - goto fail; + return NULL; - if (read_u32be(0x00,sf) != 0x02) - goto fail; + uint32_t type = read_u32be(0x00,sf); + if (type == 0x00) { + loop_flag = 0; + } + else if (type == 0x02) { + loop_flag = 1; + } + else { + return NULL; + } - loop_start = read_s32be(0x04, sf); + loop_start = read_s32be(0x04, sf); /* non-looping: 0 or some number lower than samples */ start_offset = 0x08; - channels = 2; - loop_flag = loop_start > 0; - /* extra check since format is so simple */ + /* extra checks since format is so simple */ data_size = get_streamfile_size(sf); num_samples = pcm16_bytes_to_samples(data_size - start_offset, channels); if (loop_start >= num_samples) - goto fail; - + return NULL; + if (num_samples > 960000) /* known max reached by various games, encoder/Wii U limit? */ + return NULL; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; - vgmstream->meta_type = meta_WIIU_BTSND; + vgmstream->meta_type = meta_BTSND; vgmstream->sample_rate = 48000; vgmstream->num_samples = num_samples; vgmstream->loop_start_sample = loop_start; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/dc_str.c b/Frameworks/vgmstream/vgmstream/src/meta/dc_str.c deleted file mode 100644 index d9be078db..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/dc_str.c +++ /dev/null @@ -1,165 +0,0 @@ -#include "meta.h" -#include "../coding/coding.h" -#include "../util.h" - -/* SEGA Stream Asset Builder... - this meta handles only V1 and V3... */ - -VGMSTREAM * init_vgmstream_dc_str(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - int loop_flag = 0; - int interleave; - int channel_count; - int samples; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("str",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0xD5,streamFile) != 0x53656761) /* "Sega" */ - goto fail; - - interleave = read_32bitLE(0xC,streamFile); - if ((get_streamfile_size(streamFile)-0x800) != (read_32bitLE(0x10,streamFile) * - ((read_32bitLE(0x0,streamFile)*(read_32bitLE(0x18,streamFile))))*interleave)) - goto fail; - - - loop_flag = 0; /* (read_32bitLE(0x00,streamFile)!=0x00000000); */ - samples = read_32bitLE(0x08,streamFile); - channel_count = (read_32bitLE(0x0,streamFile))*(read_32bitLE(0x18,streamFile)); - - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - - /* fill in the vital statistics */ - switch (samples) { - case 4: - vgmstream->coding_type = coding_AICA_int; - vgmstream->num_samples = read_32bitLE(0x14,streamFile); - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = read_32bitLE(0x14,streamFile); - } - break; - case 16: - vgmstream->coding_type = coding_PCM16LE; - vgmstream->num_samples = read_32bitLE(0x14,streamFile)/2/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = read_32bitLE(0x14,streamFile)/2/channel_count; - } - break; - default: - goto fail; -} - - - start_offset = 0x800; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x04,streamFile); - - if (vgmstream->channels == 1) { - vgmstream->layout_type = layout_none; - } else if (vgmstream->channels > 1) { - vgmstream->interleave_block_size = interleave; - vgmstream->layout_type = layout_interleave; - } - - vgmstream->meta_type = meta_DC_STR; - - /* 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; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - -/* This handles V2, not sure if it is really V2, cause the header is always - the same, not like in V1 and V3, only found in "102 Dalmatians - Puppies to the Rescue" - until now... */ - -VGMSTREAM * init_vgmstream_dc_str_v2(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - int loop_flag = 0; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("str",filename_extension(filename))) goto fail; - - /* check header */ - if ((read_32bitLE(0x00,streamFile) != 0x2)) - goto fail; - if ((read_32bitLE(0x10,streamFile) != 0x10000)) - goto fail; - if ((read_32bitLE(0x1C,streamFile) != 0x1F)) - goto fail; - - channel_count = 2; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x800; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x4,streamFile); - vgmstream->coding_type = coding_PCM16LE; - vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0xC,streamFile); - vgmstream->meta_type = meta_DC_STR_V2; - - /* 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; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/filp.c b/Frameworks/vgmstream/vgmstream/src/meta/filp.c new file mode 100644 index 000000000..1f4e9e028 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/filp.c @@ -0,0 +1,55 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../coding/coding.h" + + +/* FILp - from Resident Evil: Dead Aim (PS2) */ +VGMSTREAM* init_vgmstream_filp(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint32_t start_offset; + int channels, loop_flag; + + + /* checks */ + if (!is_id32be(0x00,sf, "FILp")) + return NULL; + /* .fil: extension in bigfile */ + if (!check_extensions(sf,"fil")) + return NULL; + + channels = read_s32le(0x04,sf); /* stereo only though */ + if (read_32bitLE(0x0C,sf) != get_streamfile_size(sf)) + goto fail; + loop_flag = (read_u32le(0x34,sf) == 0x00); /* 00/01/02 */ + + if (!is_id32be(0x100,sf, "VAGp")) + return NULL; + if (!is_id32be(0x130,sf, "VAGp")) + return NULL; + + start_offset = 0x00; /* multiple FILp blocks pasted together (each including VAGps, but their sizes refer to the whole thing) */ + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_FILP; + vgmstream->sample_rate = read_s32le(0x110,sf); + + vgmstream->num_samples = ps_bytes_to_samples(read_u32le(0x10C,sf), 1); /* channel size for the whole stream */ + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = vgmstream->num_samples; + + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_blocked_filp; + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + block_update(start_offset, vgmstream); + + return vgmstream; +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb5_fev.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb5_fev.c index 6a59ae3d7..8ba874523 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb5_fev.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb5_fev.c @@ -18,12 +18,12 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) { /* checks */ if (!is_id32be(0x00,sf, "RIFF")) - goto fail; + return NULL; if (!is_id32be(0x08,sf, "FEV ")) - goto fail; + return NULL; if (!check_extensions(sf, "bank")) - goto fail; + return NULL; version = read_u32le(0x14,sf); /* newer FEV have some kind of sub-version at 0x18 */ @@ -102,8 +102,10 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) { off_t fsb5_offset = read_u32le(bank_offset + 0x04 + entry_size*i + 0x00,sf); size_t fsb5_size = read_u32le(bank_offset+0x08 + entry_size*i,sf); int fsb5_subsongs = get_subsongs(sf, fsb5_offset, fsb5_size); - if (!fsb5_subsongs) + if (!fsb5_subsongs) { + vgm_logi("FSB: couldn't load bank (encrypted?)\n"); goto fail; + } /* target in range */ if (target_subsong >= total_subsongs + 1 && target_subsong < total_subsongs + 1 + fsb5_subsongs) { @@ -140,7 +142,10 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) { vgmstream = (read_u32be(0x00, temp_sf) == 0x46534235) ? /* "FSB5" (better flag?)*/ init_vgmstream_fsb5(temp_sf) : init_vgmstream_fsb_encrypted(temp_sf); - if (!vgmstream) goto fail; + if (!vgmstream) { + vgm_logi("FSB: couldn't load bank (encrypted?)\n"); + goto fail; + } vgmstream->stream_index = sf->stream_index; //target_subsong; /* 0-index matters */ vgmstream->num_streams = total_subsongs; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/fsb_keys.h index b852a04ec..1e57ca345 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb_keys.h @@ -58,6 +58,7 @@ static const fsbkey_info fsbkey_list[] = { { MODE_FSB4_ALT, FSBKEY_ADD("truck/impact/carbody") },// Monster Jam (PS2) [FSB3] { MODE_FSB4_ALT, FSBKEY_ADD("\xFC\xF9\xE4\xB3\xF5\x57\x5C\xA5\xAC\x13\xEC\x4A\x43\x19\x58\xEB\x4E\xF3\x84\x0B\x8B\x78\xFA\xFD\xBB\x18\x46\x7E\x31\xFB\xD0") }, // Guitar Hero 5 (X360) { MODE_FSB4_ALT, FSBKEY_ADD("\x8C\xFA\xF3\x14\xB1\x53\xDA\xAB\x2B\x82\x6B\xD5\x55\x16\xCF\x01\x90\x20\x28\x14\xB1\x53\xD8") }, // Guitar Hero: Metallica (X360) + { MODE_FSB4_STD, FSBKEY_ADD("\xd2\x37\x70\x39\xa9\x86\xc5\xaf\x5b\x7f\xa2\x23\x98\x7e\xb6\xc2\x7e\x18\x7b\x2d\xd9\x31\x4b\x20\xb0\xc1\x8d\x06\xf2\xa7\xcd") }, // Guitar Hero: Metallica (PS3) [FSB4] { MODE_FSB5_STD, FSBKEY_ADD("G0KTrWjS9syqF7vVD6RaVXlFD91gMgkC") }, // Sekiro: Shadows Die Twice (PC) { MODE_FSB5_STD, FSBKEY_ADD("BasicEncryptionKey") }, // SCP: Unity (PC) { MODE_FSB5_STD, FSBKEY_ADD("FXnTffGJ9LS855Gc") }, // Worms Rumble Beta (PC) @@ -71,6 +72,7 @@ static const fsbkey_info fsbkey_list[] = { { MODE_FSB5_STD, FSBKEY_ADD("281ad163160cfc16f9a22c6755a64fad") }, // Ash Echoes beta (Android) { MODE_FSB5_STD, FSBKEY_ADD("Aurogon666") }, // Afterimage demo (PC) { MODE_FSB5_STD, FSBKEY_ADD("IfYouLikeThosesSoundsWhyNotRenumerateTheir2Authors?") }, // Blanc (PC/Switch) + { MODE_FSB5_STD, FSBKEY_ADD("L36nshM520") }, // Nishuihan Mobile (Android) }; static const int fsbkey_list_count = sizeof(fsbkey_list) / sizeof(fsbkey_list[0]); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/gsp_gsb.c b/Frameworks/vgmstream/vgmstream/src/meta/gsnd.c similarity index 64% rename from Frameworks/vgmstream/vgmstream/src/meta/gsp_gsb.c rename to Frameworks/vgmstream/vgmstream/src/meta/gsnd.c index 15ec2bcb2..9ea897f3f 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/gsp_gsb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/gsnd.c @@ -4,55 +4,55 @@ #include "../util/chunks.h" /* GSP+GSB - from Tecmo's Super Swing Golf 1 & 2 (Wii), Quantum Theory (PS3/X360) */ -VGMSTREAM* init_vgmstream_gsp_gsb(STREAMFILE* sf) { +VGMSTREAM* init_vgmstream_gsnd(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; - STREAMFILE* sf_head = NULL; + STREAMFILE* sb = NULL; int loop_flag, channel_count, sample_rate, num_samples, loop_start, loop_end; off_t start_offset, chunk_offset, first_offset; size_t data_size; int codec; - /* checks */ - if (!check_extensions(sf,"gsb")) + if (!is_id32be(0x00,sf, "GSND")) goto fail; - sf_head = open_streamfile_by_ext(sf, "gsp"); - if (!sf_head) goto fail; - - if (!is_id32be(0x00,sf_head, "GSND")) + if (!check_extensions(sf,"gsp")) goto fail; + + sb = open_streamfile_by_ext(sf, "gsb"); + if (!sb) goto fail; + /* 0x04: version? */ /* 0x08: 1? */ /* 0x0c: 0? */ - first_offset = read_32bitBE(0x10,sf_head); /* usually 0x14 */ + first_offset = read_32bitBE(0x10,sf); /* usually 0x14 */ - if (!find_chunk_be(sf_head, 0x48454144,first_offset,1, &chunk_offset,NULL)) /* "HEAD" */ + if (!find_chunk_be(sf, get_id32be("HEAD"),first_offset,1, &chunk_offset,NULL)) goto fail; /* 0x00: header size */ /* 0x04: num_chunks */ - if (!find_chunk_be(sf_head, 0x44415441,first_offset,1, &chunk_offset,NULL)) /* "DATA" */ + if (!find_chunk_be(sf, get_id32be("DATA"),first_offset,1, &chunk_offset,NULL)) goto fail; - data_size = read_32bitBE(chunk_offset + 0x00,sf_head); - codec = read_32bitBE(chunk_offset + 0x04,sf_head); - sample_rate = read_32bitBE(chunk_offset + 0x08,sf_head); + data_size = read_32bitBE(chunk_offset + 0x00,sf); + codec = read_32bitBE(chunk_offset + 0x04,sf); + sample_rate = read_32bitBE(chunk_offset + 0x08,sf); /* 0x0c: always 16? */ - channel_count = read_16bitBE(chunk_offset + 0x0e,sf_head); + channel_count = read_16bitBE(chunk_offset + 0x0e,sf); /* 0x10: always 0? */ - num_samples = read_32bitBE(chunk_offset + 0x14,sf_head); + num_samples = read_32bitBE(chunk_offset + 0x14,sf); /* 0x18: always 0? */ /* 0x1c: unk (varies with codec_id) */ - if (!find_chunk_be(sf_head, 0x42534943,first_offset,1, &chunk_offset,NULL)) /* "BSIC" */ + if (!find_chunk_be(sf, get_id32be("BSIC"),first_offset,1, &chunk_offset,NULL)) goto fail; /* 0x00/0x04: probably volume/pan/etc floats (1.0) */ /* 0x08: null? */ - loop_flag = read_8bit(chunk_offset+0x0c,sf_head); - loop_start = read_32bitBE(chunk_offset+0x10,sf_head); - loop_end = read_32bitBE(chunk_offset+0x14,sf_head); + loop_flag = read_8bit(chunk_offset+0x0c,sf); + loop_start = read_32bitBE(chunk_offset+0x10,sf); + loop_end = read_32bitBE(chunk_offset+0x14,sf); - //if (!find_chunk_be(streamHeader, 0x4E414D45,first_offset,1, &chunk_offset,NULL)) /* "NAME" */ + //if (!find_chunk_be(streamHeader, get_id32be("NAME"),first_offset,1, &chunk_offset,NULL)) // goto fail; /* 0x00: name_size */ /* 0x04+: name (same as filename) */ @@ -65,7 +65,7 @@ VGMSTREAM* init_vgmstream_gsp_gsb(STREAMFILE* sf) { vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - vgmstream->meta_type = meta_GSP_GSB; + vgmstream->meta_type = meta_GSND; vgmstream->sample_rate = sample_rate; vgmstream->num_samples = num_samples; @@ -80,16 +80,16 @@ VGMSTREAM* init_vgmstream_gsp_gsb(STREAMFILE* sf) { vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_blocked_gsb; - if (!find_chunk_be(sf_head, 0x47434558,first_offset,1, &chunk_offset,NULL)) /* "GCEX" */ + if (!find_chunk_be(sf, get_id32be("GCEX"),first_offset,1, &chunk_offset,NULL)) goto fail; //vgmstream->current_block_size = read_32bitBE(chunk_offset+0x00,streamHeader); - block_header_size = read_32bitBE(chunk_offset+0x04,sf_head); - num_blocks = read_32bitBE(chunk_offset+0x08,sf_head); + block_header_size = read_32bitBE(chunk_offset+0x04,sf); + num_blocks = read_32bitBE(chunk_offset+0x08,sf); vgmstream->num_samples = (data_size - block_header_size * num_blocks) / 8 / vgmstream->channels * 14; /* 0x0c+: unk */ - dsp_read_coefs_be(vgmstream, sf_head, chunk_offset+0x18, 0x30); + dsp_read_coefs_be(vgmstream, sf, chunk_offset+0x18, 0x30); break; } #ifdef VGM_USE_FFMPEG @@ -101,7 +101,7 @@ VGMSTREAM* init_vgmstream_gsp_gsb(STREAMFILE* sf) { vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_align) - encoder_delay; /* fix num_samples as header samples seem to be modified to match altered (49999/48001) sample rates somehow */ - vgmstream->codec_data = init_ffmpeg_atrac3_raw(sf, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay); + vgmstream->codec_data = init_ffmpeg_atrac3_raw(sb, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; @@ -112,18 +112,18 @@ VGMSTREAM* init_vgmstream_gsp_gsb(STREAMFILE* sf) { break; } - case 0x09: { /* XMA2 [Quantum Theory (PS3)] */ - if (!find_chunk_be(sf_head, 0x584D4558,first_offset,1, &chunk_offset,NULL)) /* "XMEX" */ + case 0x09: { /* XMA2 [Quantum Theory (X360)] */ + if (!find_chunk_be(sf, get_id32be("XMEX"),first_offset,1, &chunk_offset,NULL)) /* "XMEX" */ goto fail; /* 0x00: fmt0x166 header (BE) */ /* 0x34: seek table */ - vgmstream->codec_data = init_ffmpeg_xma_chunk_split(sf_head, sf, start_offset, data_size, chunk_offset, 0x34); + vgmstream->codec_data = init_ffmpeg_xma_chunk_split(sf, sb, start_offset, data_size, chunk_offset, 0x34); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; - xma_fix_raw_samples(vgmstream, sf, start_offset,data_size, 0, 0,0); /* samples are ok */ + xma_fix_raw_samples(vgmstream, sb, start_offset,data_size, 0, 0,0); /* samples are ok */ break; } #endif @@ -132,13 +132,13 @@ VGMSTREAM* init_vgmstream_gsp_gsb(STREAMFILE* sf) { } - if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + if (!vgmstream_open_stream(vgmstream, sb, start_offset)) goto fail; - close_streamfile(sf_head); + close_streamfile(sb); return vgmstream; fail: - close_streamfile(sf_head); + close_streamfile(sb); close_vgmstream(vgmstream); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h index 555f47a43..a0ac49740 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h @@ -424,6 +424,9 @@ static const hcakey_info hcakey_list[] = { {0xc4276ffaee4aadec}, //music_0000005 {0x683d739be9679e61}, //music_0000006 {0xa3adc531c32bb128}, //music_0000007 + {0xbb8f42a806d1fa6}, //music_0000008 + {0xfd6e5a721921d936}, //music_0000009 + {0x7749847207a5f0da}, //music_0000010 {0x52d065d9ccdb8696}, //music_0110001 {0xba26e58923a5da5d}, //music_0110002 {0x5b877af6e52af19b}, //music_0110003 @@ -454,6 +457,7 @@ static const hcakey_info hcakey_list[] = { {0x22c6b455883b1c28}, //music_0110030 {0xff2ae68fa067f80a}, //music_0110031 {0x422ca19b0fa5c7c0}, //music_0110032 + {0x3b11592a696da747}, //music_0110033 {0xfb647d074e53fab6}, //music_0120001 {0xc24049b9f7ed3105}, //music_0120002 {0xdc128f2fd48bf4b}, //music_0120003 @@ -495,6 +499,7 @@ static const hcakey_info hcakey_list[] = { {0xe38b758bcadfc621}, //music_0210018 {0x3399e970670db2ba}, //music_0210019 {0x1cb76530af356c05}, //music_0210020 + {0x2ae40b627c7125d7}, //music_0210021 {0x15bb78c31db0a0b6}, //music_0220001 {0x59b1257242c40109}, //music_0220002 {0xdb402bd08d522f34}, //music_0220003 @@ -576,6 +581,7 @@ static const hcakey_info hcakey_list[] = { {0x685b5601a43b6c60}, //music_0410018 {0x75927596a180f3e3}, //music_0410019 {0xc3d36676d54255c5}, //music_0410020 + {0x41283c6f06db3cdd}, //music_0410021 {0x5d1f3fdbbb036f8d}, //music_0420001 {0xc04264e8f34ad5c0}, //music_0420002 {0x8f0e96b4f71f724f}, //music_0420003 @@ -615,6 +621,8 @@ static const hcakey_info hcakey_list[] = { {0xb069a5c5e2d93edf}, //music_0510019 {0x30f9dcefa450733a}, //music_0510020 {0xf85695960e2dcb7f}, //music_0510021 + {0x212604f36a4ddb0c}, //music_0510022 + {0xef7ee9169b194770}, //music_0510023 {0x15f82c1617013c36}, //music_0520001 {0xc7da8e6f0e2fe399}, //music_0520002 {0xe350bffcdc9cb686}, //music_0520003 @@ -655,6 +663,8 @@ static const hcakey_info hcakey_list[] = { {0x7aece54359beac21}, //music_0610021 {0x7c9332be25e5c95a}, //music_0610022 {0x415eef25f84e8c2e}, //music_0610023 + {0xfd2237157af70152}, //music_0610024 + {0xf6c91cba66c3fe68}, //music_0610025 {0x8258ddd6a1d0849b}, //music_0620001 {0x1dd21a1244ca12f1}, //music_0620002 {0xfdec74b23d8b494b}, //music_0620003 @@ -674,15 +684,23 @@ static const hcakey_info hcakey_list[] = { {0x5c1195d8afcb1901}, //music_0620017 {0x1ad8db767d9ba4a7}, //music_0620018 {0x9bc820aa161b0f08}, //music_0620019 + {0x85f26fa7befc2b5a}, //music_0810000 {0xd1df27a57399613e}, //music_0810001 {0xd37ec4cb304e16ae}, //music_0810002 + {0x4582fedda6a62aa8}, //music_0810003 + {0xb31ea911ea8aba81}, //music_0810004 {0x1e99d14d97ab82c5}, //music_0820001 {0x5bf7cefecda8bcb2}, //music_0820002 {0x9cf7ab0ccafa374e}, //music_0820003 + {0x7a9e4b710716a8e2}, //music_0910000 {0x972b52f3dfaa387a}, //music_0910001 {0x407a4b6c3dcf2509}, //music_0910002 + {0x838be1aa4dc372bb}, //music_0910003 + {0xc03bac003c24471d}, //music_0910004 + {0xf864df0abe22ec49}, //music_0910005 {0x4683c57919dbdeee}, //music_0920001 {0x126d0d20ad7f0401}, //music_0920002 + {0x1652eb8bf3cea8f5}, //music_0920003 {0x2a47feac8dc3ca9c}, //music_3010001 {0x9ebbaf63ffe9d9ef}, //music_3010002 {0xe553dba6592293d8}, //music_3010003 @@ -700,10 +718,16 @@ static const hcakey_info hcakey_list[] = { {0x5e23d8a2488bc715}, //music_3010016 {0x198cc607e20dd264}, //music_3010017 {0x31a9ab25b5dff424}, //music_3010018 + {0x86e823895bb0bec6}, //music_3010019 {0x17f53cfa841f41b5}, //music_3010020 {0x4992a33be3ba81dd}, //music_3010021 {0x86d0ab836f09a599}, //music_3010022 + {0x2a5eefc1987bf7fb}, //music_3010023 {0x157f20b466d75228}, //music_3010024 + {0x13cada13f45f432b}, //music_3010025 + {0xe0f08378be17633b}, //music_3010026 + {0xaf81e107cd20ba90}, //music_3010027 + {0x4efe51d362dcb6b1}, //music_3010028 {0xfd3ea450350d666f}, //music_3020001 {0x5e91a3790c32e2b3}, //music_3020002 {0x358adfd1bbd3a95e}, //music_3020003 @@ -719,11 +743,18 @@ static const hcakey_info hcakey_list[] = { {0x3d01826fe053ddda}, //music_3020014 {0xa6a6426caed68f7c}, //music_3020015 {0x34cc16f635101f02}, //music_3020016 + {0xc92c94fdc988b8fa}, //music_3020017 {0x4429ed54ca45a36d}, //music_3020018 {0xcc935f3ebbb7bb94}, //music_3020019 {0x4a1d57f0db140c12}, //music_3020020 {0x8ddea25a12f93099}, //music_3020022 {0xf754248dcd46287e}, //music_3020023 + {0xa3c06ffa7775a274}, //music_3020024 + {0x427be43aa233382c}, //music_3020025 + {0x4ec96dd7db2adfd7}, //music_3020026 + {0x9f12a5003f112aaa}, //music_3020028 + {0x38edf73f19401e1c}, //music_3020030 + {0xfa2c72797fa3e388}, //music_3020031 {0xdfad847a86a126bb}, //music_5030001 {0x711ef85045b8c26e}, //music_5030002 {0xff7640b46d72b337}, //music_5030003 @@ -989,6 +1020,7 @@ static const hcakey_info hcakey_list[] = { {0x1be3e8255dde31e3}, //music_5050147 {0x58b735f1a68c9a81}, //music_5050148 {0x5b3cb281d89019db}, //music_5050149 + {0x74f39448d2b75d4d}, //music_5050150 {0x2b1a0269a3d890d4}, //music_5050151 {0x74e058fd628364c9}, //music_5050152 {0x3ade68d4857395c0}, //music_5050153 @@ -1042,6 +1074,29 @@ static const hcakey_info hcakey_list[] = { {0x929ca6a5e8e0445}, //music_5050206 {0xf0de6097ea78513c}, //music_5050207 {0xcde0de0e1216bdea}, //music_5050208 + {0xb496e9301bfc57c4}, //music_5050209 + {0xff4db63086831e8f}, //music_5050210 + {0x21cd7a36d33daae9}, //music_5050211 + {0x88fe1d5592979a66}, //music_5050212 + {0x1782668d98097f3b}, //music_5050213 + {0xb174215f3ed746e3}, //music_5050214 + {0x445aa44e5029d76b}, //music_5050215 + {0x39b3d29fc04211ed}, //music_5050216 + {0x6856a8773f3e7712}, //music_5050217 + {0x7f08330d7d971292}, //music_5050218 + {0x6ac19245cd7e8de0}, //music_5050219 + {0x7a0ed12fd8b5a9e8}, //music_5050220 + {0xc13b8037e2be01bf}, //music_5050221 + {0x5856576aa5c0a59f}, //music_5050222 + {0xe8286a95b8f38dd1}, //music_5050223 + {0x48015b291de44ff3}, //music_5050224 + {0x4521644fd1682bc0}, //music_5050226 + {0x808e307ec28b9ef0}, //music_5050227 + {0x6a4493f6e7dcce6c}, //music_5050228 + {0xd6bc23de632b00e0}, //music_5050229 + {0x7268ea33e33cbcfa}, //music_5050230 + {0x2de61d98bc2cea48}, //music_5050231 + {0xd8bdb31ab72c355b}, //music_5050242 {0x52c250eade92393b}, //music_9010001 {0xf66e6bb5b0599b07}, //music_9010002 {0x8582b5a60dbbf948}, //music_9010003 @@ -1187,6 +1242,18 @@ static const hcakey_info hcakey_list[] = { // Disney Star Smash (Android) {3941111674189632}, // 000E006B915C3740 + // Final Fantasy VII: Ever Crisis (beta) (Android) + {19629307353822}, // 000011DA4DE45ADE + + // Tower of Sky (Android) + {5893902754391672}, // 0014F0792C042678 + + // The Irregular at Magic High School: Reloaded Memory (Android) + {7181280307767738368}, // 63A9086451010000 + + // BlazBlue Entropy Effect (Early Access) (PC) + {29814655674508831}, // 0069EC457894661F + }; #endif/*_HCA_KEYS_H_*/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hgc1.c b/Frameworks/vgmstream/vgmstream/src/meta/hgc1.c new file mode 100644 index 000000000..1b3d9acb9 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/hgc1.c @@ -0,0 +1,41 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* hgC1 - from Knights of the Temple 2 (PS2) */ +VGMSTREAM* init_vgmstream_hgc1(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint32_t start_offset; + int channels, loop_flag = 0; + + /* checks */ + if (!is_id32be(0x00,sf, "hgC1")) + return NULL; + if (!is_id32be(0x04,sf, "strm")) + return NULL; + if (!check_extensions(sf,"str")) + return NULL; + + start_offset = 0x20; + loop_flag = 0; + channels = read_s32le(0x08,sf); /* always stereo? */ + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_HGC1; + vgmstream->sample_rate = read_s32le(0x10,sf); + vgmstream->num_samples = ps_bytes_to_samples(read_u32le(0x0C,sf) * 0x10, 1); /* mono frames*/ + + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/idtech.c b/Frameworks/vgmstream/vgmstream/src/meta/idtech.c index bae933ff0..191515ae5 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/idtech.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/idtech.c @@ -303,90 +303,87 @@ VGMSTREAM* init_vgmstream_bsnf(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; off_t start_offset, offset, extra_offset; size_t stream_size; - int loop_flag, channels, codec, sample_rate; //, block_size = 0, bps = 0; + int target_subsong = sf->stream_index, num_languages, + loop_flag, channels, codec, sample_rate; //, block_size = 0, bps = 0; int32_t num_samples, loop_start = 0; + char language[0x10]; STREAMFILE* sb = NULL; - const char* suffix = NULL; - const char* extension = NULL; /* checks */ - if (!is_id32be(0x00,sf, "bsnf")) /* null-terminated string */ - goto fail; - if (read_u32be(0x05, sf) != 0x00000100) /* version */ + if (!is_id32be(0x00, sf, "bsnf")) goto fail; if (!check_extensions(sf, "bsnd")) goto fail; - offset = 0x18; + num_languages = read_u32be(0x04, sf); + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > num_languages || num_languages < 1) + goto fail; - stream_size = read_u32be(offset + 0x00,sf); - offset = read_u32be(offset + 0x04,sf); /* absolute but typically right after this */ + offset = 0x08 + (target_subsong - 1) * 0x18; + + read_string(language, 0x10, offset + 0x00, sf); + stream_size = read_u32be(offset + 0x10, sf); + offset = read_u32be(offset + 0x14, sf); /* absolute but typically right after this */ /* 0x00: crc? */ /* 0x04: CBR samples or 0 if VBR */ - num_samples = read_s32be(offset + 0x08,sf); - loop_start = read_s32be(offset + 0x0c,sf); + num_samples = read_s32be(offset + 0x08, sf); + loop_start = read_s32be(offset + 0x0c, sf); /* 0x10: stream size? */ - codec = read_u16le(offset + 0x14,sf); + codec = read_u16le(offset + 0x14, sf); channels = read_u16le(offset + 0x16, sf); sample_rate = read_u32le(offset + 0x18, sf); //block_size = read_u16le(offset + 0x20, sf); //bps = read_u16le(offset + 0x22, sf); extra_offset = offset + 0x24; - extension = "ogg"; /* same for all codecs */ - switch(codec) { - case 0x0055: /* msf */ - /* 0x00: table entries */ - /* 0x04: seek table, format: frame size (16b) + frame samples (16b) */ - suffix = "_msf.bsnd"; - break; - case 0x0166: /* xma */ - /* 0x00: extra size */ - /* 0x02: xma config and block table */ - suffix = "_xma.bsnd"; - break; - - case 0x674F: /* vorbis */ - /* 0x00: extra size */ - /* 0x02: num samples */ - suffix = "_vorbis.bsnd"; - goto fail; //untested - //break; - - case 0x42D2: /* at9 */ - /* 0x00: extra size */ - /* 0x02: encoder delay */ - /* 0x04: channel config */ - /* 0x08: ATRAC9 GUID */ - /* 0x1c: ATRAC9 config */ - suffix = "_at9.bsnd"; - break; - - default: - goto fail; - } + /* extra data per codec */ + /* 0x0055 - msf */ + /* 0x00: table entries */ + /* 0x04: seek table, format: frame size (16b) + frame samples (16b) */ + /* 0x0166 - xma */ + /* 0x00: extra size */ + /* 0x02: xma config and block table */ + /* 0x674F - vorbis */ + /* 0x00: extra size */ + /* 0x02: num samples */ + /* 0x42D2 - at9 */ + /* 0x00: extra size */ + /* 0x02: encoder delay */ + /* 0x04: channel config */ + /* 0x08: ATRAC9 GUID */ + /* 0x1c: ATRAC9 config */ { - int suffix_len = strlen(suffix); - int filename_len; char filename[PATH_LIMIT]; + get_streamfile_basename(sf, filename, sizeof(filename)); - get_streamfile_filename(sf, filename, sizeof(filename)); - filename_len = strlen(filename); - - if (filename_len < suffix_len) - goto fail; - filename[filename_len - suffix_len + 0] = '.'; - filename[filename_len - suffix_len + 1] = '\0'; - strcat(filename, extension); + if (language[0] != '\0') { + strcat(filename, "_"); + strcat(filename, language); + } sb = open_streamfile_by_filename(sf, filename); - if (!sb) goto fail; + if (!sb) { + if (language[0] != '\0') { + // fill missing languages with blanks + vgmstream = init_vgmstream_silence(channels, sample_rate, num_samples); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_BSNF; + vgmstream->num_streams = num_languages; + snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%s (missing)", language); + + return vgmstream; + } + + goto fail; + } } if (stream_size != get_streamfile_size(sb)) @@ -395,7 +392,6 @@ VGMSTREAM* init_vgmstream_bsnf(STREAMFILE* sf) { loop_flag = (loop_start > 0); start_offset = 0x00; - /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; @@ -405,12 +401,14 @@ VGMSTREAM* init_vgmstream_bsnf(STREAMFILE* sf) { vgmstream->num_samples = num_samples; vgmstream->loop_start_sample = loop_start; vgmstream->loop_end_sample = num_samples; + vgmstream->num_streams = num_languages; + strncpy(vgmstream->stream_name, language, STREAM_NAME_SIZE); - switch(codec) { + switch (codec) { #ifdef VGM_USE_MPEG case 0x0055: { - mpeg_custom_config cfg = {0}; + mpeg_custom_config cfg = { 0 }; cfg.skip_samples = 1152; /* seems ok */ @@ -427,14 +425,14 @@ VGMSTREAM* init_vgmstream_bsnf(STREAMFILE* sf) { #ifdef VGM_USE_FFMPEG case 0x0166: { - int block_size = 0x800; + int block_size = 0x800; - vgmstream->codec_data = init_ffmpeg_xma2_raw(sf, start_offset, stream_size, num_samples, channels, sample_rate, block_size, 0); + vgmstream->codec_data = init_ffmpeg_xma2_raw(sb, start_offset, stream_size, num_samples, channels, sample_rate, block_size, 0); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; - xma_fix_raw_samples(vgmstream, sb, start_offset, stream_size, 0x00, 1,1); + xma_fix_raw_samples(vgmstream, sb, start_offset, stream_size, 0x00, 1, 1); break; } #endif @@ -451,11 +449,11 @@ VGMSTREAM* init_vgmstream_bsnf(STREAMFILE* sf) { #ifdef VGM_USE_ATRAC9 case 0x42D2: { - atrac9_config cfg = {0}; + atrac9_config cfg = { 0 }; cfg.channels = vgmstream->channels; - cfg.encoder_delay = read_u16le(extra_offset + 0x02,sf); - cfg.config_data = read_u32be(extra_offset + 0x1c,sf); + cfg.encoder_delay = read_u16le(extra_offset + 0x02, sf); + cfg.config_data = read_u32be(extra_offset + 0x1c, sf); vgmstream->codec_data = init_atrac9(&cfg); if (!vgmstream->codec_data) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ivaud.c b/Frameworks/vgmstream/vgmstream/src/meta/ivaud.c index 43113eac3..13ed4888d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ivaud.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ivaud.c @@ -1,6 +1,7 @@ #include "meta.h" #include "../layout/layout.h" #include "../coding/coding.h" +#include "../util/endianness.h" typedef struct { int is_music; @@ -31,13 +32,13 @@ VGMSTREAM* init_vgmstream_ivaud(STREAMFILE* sf) { int loop_flag; /* checks */ - /* (hashed filenames are likely extensionless and .ivaud is added by tools) */ + /* (hashed filenames are likely extensionless, .ivaud is added by tools) */ if (!check_extensions(sf, "ivaud,")) - goto fail; + return NULL; /* check header */ if (!parse_ivaud_header(sf, &ivaud)) - goto fail; + return NULL; loop_flag = 0; @@ -121,9 +122,9 @@ fail: /* Parse Rockstar's .ivaud header (much info from SparkIV). */ static int parse_ivaud_header(STREAMFILE* sf, ivaud_header* ivaud) { int target_subsong = sf->stream_index; - uint64_t (*read_u64)(off_t,STREAMFILE*); - uint32_t (*read_u32)(off_t,STREAMFILE*); - uint16_t (*read_u16)(off_t,STREAMFILE*); + read_u64_t read_u64; + read_u32_t read_u32; + read_u16_t read_u16; ivaud->big_endian = read_u32be(0x00, sf) == 0; /* table offset at 0x04 > BE (64b) */ @@ -131,6 +132,10 @@ static int parse_ivaud_header(STREAMFILE* sf, ivaud_header* ivaud) { read_u32 = ivaud->big_endian ? read_u32be : read_u32le; read_u16 = ivaud->big_endian ? read_u16be : read_u16le; + uint64_t table_offset = read_u64(0x00,sf); + if (table_offset > 0x10000) /* arbitrary max, typically 0x1c~0x1000 */ + return 0; + /* use bank's stream count to detect */ ivaud->is_music = (read_u32(0x10,sf) == 0); @@ -138,7 +143,7 @@ static int parse_ivaud_header(STREAMFILE* sf, ivaud_header* ivaud) { off_t block_table_offset, channel_table_offset, channel_info_offset; /* music header */ - block_table_offset = read_u64(0x00,sf); + block_table_offset = table_offset; ivaud->block_count = read_u32(0x08,sf); ivaud->block_size = read_u32(0x0c,sf); /* uses padded blocks */ /* 0x10(4): stream count */ @@ -185,7 +190,7 @@ static int parse_ivaud_header(STREAMFILE* sf, ivaud_header* ivaud) { off_t stream_table_offset, stream_info_offset, stream_entry_offset, offset; /* bank header */ - stream_table_offset = read_u64(0x00,sf); + stream_table_offset = table_offset; /* 0x08(8): header size? start offset? */ ivaud->total_subsongs = read_u32(0x10,sf); /* 0x14(4): unknown */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h index 69b455cfa..f11b389c8 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -257,15 +257,11 @@ VGMSTREAM * init_vgmstream_sdt(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_aix(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_ngc_tydsp(STREAMFILE * streamFile); - VGMSTREAM* init_vgmstream_wvs_xbox(STREAMFILE* sf); VGMSTREAM* init_vgmstream_wvs_ngc(STREAMFILE* sf); -VGMSTREAM * init_vgmstream_dc_str(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_dc_str_v2(STREAMFILE *streamFile); - -VGMSTREAM * init_vgmstream_xbox_matx(STREAMFILE *streamFile); +VGMSTREAM* init_vgmstream_str_sega(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_str_sega_custom(STREAMFILE* sf); VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile); @@ -300,7 +296,7 @@ VGMSTREAM * init_vgmstream_ps2_mihb(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ngc_pdt_split(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ngc_pdt(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_wii_mus(STREAMFILE * streamFile); +VGMSTREAM* init_vgmstream_mus_krome(STREAMFILE* sf); VGMSTREAM * init_vgmstream_rsd(STREAMFILE * streamFile); @@ -332,7 +328,7 @@ VGMSTREAM * init_vgmstream_ish_isd(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ydsp(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE * streamFile); +VGMSTREAM* init_vgmstream_gsnd(STREAMFILE* sf); VGMSTREAM * init_vgmstream_ngc_ssm(STREAMFILE * streamFile); @@ -412,7 +408,7 @@ VGMSTREAM * init_vgmstream_sab(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_exakt_sc(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_wii_bns(STREAMFILE* streamFile); +VGMSTREAM* init_vgmstream_bns(STREAMFILE* sf); VGMSTREAM * init_vgmstream_pona_3do(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_pona_psx(STREAMFILE* streamFile); @@ -433,7 +429,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_konami(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_bnsf(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_ps2_wb(STREAMFILE* streamFile); +VGMSTREAM* init_vgmstream_wb(STREAMFILE* sf); VGMSTREAM* init_vgmstream_raw_s14_sss(STREAMFILE* sf); @@ -455,8 +451,6 @@ VGMSTREAM * init_vgmstream_ea_swvr(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_ps2_b1s(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_ps2_wad(STREAMFILE* streamFile); - VGMSTREAM * init_vgmstream_ps2_adm(STREAMFILE* streamFile); VGMSTREAM* init_vgmstream_lpcm_shade(STREAMFILE* sf); @@ -578,7 +572,7 @@ VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE* streamFile); VGMSTREAM* init_vgmstream_pasx(STREAMFILE* sf); -VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_sndx(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ogl(STREAMFILE *streamFile); @@ -959,6 +953,7 @@ VGMSTREAM* init_vgmstream_s3v(STREAMFILE* sf); VGMSTREAM* init_vgmstream_esf(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_adm2(STREAMFILE* sf); VGMSTREAM* init_vgmstream_adm3(STREAMFILE* sf); VGMSTREAM* init_vgmstream_tt_ad(STREAMFILE* sf); @@ -982,4 +977,9 @@ VGMSTREAM* init_vgmstream_rws_809(STREAMFILE* sf); VGMSTREAM* init_vgmstream_pwb(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_squeakstream(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_squeaksample(STREAMFILE* sf); + +VGMSTREAM* init_vgmstream_snds(STREAMFILE* sf); + #endif /*_META_H*/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mus_krome.c b/Frameworks/vgmstream/vgmstream/src/meta/mus_krome.c new file mode 100644 index 000000000..c59d84b02 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/mus_krome.c @@ -0,0 +1,56 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../coding/coding.h" + + +/* .mus - from Krome games [Ty: The Tasmanian Tiger 2 (GC), Star Wars: The Force Unleashed (Wii)] */ +VGMSTREAM* init_vgmstream_mus_krome(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint32_t start_offset, data_size; + int channels, loop_flag, interleave; + int32_t num_samples; + + + /* checks */ + num_samples = read_s32be(0x00,sf); + interleave = read_s32be(0x04,sf); + start_offset = read_u32be(0x08,sf); + data_size = read_u32be(0x0c,sf); + + if (interleave != 0x8000) + return NULL; + if (start_offset != 0x80) + return NULL; + if (data_size + start_offset != get_streamfile_size(sf)) + return NULL; + /* could test gain/initial ps at 0x10 + 0x20 too */ + + if (!check_extensions(sf,"mus")) + return NULL; + + + channels = 2; + loop_flag = 0; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_MUS_KROME; + vgmstream->num_samples = num_samples; + vgmstream->sample_rate = read_u16be(0x6c,sf); + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; /* no last block size unlike similar DSPs */ + + dsp_read_coefs_be(vgmstream, sf, 0x10, 0x2e); + dsp_read_hist_be(vgmstream, sf, 0x10 + 0x24, 0x2e); + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ngc_tydsp.c b/Frameworks/vgmstream/vgmstream/src/meta/ngc_tydsp.c deleted file mode 100644 index 37f3a6037..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/ngc_tydsp.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "meta.h" -#include "../util.h" - -/* TYDSP (Ty - The Tasmanian Tiger) */ -VGMSTREAM * init_vgmstream_ngc_tydsp(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("tydsp",filename_extension(filename))) goto fail; - - loop_flag = 1; - channel_count = 2; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = read_32bitBE(0x08,streamFile); - vgmstream->channels = channel_count; - vgmstream->sample_rate = (uint16_t)(read_16bitBE(0x6C,streamFile)); - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->num_samples = read_32bitBE(0x00,streamFile); - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = read_32bitBE(0x00,streamFile); - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitBE(0x04,streamFile); - vgmstream->meta_type = meta_NGC_TYDSP; - - if (vgmstream->coding_type == coding_NGC_DSP) { - int i; - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x10+i*2,streamFile); - } - if (vgmstream->channels) { - for (i=0;i<16;i++) { - vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x3E +i*2,streamFile); - } - } - } - - /* 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; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c b/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c index d9e242895..31a7ae6c2 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c @@ -302,6 +302,34 @@ static int _init_vgmstream_ogg_vorbis_tests(STREAMFILE* sf, ogg_vorbis_io_config return 1; } + /* .fish: Wonder Boy: The Dragon's Trap (PC) */ + if (read_u32be(0x00,sf) == 0x4E7C0F0E) { + + /* init big-ish table on startup, based on original unrolled code (sub_7FF7670FD990) */ + cfg->key_len = 0x400; + if (sizeof(cfg->key) < cfg->key_len) + goto fail; + + for (int i = 0; i < 0x400 / 4; i++) { + uint32_t key = i; + for (int round = 0; round < 8; round++) { + uint32_t tmp1 = (key >> 1); + uint32_t tmp2 = -(key & 1) & 0xEDB88324; + key = tmp1 ^ tmp2; + } + if (key == 0) + key = 0xEDB88324; + + put_u32le(cfg->key + (i ^ 0x2A) * 4, key); + } + cfg->is_encrypted = 1; + + if (!check_extensions(sf,"fish")) + goto fail; + + return 1; + } + /***************************************/ /* harder to check (could be improved) */ @@ -614,6 +642,7 @@ static VGMSTREAM* _init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, const char* comment = NULL; while (ogg_vorbis_get_comment(data, &comment)) { + ;VGM_LOG("OGG: user_comment=%s\n", comment); if (strstr(comment,"loop_start=") == comment || /* Phantasy Star Online: Blue Burst (PC) (no loop_end pair) */ strstr(comment,"LOOP_START=") == comment || /* Phantasy Star Online: Blue Burst (PC), common */ @@ -702,18 +731,26 @@ static VGMSTREAM* _init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, force_seek = 1; } + else if (strstr(comment,"COMMENT=*loopsample,") == comment) { /* Tsuki ni Yorisou Otome no Sahou (PC) */ + int unk0; // always 0 (delay?) + int unk1; // always -1 (loop flag? but non-looped files have no comment) + int m = sscanf(comment,"COMMENT=*loopsample,%d,%d,%d,%d", &unk0, &loop_start, &loop_end, &unk1); + if (m == 4) { + loop_flag = 1; + loop_end_found = 1; + } + } + /* Hatsune Miku Project DIVA games, though only 'Arcade Future Tone' has >4ch files * ENCODER tag is common but ogg_vorbis_encode looks unique enough * (arcade ends with "2010-11-26" while consoles have "2011-02-07" */ - if (strstr(comment, "ENCODER=ogg_vorbis_encode/") == comment) { + else if (strstr(comment, "ENCODER=ogg_vorbis_encode/") == comment) { disable_reordering = 1; } - if (strstr(comment, "TITLE=") == comment) { + else if (strstr(comment, "TITLE=") == comment) { strncpy(name, comment + 6, sizeof(name) - 1); } - - ;VGM_LOG("OGG: user_comment=%s\n", comment); } } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_bg00.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_bg00.c deleted file mode 100644 index 4ae1362da..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_bg00.c +++ /dev/null @@ -1,65 +0,0 @@ -#include "meta.h" -#include "../util.h" - -/* BG0 (from Ibara, Mushihimesama) -Note: Seems the Loop Infos are stored external... */ -VGMSTREAM * init_vgmstream_bg00(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - int loop_flag = 0; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("bg00",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x42473030) /* "BG00" */ - goto fail; - - loop_flag = (read_32bitLE(0x08,streamFile)!=0); - channel_count = 2; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x800; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitBE(0x80,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = (read_32bitBE(0x4C,streamFile)*2)*28/16/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = (read_32bitBE(0x4C,streamFile)*2)*28/16/channel_count; - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile); - vgmstream->meta_type = meta_BG00; - - /* 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; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_filp.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_filp.c deleted file mode 100644 index 967cf2cc7..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_filp.c +++ /dev/null @@ -1,67 +0,0 @@ -#include "meta.h" -#include "../layout/layout.h" -#include "../util.h" - -/* FILp (Resident Evil - Dead Aim) */ -VGMSTREAM * init_vgmstream_filp(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - int loop_flag = 0; - int channel_count; - int i; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("filp",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x46494C70) /* "FILp" */ - goto fail; - if (read_32bitBE(0x100,streamFile) != 0x56414770) /* "VAGp" */ - goto fail; - if (read_32bitBE(0x130,streamFile) != 0x56414770) /* "VAGp" */ - goto fail; - if (get_streamfile_size(streamFile) != read_32bitLE(0xC,streamFile)) - goto fail; - - loop_flag = (read_32bitLE(0x34,streamFile) == 0); - channel_count = read_32bitLE(0x4,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x0; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x110,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->layout_type = layout_blocked_filp; - vgmstream->meta_type = meta_FILP; - - /* open the file for reading */ - { - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - } - } - - block_update_filp(start_offset,vgmstream); - vgmstream->num_samples = read_32bitLE(0x10C,streamFile)/16*28; - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = vgmstream->num_samples; - } - - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_hgc1.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_hgc1.c deleted file mode 100644 index 7588febe8..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_hgc1.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "meta.h" -#include "../util.h" - -/* hgC1 (from Knights of the Temple 2) */ -VGMSTREAM * init_vgmstream_hgc1(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - int loop_flag = 0; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("hgc1",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x68674331) /* "hgC1" */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x08,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x40; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = (read_32bitLE(0x0C,streamFile)*32)/channel_count/16*28; - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = (read_32bitLE(0x0C,streamFile)*32)/channel_count/16*28; - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x10; - vgmstream->meta_type = meta_HGC1; - - /* 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; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_sl3.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_sl3.c deleted file mode 100644 index 69fc81d38..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_sl3.c +++ /dev/null @@ -1,45 +0,0 @@ -#include "meta.h" -#include "../coding/coding.h" - -/* SL3 - Atari Melbourne House games [ Test Drive Unlimited (PS2), Transformers (PS2)] */ -VGMSTREAM * init_vgmstream_sl3(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset; - int loop_flag = 0, channel_count; - - /* checks */ - /* .ms: actual extension, sl3: header id */ - if (!check_extensions(streamFile, "ms,sl3")) - goto fail; - if (read_32bitBE(0x00,streamFile) != 0x534C3300) /* "SL3\0" */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x14,streamFile); - start_offset = 0x8000; /* also at 0x24? */ - - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - vgmstream->sample_rate = read_32bitLE(0x18,streamFile); - vgmstream->num_samples = ps_bytes_to_samples(get_streamfile_size(streamFile)-start_offset,channel_count); - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = read_32bitLE(0x1C,streamFile); - } - - vgmstream->coding_type = coding_PSX; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0x20,streamFile); - vgmstream->meta_type = meta_SL3; - - 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_wad.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_wad.c index 9242f4cb7..e69de29bb 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_wad.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_wad.c @@ -1,71 +0,0 @@ -#include "meta.h" -#include "../util.h" - -/* WAD (from The golden Compass) */ -VGMSTREAM * init_vgmstream_ps2_wad(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - int loop_flag = 0; - int channel_count; - off_t start_offset; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("wad",filename_extension(filename))) goto fail; - - /* check header */ - if ((read_32bitLE(0x00,streamFile)+0x40) != get_streamfile_size(streamFile)) - goto fail; - - loop_flag = 0; - channel_count = (uint16_t) read_16bitLE(0x4,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x40; - vgmstream->channels = channel_count; - vgmstream->sample_rate = (uint16_t) read_16bitLE(0x6,streamFile);; - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = read_32bitLE(0x0,streamFile)/channel_count/16*28; - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = read_32bitLE(0x0,streamFile)/channel_count/16*28; - } - - if (channel_count == 1) - { - vgmstream->layout_type = layout_none; - } - else - { - goto fail; - } - - vgmstream->meta_type = meta_PS2_WAD; - - /* 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; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_wb.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_wb.c deleted file mode 100644 index 49efbf6b7..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_wb.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "meta.h" -#include "../util.h" - -/* WB (from Shooting Love. ~TRIZEAL~) */ -VGMSTREAM * init_vgmstream_ps2_wb(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("wb",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0,streamFile) != 0x00000000) - goto fail; - - loop_flag = read_32bitLE(0x4,streamFile); - channel_count = 2; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x10; - vgmstream->channels = channel_count; - vgmstream->sample_rate = 48000; - vgmstream->coding_type = coding_PCM16LE; - vgmstream->num_samples = read_32bitLE(0xC,streamFile)/4; - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(0x4,streamFile); - vgmstream->loop_end_sample = read_32bitLE(0x8,streamFile); - } - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 2; - vgmstream->meta_type = meta_PS2_WB; - - /* 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; - - } - } - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/riff.c b/Frameworks/vgmstream/vgmstream/src/meta/riff.c index 2e5a73fde..1a91faea5 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/riff.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/riff.c @@ -146,6 +146,9 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk case 0x0001: /* PCM */ switch (fmt->bps) { + case 32: + fmt->coding_type = coding_PCM32LE; + break; case 24: /* Omori (PC) */ fmt->coding_type = coding_PCM24LE; break; @@ -177,6 +180,14 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk goto fail; } break; + case 0x003: /* floating point PCM */ + if (fmt->bps == 32) { + fmt->coding_type = coding_PCMFLOAT; + } else { + goto fail; + } + fmt->interleave = fmt->block_size / fmt->channels; + break; case 0x0011: /* MS-IMA ADPCM [Layton Brothers: Mystery Room (iOS/Android)] */ if (fmt->bps != 4) goto fail; @@ -701,9 +712,11 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) { /* samples, codec init (after setting coding to ensure proper close on failure) */ switch (fmt.coding_type) { + case coding_PCM32LE: case coding_PCM24LE: case coding_PCM16LE: case coding_PCM8_U: + case coding_PCMFLOAT: vgmstream->num_samples = pcm_bytes_to_samples(data_size, fmt.channels, fmt.bps); break; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sdrh.c b/Frameworks/vgmstream/vgmstream/src/meta/sdrh.c index 88d43035a..72b04a6a9 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sdrh.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sdrh.c @@ -216,6 +216,7 @@ VGMSTREAM* init_vgmstream_sdrh_old(STREAMFILE* sf) { * 0x30: file name in a custom 40-char (RADIX style) encoding * others: ? (change in old/new) */ + /* there is also an older version in Shadow Hearts 2, more basic (no section table) and may contain sequences */ /* parse section */ { diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c b/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c index c16c53a2f..a0ff71358 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c @@ -3,16 +3,15 @@ #include "../util/chunks.h" -/* SGXD - Sony/SCEI's format (SGB+SGH / SGD / SGX) */ +/* SGXD - Sony/SCEI's SGX lib (cousin of RXWS) */ VGMSTREAM* init_vgmstream_sgxd(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; STREAMFILE* sf_head = NULL; STREAMFILE* sf_body = NULL; off_t start_offset, data_offset, chunk_offset, name_offset = 0; size_t stream_size; - uint32_t base1_offset, base2_offset, base3_offset; - - int is_sgx, is_sgd = 0; + uint32_t /*base1_offset,*/ base2_offset, base3_offset; + int is_sgd = 0; int loop_flag, channels, codec, sample_rate; int32_t num_samples, loop_start_sample, loop_end_sample; int total_subsongs, target_subsong = sf->stream_index; @@ -28,35 +27,31 @@ VGMSTREAM* init_vgmstream_sgxd(STREAMFILE* sf) { } if (!is_id32be(0x00,sf_head, "SGXD")) - goto fail; + return NULL; /* checks */ - /* .sgx: header+data (Genji) - * .sgd: header+data (common) + /* .sgd: header+data (common) * .sgh+sgd: header+data (streams) */ - if (!check_extensions(sf,"sgx,sgd,sgb")) - goto fail; + if (!check_extensions(sf,"sgd,sgb")) + return NULL; /* SGXD base (size 0x10), always LE even on PS3 */ - /* 0x04: SGX = full header size - SGD/SGH = bank name offset (part of NAME table, usually same as filename) */ - /* 0x08: SGX = first chunk offset? (0x10) - SGD/SGH = full header size */ - /* 0x0c: SGX/SGH = full data size with padding / - SGD = full data size ^ (1<<31) with padding */ - base1_offset = read_u32le(0x04, sf_head); + /* 0x04: SGD/SGH = bank name offset (part of NAME table, usually same as filename) */ + /* 0x08: SGD/SGH = full header size */ + /* 0x0c: SGH = full data size with padding + * SGD = full data size ^ (1<<31) with padding */ + //base1_offset = read_u32le(0x04, sf_head); base2_offset = read_u32le(0x08, sf_head); base3_offset = read_u32le(0x0c, sf_head); - is_sgx = base2_offset == 0x10; /* fixed size */ is_sgd = base3_offset & (1 << 31); /* flag */ /* Ogg SGXD don't have flag (probably due to codec hijack, or should be split), allow since it's not so obvious */ - if (!(is_sgx || is_sgd) && get_streamfile_size(sf_head) != base2_offset) /* sgh but wrong header size must be sgd */ + if (!(is_sgd) && get_streamfile_size(sf_head) != base2_offset) /* sgh but wrong header size must be sgd */ is_sgd = 1; /* for plugins that start with .sgh (and don't check extensions) */ - if (!(is_sgx || is_sgd) && sf == sf_head) { + if (!(is_sgd) && sf == sf_head) { sf_body = open_streamfile_by_ext(sf, "sgb"); if (!sf_body) goto fail; } @@ -65,9 +60,7 @@ VGMSTREAM* init_vgmstream_sgxd(STREAMFILE* sf) { } - if (is_sgx) { - data_offset = base1_offset; - } else if (is_sgd) { + if (is_sgd) { data_offset = base2_offset; } else { data_offset = 0x00; @@ -76,7 +69,7 @@ VGMSTREAM* init_vgmstream_sgxd(STREAMFILE* sf) { /* Format per chunk: * - 0x00: id - * - 0x04: SGX: unknown; SGD/SGH: chunk length + * - 0x04: chunk length * - 0x08: null * - 0x0c: entries */ @@ -103,14 +96,8 @@ VGMSTREAM* init_vgmstream_sgxd(STREAMFILE* sf) { * - BUSS: bus config? */ /* WAVE chunk (size 0x10 + files * 0x38 + optional padding) */ - if (is_sgx) { /* position after chunk+size */ - if (!is_id32be(0x10,sf_head, "WAVE")) - goto fail; - chunk_offset = 0x18; - } else { - if (!find_chunk_le(sf_head, get_id32be("WAVE"),0x10,0, &chunk_offset, NULL)) - goto fail; - } + if (!find_chunk_le(sf_head, get_id32be("WAVE"),0x10,0, &chunk_offset, NULL)) + goto fail; /* check multi-streams (usually only SE containers; Puppeteer) */ total_subsongs = read_s32le(chunk_offset+0x04,sf_head); @@ -123,8 +110,7 @@ VGMSTREAM* init_vgmstream_sgxd(STREAMFILE* sf) { chunk_offset += 0x08 + 0x38 * (target_subsong-1); /* position in target header*/ /* 0x00: ? (00/01/02) */ - if (!is_sgx) /* meaning unknown in .sgx; offset 0 = not a stream (a RGND sample) */ - name_offset = read_u32le(chunk_offset+0x04,sf_head); + name_offset = read_u32le(chunk_offset+0x04,sf_head); codec = read_u8(chunk_offset+0x08,sf_head); channels = read_u8(chunk_offset+0x09,sf_head); /* 0x0a: null */ @@ -141,13 +127,9 @@ VGMSTREAM* init_vgmstream_sgxd(STREAMFILE* sf) { loop_end_sample = read_s32le(chunk_offset+0x28,sf_head); stream_size = read_u32le(chunk_offset+0x2c,sf_head); /* stream size (without padding) / interleave (for type3) */ - if (is_sgx) { - stream_offset = 0x0; - } else{ - stream_offset = read_u32le(chunk_offset+0x30,sf_head); - } - /* 0x34: SGX = unknown - * SGD/SGH = stream size (with padding) / interleave */ + stream_offset = read_u32le(chunk_offset+0x30,sf_head); + + /* 0x34: SGD/SGH = stream size (with padding) / interleave */ loop_flag = loop_start_sample != -1 && loop_end_sample != -1; start_offset = data_offset + stream_offset; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sl3.c b/Frameworks/vgmstream/vgmstream/src/meta/sl3.c new file mode 100644 index 000000000..a712c0dfd --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/sl3.c @@ -0,0 +1,41 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* SL3 - Sirens Sound Library (Winky Soft / Atari Melbourne House) games [Test Drive Unlimited (PS2), Transformers 2003/2004 (PS2)] */ +VGMSTREAM* init_vgmstream_sl3(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + off_t start_offset; + int loop_flag = 0, channels; + + /* checks */ + if (!is_id32be(0x00,sf, "SL3\0")) + goto fail; + /* .ms: actual extension */ + if (!check_extensions(sf, "ms")) + goto fail; + + loop_flag = 0; + channels = read_32bitLE(0x14,sf); + start_offset = 0x8000; /* also at 0x24? */ + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_SL3; + vgmstream->sample_rate = read_32bitLE(0x18,sf); + vgmstream->num_samples = ps_bytes_to_samples(get_streamfile_size(sf)-start_offset,channels); + + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = read_32bitLE(0x20,sf); + + if (!vgmstream_open_stream(vgmstream,sf,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/snds.c b/Frameworks/vgmstream/vgmstream/src/meta/snds.c new file mode 100644 index 000000000..bb5ec7c22 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/snds.c @@ -0,0 +1,112 @@ +#include "meta.h" +#include "../coding/coding.h" +#include "../util/chunks.h" + + +/* SSDD - Sony/SCE's SNDS lib format (cousin of SGXD/SNDX) */ +VGMSTREAM* init_vgmstream_snds(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint32_t stream_offset, stream_size; + int loop_flag, channels, codec, sample_rate; + int32_t num_samples, loop_start, loop_end, encoder_delay; + uint32_t at9_config = 0; + int total_subsongs, target_subsong = sf->stream_index; + + + /* checks */ + if (!is_id32be(0x00, sf, "SSDD")) + return NULL; + + if (read_u32le(0x04, sf) != get_streamfile_size(sf)) + return NULL; + /* 0x10: file name */ + + /* (extensionless): no apparent extension in debug strings, though comparing other SCE libs possibly ".ssd" */ + if (!check_extensions(sf,"")) + return NULL; + + /* from debug info seems to have free chunks but known files always use the same and 1 subsong */ + off_t base_offset = 0x60, wavs_offset = 0; + if (!find_chunk_le(sf, get_id32be("WAVS"),base_offset,0, &wavs_offset,NULL)) + return NULL; + + if (read_u16le(wavs_offset + 0x00, sf) != 0x2c) /* entry size? */ + return NULL; + + total_subsongs = read_s16le(wavs_offset + 0x02, sf); + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) return NULL; + if (total_subsongs != 1) return NULL; /* not seen */ + + /* read stream header */ + { + uint32_t head_offset = wavs_offset + 0x04 + 0x2c * (target_subsong - 1); + /* 0x00: null/flags? */ + /* 0x04: null/offset? */ + /* 0x0c: null/offset? */ + codec = read_u8(head_offset + 0x0c, sf); + channels = read_u16le(head_offset + 0x0d, sf); + /* 0x0e: null? */ + sample_rate = read_u32le(head_offset + 0x10, sf); + at9_config = read_u32le(head_offset + 0x14, sf); /* !!! (only known use of this lib is Android/iOS) */ + num_samples = read_s32le(head_offset + 0x18, sf); + loop_start = read_s32le(head_offset + 0x1c, sf); + loop_end = read_s32le(head_offset + 0x20, sf); + encoder_delay = read_s32le(head_offset + 0x24, sf); + stream_size = read_u32le(head_offset + 0x28, sf); + + loop_flag = loop_end > 0; + } + + /* CUES chunk: cues (various fields, also names) */ + /* CUNS chunk: cue names (flags + hash + offset, then names) */ + + off_t wavd_offset = 0; + if (!find_chunk_le(sf, get_id32be("WAVD"),wavs_offset - 0x08,0, &wavd_offset,NULL)) + return NULL; + stream_offset = wavd_offset + 0x08; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_SNDS; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = num_samples; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; + + vgmstream->num_streams = total_subsongs; + vgmstream->stream_size = stream_size; + + switch (codec) { +#ifdef VGM_USE_ATRAC9 + case 0x41: { + atrac9_config cfg = {0}; + + cfg.channels = channels; + cfg.config_data = at9_config; + cfg.encoder_delay = encoder_delay; + + vgmstream->codec_data = init_atrac9(&cfg); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_ATRAC9; + vgmstream->layout_type = layout_none; + break; + } +#endif + default: + VGM_LOG("SNDS: unknown codec 0x%x\n", codec); + goto fail; + } + + /* open the file for reading */ + if (!vgmstream_open_stream(vgmstream, sf, stream_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sxd.c b/Frameworks/vgmstream/vgmstream/src/meta/sndx.c similarity index 97% rename from Frameworks/vgmstream/vgmstream/src/meta/sxd.c rename to Frameworks/vgmstream/vgmstream/src/meta/sndx.c index 4cbd97fc9..798990cd6 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sxd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sndx.c @@ -3,8 +3,8 @@ #include "../util/chunks.h" -/* SXD - Sony/SCE's SNDX lib format (cousin of SGXD) [Gravity Rush, Freedom Wars, Soul Sacrifice PSV] */ -VGMSTREAM* init_vgmstream_sxd(STREAMFILE* sf) { +/* SXDF/SXDS - Sony/SCE's SNDX lib format (cousin of SGXD) [Gravity Rush, Freedom Wars, Soul Sacrifice PSV] */ +VGMSTREAM* init_vgmstream_sndx(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; STREAMFILE* sf_sxd1 = NULL, *sf_sxd2 = NULL, *sf_data = NULL, *sf_h = NULL, *sf_b = NULL; off_t start_offset, chunk_offset, first_offset = 0x60, name_offset = 0; @@ -180,7 +180,7 @@ VGMSTREAM* init_vgmstream_sxd(STREAMFILE* sf) { vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; - vgmstream->meta_type = meta_SXD; + vgmstream->meta_type = meta_SNDX; vgmstream->sample_rate = sample_rate; vgmstream->num_samples = num_samples; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/spsd.c b/Frameworks/vgmstream/vgmstream/src/meta/spsd.c index 955d83530..14d78c079 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/spsd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/spsd.c @@ -11,27 +11,29 @@ VGMSTREAM* init_vgmstream_spsd(STREAMFILE *sf) { /* checks */ if (!is_id32be(0x00,sf, "SPSD")) - goto fail; + return NULL; /* .str: actual extension, rare [Shenmue (DC)] * .spsd: header id (maybe real ext is .PSD, similar to "SMLT" > .MLT) */ if (!check_extensions(sf, "str,spsd")) - goto fail; + return NULL; - if (read_32bitBE(0x04,sf) != 0x01010004 && /* standard version */ - read_32bitBE(0x04,sf) != 0x00010004) /* uncommon version [Crazy Taxi (Naomi)] */ - goto fail; + if (read_u32be(0x04,sf) != 0x01010004 && /* standard version */ + read_u32be(0x04,sf) != 0x00010004) /* uncommon version [Crazy Taxi (Naomi)] */ + return NULL; - codec = read_8bit(0x08,sf); - flags = read_8bit(0x09,sf); - index = read_16bitLE(0x0a,sf); - data_size = read_32bitLE(0x0c,sf); + codec = read_u8(0x08,sf); + flags = read_u8(0x09,sf); + index = read_u16le(0x0a,sf); + data_size = read_u32le(0x0c,sf); //if (data_size + start_offset != get_streamfile_size(streamFile)) // goto fail; /* some rips out there have incorrect padding */ + /* At 0x30(4*ch) is some config per channel but doesn't seem to affect ADPCM (found with PCM too) */ + //todo with 0x80 seems 0x2c is a loop_start_sample but must be adjusted to +1 block? (uncommon flag though) loop_flag = (flags & 0x80); - channels = ((flags & 0x01) || (flags & 0x02)) ? 2 : 1; /* 0x02 is rare but looks normal (Virtua Tennis 2) */ + channels = ((flags & 0x01) || (flags & 0x02)) ? 2 : 1; /* 0x02 is rare (Virtua Tennis 2) */ start_offset = 0x40; @@ -39,29 +41,29 @@ VGMSTREAM* init_vgmstream_spsd(STREAMFILE *sf) { vgmstream = allocate_vgmstream(channels,loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = (uint16_t)read_16bitLE(0x2A,sf); + vgmstream->sample_rate = read_u16le(0x2A,sf); vgmstream->meta_type = meta_SPSD; switch (codec) { case 0x00: /* [Virtua Tennis 2 (Naomi), Club Kart: European Session (Naomi)] */ vgmstream->coding_type = coding_PCM16LE; - vgmstream->num_samples = pcm_bytes_to_samples(data_size,channels,16); - vgmstream->loop_start_sample = read_32bitLE(0x2c,sf) + pcm_bytes_to_samples(0x2000*channels,channels,16); + vgmstream->num_samples = pcm16_bytes_to_samples(data_size, channels); + vgmstream->loop_start_sample = read_s32le(0x2c,sf) + pcm16_bytes_to_samples(0x2000,1); vgmstream->loop_end_sample = vgmstream->num_samples; break; case 0x01: /* [Virtua Tennis 2 (Naomi)] */ vgmstream->coding_type = coding_PCM8; - vgmstream->num_samples = pcm_bytes_to_samples(data_size,channels,8); - vgmstream->loop_start_sample = read_32bitLE(0x2c,sf) + pcm_bytes_to_samples(0x2000*channels,channels,8); + vgmstream->num_samples = pcm8_bytes_to_samples(data_size, channels); + vgmstream->loop_start_sample = read_s32le(0x2c,sf) + pcm8_bytes_to_samples(0x2000,1); vgmstream->loop_end_sample = vgmstream->num_samples; break; case 0x03: /* standard */ vgmstream->coding_type = coding_AICA_int; - vgmstream->num_samples = yamaha_bytes_to_samples(data_size,channels); - vgmstream->loop_start_sample = /*read_32bitLE(0x2c,streamFile) +*/ yamaha_bytes_to_samples(0x2000*channels,channels); + vgmstream->num_samples = yamaha_bytes_to_samples(data_size, channels); + vgmstream->loop_start_sample = /*read_s32le(0x2c,streamFile) +*/ yamaha_bytes_to_samples(0x2000,1); vgmstream->loop_end_sample = vgmstream->num_samples; break; @@ -92,9 +94,6 @@ VGMSTREAM* init_vgmstream_spsd(STREAMFILE *sf) { goto fail; } - /* todo seems to decode slightly incorrectly in after certain data (loop section start?) - * may depend on values in 0x20 or 0x2c [ex. Marvel vs Capcom 2 (Naomi)] - * at 0x30(4*ch) is some config per channel but doesn't seem to affect ADPCM (found with PCM too) */ { int i; for (i = 0; i < channels; i++) { diff --git a/Frameworks/vgmstream/vgmstream/src/meta/squeak.c b/Frameworks/vgmstream/vgmstream/src/meta/squeak.c new file mode 100644 index 000000000..710d416aa --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/squeak.c @@ -0,0 +1,446 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../coding/coding.h" +#include "../util/endianness.h" +#include "../util/layout_utils.h" + +#define SQUEAK_MAX_CHANNELS 6 /* seen 3 in some voices */ +typedef enum { PCM16LE, PCM16BE, PCM8, DSP, PSX, MSIMA, IMA, XMA2, VORBIS, SPEEX } squeak_type_t; + +typedef struct { + squeak_type_t type; + int version; + + int channels; + int codec; + int sample_rate; + uint32_t interleave; + + uint32_t extb_offset; + uint32_t name_offset; + + int32_t num_samples; + int32_t loop_start; + int32_t loop_end; + + uint32_t data_offset; + uint32_t coef_offset; + uint32_t coef_spacing; + + uint32_t data_offsets[SQUEAK_MAX_CHANNELS]; + uint32_t coef_offsets[SQUEAK_MAX_CHANNELS]; + uint32_t data_size; + + bool big_endian; + bool external_info; + bool external_data; + bool stream; +} squeak_header_t; + +static VGMSTREAM* init_vgmstream_squeak_common(STREAMFILE* sf, squeak_header_t* h); + + +/* SqueakStream - from Torus games (name/engine as identified in .hnk subdirs) */ +VGMSTREAM* init_vgmstream_squeakstream(STREAMFILE* sf) { + squeak_header_t h = {0}; + bool is_old = false; + + + /* checks */ + if (is_id32be(0x00,sf, "RAWI") || is_id32be(0x00,sf, "VORB") || is_id32be(0x00,sf, "SPEX")) { + h.big_endian = false; /* VORB/SPEX only use vorbis/speex but no apparent diffs */ + } + else if (is_id32be(0x00,sf, "IWAR")) { + h.big_endian = true; /* Wii/PS3/X360 */ + } + else { + /* no header id in early version so test codec in dumb endian */ + if ((read_u32le(0x00,sf) & 0x00FFFFFF) > 9 || (read_u32be(0x00,sf) & 0x00FFFFFF) > 9) + return NULL; + is_old = true; + h.big_endian = guess_endian32(0x04, sf); + } + + if (get_streamfile_size(sf) > 0x1000) /* arbitrary max */ + return NULL; + + /* (extensionless): no known extension */ + if (!check_extensions(sf,"")) + return NULL; + + read_s32_t read_s32 = h.big_endian ? read_s32be : read_s32le; + read_u32_t read_u32 = h.big_endian ? read_u32be : read_u32le; + + /* base header (with extra checks for old version since format is a bit simple) */ + if (!is_old) { + h.version = read_u8(0x04,sf); + if (h.version != 0x01) return NULL; + h.codec = read_u8(0x05,sf); + h.channels = read_u8(0x06,sf); + /* 07: null */ + h.num_samples = read_s32(0x08, sf); + h.sample_rate = read_s32(0x0c, sf); + h.loop_start = read_s32(0x10, sf); + h.loop_end = read_s32(0x14, sf); + h.extb_offset = read_u32le(0x18, sf); /* LE! */ + h.name_offset = read_u32le(0x1c, sf); + /* 20: null, unknown values (sometimes floats) */ + h.interleave = read_u32(0x38, sf); + + h.data_offset = 0; /* implicit... */ + + /* XX: extra values (may depend on codec/channels) */ + /* XX: DSP coefs / fmt headers (optional) */ + /* XX: extra table with offset to fmt headers / DSP coefs /etc (per channel) */ + /* XX: asset name */ + } + else { + h.codec = read_s32(0x00,sf); + if (h.codec > 0x09) return NULL; + h.channels = read_s32(0x04,sf); + if (h.channels > SQUEAK_MAX_CHANNELS) return NULL; + h.interleave = read_u32(0x08, sf); + if (h.interleave > 0xFFFFFF) return NULL; + h.loop_start = read_s32(0x0c, sf); + h.loop_end = read_s32(0x10, sf); + h.num_samples = read_s32(0x14, sf); + if (h.loop_start > h.loop_end || h.loop_end > h.num_samples) return NULL; + /* 18: float/value */ + /* 1c: float/value */ + /* 20: cue table entries (optional) */ + /* 22: unknown */ + /* 24: cues offset */ + /* 26: cues flags */ + h.extb_offset = read_u32le(0x28, sf); /* LE! */ + h.name_offset = read_u32le(0x2c, sf); + h.data_offset = read_u32(0x30, sf); /* PS2 uses a few big .raw rather than separate per header */ + + /* XX: DSP coefs / fmt headers (optional) */ + /* XX: cue table (00=null + 04=sample start per entry) */ + /* XX: extra table (00=null + 00=sample rate, 04=samples, per channel) */ + /* XX: asset name */ + + //sample_rate = ...; // read later after opening external info + + /* not ideal but... */ + if (h.data_offset && h.codec == 0x03) { + h.data_size = (h.num_samples / 28) * 0x10 * h.channels; + } + } + + + /* Wii streams uses a separate info file, check external flags */ + /* (possibly every section may be separate or not but only seen all at once) */ + h.stream = true; + h.external_info = (h.name_offset & 0xF0000000); + h.external_data = true; + h.name_offset = h.name_offset & 0x0FFFFFFF; + h.extb_offset = h.extb_offset & 0x0FFFFFFF; + if (h.extb_offset > h.name_offset) return NULL; + + switch(h.codec) { + case 0x00: h.type = DSP; break; /* Turbo Super Stunt Squad (Wii/3DS), Penguins of Madagascar (Wii/U/3DS) */ + case 0x01: h.type = PCM16LE; break; /* Falling Skies The Game (PC) */ + case 0x02: h.type = h.big_endian ? PCM16BE : PCM16LE; break; /* Falling Skies The Game (X360)-be, Scooby Doo and the Spooky Swamp (PC)-le */ + case 0x03: h.type = PSX; break; /* How to Train Your Dragon 2 (PS3), Falling Skies The Game (PS3) */ + case 0x04: h.type = MSIMA; break; /* Barbie Dreamhouse Party (DS) */ + case 0x05: h.type = PCM8; break; /* Scooby Doo and the Spooky Swamp (DS), Scooby Doo! First Frights (DS) */ + case 0x07: h.type = SPEEX; break; /* Scooby Doo and the Spooky Swamp (PC) */ + case 0x08: h.type = VORBIS; break; /* Scooby Doo and the Spooky Swamp (PC) */ + case 0x09: h.type = MSIMA; break; /* Turbo Super Stunt Squad (DS) */ + default: + VGM_LOG("SqueakStream: unknown codec %x\n", h.codec); + return NULL; + } + + return init_vgmstream_squeak_common(sf, &h); +} + + +/* SqueakSample - from Torus games (name/engine as identified in .hnk subdirs) */ +VGMSTREAM* init_vgmstream_squeaksample(STREAMFILE* sf) { + squeak_header_t h = {0}; + + + /* checks */ + if (read_u32le(0x00,sf) != 0x20 && read_u32le(0x00,sf) != 0x1c) /* even on BE */ + return NULL; + //if (get_streamfile_size(sf) > 0x1000) /* not correct for non-external files */ + // return NULL; + + /* (extensionless): no known extension */ + if (!check_extensions(sf,"")) + return NULL; + + h.big_endian = guess_endian32(0x04, sf); + read_s32_t read_s32 = h.big_endian ? read_s32be : read_s32le; + + /* base header (with extra checks since format is a bit simple) */ + uint32_t offset = read_u32le(0x00, sf); /* old versions use 0x1c, new 0x20, but otherwise don't look different */ + + h.channels = read_s32(0x04,sf); + if (h.channels > SQUEAK_MAX_CHANNELS) return NULL; + /* 04: float/value */ + /* 0c: float/value */ + /* 14: value? */ + /* 18: value? (new) / 1 (old) */ + /* 1c: 1? (new) / none (old) */ + + /* sample header per channel (separate fields but assumes all are repeated except offsets) */ + h.num_samples = read_s32(offset + 0x00,sf); + h.data_offset = read_u32le(offset + 0x04,sf); + h.loop_start = read_s32(offset + 0x08,sf); + h.loop_end = read_s32(offset + 0x0c,sf); + if (h.loop_start > h.loop_end || h.loop_end > h.num_samples) return NULL; + h.codec = read_s32(offset + 0x10,sf); + h.sample_rate = read_s32(offset + 0x14,sf); + if (h.sample_rate > 48000 || h.sample_rate < 0) return NULL; + + /* PCM has extended fields (0x68)*/ + if (h.codec != 0xFFFE0001) { + /* 18: loop start offset? (not always) */ + /* 1c: loop end offset? */ + /* 20: data size? */ + /* 24: data size? (new) / count? (old) */ + h.coef_offset = read_u32le(offset + 0x28,sf); + } + + /* DSP and old versions use a external .raw file (assumed extension) */ + h.stream = false; + h.external_info = false; + h.external_data = (h.data_offset & 0xF0000000); + h.data_offset = h.data_offset & 0x0FFFFFFF; + + /* each channel has its own info but mostly repeats (data may have padding, but files end with no padding) */ + { + int separation = 0; + switch(h.codec) { + case 0xFFFE0001: + case 0x0001FFFE: + case 0x01660001: separation = 0x68; break; + default: separation = 0x2c; break; + } + + for (int i = 0; i < h.channels; i++) { + h.data_offsets[i] = read_u32le(offset + 0x04 + i * separation, sf) & 0x0FFFFFFF; + h.coef_offsets[i] = read_u32le(offset + 0x28 + i * separation, sf); + } + + if (h.channels > 1) { + h.interleave = h.data_offsets[1] - h.data_offsets[0]; + h.coef_spacing = h.coef_offsets[1] - h.coef_offsets[0]; + } + } + + switch(h.codec) { + case 0x00: h.type = DSP; break; /* (same as below for unlooped audio) */ + case 0x01: h.type = DSP; break; /* Turbo Super Stunt Squad (Wii/3DS) */ + case 0x06: /* (same as below for unlooped audio) */ + case 0x07: h.type = PSX; break; /* How to Train Your Dragon 2 (PS3), Falling Skies The Game (PS3) */ + case 0x08: /* (same as below for unlooped audio) */ + case 0x09: h.type = IMA; break; /* Scooby-Doo! First Frights (DS), Turbo Super Stunt Squad (DS) */ + case 0xFFFE0001: h.type = PCM16BE; break; /* Falling Skies The Game (X360) */ + case 0x0001FFFE: h.type = PCM16LE; break; /* Scooby Doo and the Spooky Swamp (PC), Monster High: New Ghoul in School (PC) */ + case 0x01660001: h.type = XMA2; break; /* Rise of the Guardians (X360) */ + default: + VGM_LOG("SqueakSample: unknown codec %x\n", h.codec); + return NULL; + } + + return init_vgmstream_squeak_common(sf, &h); +} + + +static STREAMFILE* load_assets(STREAMFILE* sf, squeak_header_t* h) { + STREAMFILE* sb = NULL; + STREAMFILE* sn = NULL; + read_s32_t read_s32 = h->big_endian ? read_s32be : read_s32le; + + + char asset_name[0x20]; /* "(8-byte crc).raw", "xx(6-byte crc).raw", "(regular name).raw" */ + if (h->external_info) { + sn = open_streamfile_by_ext(sf, "asset"); /* unknown real extension if any, based on debug strings */ + if (!sn) { + vgm_logi("Squeak: external name '.asset' not found (put together)\n"); + goto fail; + } + } + + if (h->stream) { + if (h->version == 0) { + h->sample_rate = read_s32(h->extb_offset + 0x04, sn ? sn : sf); /* per channel, use first */ + } + + read_string(asset_name, sizeof(asset_name), h->name_offset, sn ? sn : sf); + + /* extb_offset defines N coef offset per channel but in practice this seem fixed, simplify */ + h->coef_offset = 0x40; + h->coef_spacing = 0x30; + } + + /* try to open external data .raw in various ways, since this format is a bit hard to use */ + if (h->stream) { + /* "(asset name)": plain as found */ + if (!sb) { + sb = open_streamfile_by_filename(sf, asset_name); + } + + /* "sound/(asset name)": most common way to store files */ + char path_name[256]; + snprintf(path_name, sizeof(path_name), "sound/%s", asset_name); + if (!sb) { + sb = open_streamfile_by_filename(sf, path_name); + } + } + + /* "(header name).raw": for squeakstreams and renamed files */ + if (!sb) { + sb = open_streamfile_by_ext(sf, "raw"); + } + + if (!sb) { + char* info = h->stream ? asset_name : "(filename).raw"; + vgm_logi("Squeak: external file '%s' not found (put together)\n", info); + goto fail; + } + + close_streamfile(sn); + return sb; +fail: + close_streamfile(sn); + return NULL; +} + +static VGMSTREAM* init_vgmstream_squeak_common(STREAMFILE* sf, squeak_header_t* h) { + VGMSTREAM* vgmstream = NULL; + STREAMFILE* sb = NULL; + STREAMFILE* sf_body = NULL; + + /* common */ + int loop_flag = h->loop_end > 0; + + + /* open external asset */ + if (h->external_data) { + sb = load_assets(sf, h); + if (!sb) goto fail; + } + + sf_body = sb ? sb : sf; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(h->channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = h->stream ? meta_SQUEAKSTREAM : meta_SQUEAKSAMPLE; + vgmstream->sample_rate = h->sample_rate; + vgmstream->num_samples = h->num_samples; + vgmstream->loop_start_sample = h->loop_start; + vgmstream->loop_end_sample = h->loop_end + 1; + vgmstream->stream_size = h->data_size; + + switch(h->type) { + case DSP: + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = h->interleave; + //vgmstream->interleave_last_block_size = ...; /* apparently padded */ + + dsp_read_coefs(vgmstream, sf, h->coef_offset + 0x00, h->coef_spacing, h->big_endian); + dsp_read_hist (vgmstream, sf, h->coef_offset + 0x24, h->coef_spacing, h->big_endian); + break; + + case PCM16LE: + vgmstream->coding_type = coding_PCM16LE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = h->interleave; /* not 0x02 */ + + break; + + case PCM16BE: + vgmstream->coding_type = coding_PCM16BE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = h->interleave; /* not 0x02 */ + + break; + + case PSX: + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = h->interleave; + break; + + case PCM8: + vgmstream->coding_type = coding_PCM8; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = h->interleave; + break; + + case MSIMA: + vgmstream->coding_type = coding_MS_IMA; + vgmstream->layout_type = layout_none; + //vgmstream->interleave_block_size = h->interleave; /* unused? (mono) */ + vgmstream->frame_size = h->codec == 0x04 ? 0x400 : 0x20; + break; + + case IMA: + vgmstream->coding_type = coding_IMA; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = h->interleave; + + /* possibly considered MS-IMA in a single block (not valid though), first 2 values maybe are adpcm hist */ + h->data_offset += 0x04; + break; + +#ifdef VGM_USE_FFMPEG + case XMA2: { + /* uses separate mono streams */ + vgmstream->coding_type = coding_FFmpeg; + for (int i = 0; i < h->channels; i++) { + uint32_t offset = h->data_offsets[i]; + uint32_t next_offset = (i + 1 == h->channels) ? get_streamfile_size(sf_body) : h->data_offsets[i+1]; + uint32_t data_size = next_offset - offset; + int layer_channels = 1; + + vgmstream->codec_data = init_ffmpeg_xma2_raw(sf_body, offset, data_size, h->num_samples, layer_channels, h->sample_rate, 0, 0); + if (!layered_add_codec(vgmstream, 0, layer_channels)) + goto fail; + } + if (!layered_add_done(vgmstream)) + goto fail; + + break; + } +#endif +#ifdef VGM_USE_VORBIS + case VORBIS: + vgmstream->codec_data = init_ogg_vorbis(sf_body, h->data_offset, 0, NULL); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_OGG_VORBIS; + vgmstream->layout_type = layout_none; + + break; +#endif +#ifdef VGM_USE_SPEEX + case SPEEX: { + vgmstream->codec_data = init_speex_torus(h->channels); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_SPEEX; + vgmstream->layout_type = layout_none; + + break; + } +#endif + default: + goto fail; + } + + if (!vgmstream_open_stream(vgmstream, sb ? sb : sf, h->data_offset)) + goto fail; + close_streamfile(sb); + return vgmstream; +fail: + close_streamfile(sb); + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/str_sega.c b/Frameworks/vgmstream/vgmstream/src/meta/str_sega.c new file mode 100644 index 000000000..f8e3dde81 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/str_sega.c @@ -0,0 +1,142 @@ +#include "meta.h" +#include "../coding/coding.h" + + +/* .STR - Sega Dreamcast's "Audio64 AM (AICA Manager) driver" streams */ +VGMSTREAM* init_vgmstream_str_sega(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint32_t start_offset, data_size; + int loop_flag, channels, track_channels, tracks, sample_rate, bps, interleave, blocks; + + + /* checks */ + tracks = read_u32le(0x00,sf); + if (tracks < 1 || tracks > 16) /* official limits */ + return NULL; + + /* "Sega Stream Asset Builder Revision ..." long text with program info, after header */ + if (!is_id64be(0xD4,sf, "\0Sega St")) + return NULL; + + if (!check_extensions(sf, "str")) + return NULL; + + sample_rate = read_s32le(0x04,sf); + bps = read_u32le(0x08,sf); + interleave = read_s32le(0x0C,sf); /* multiples of 0x800 (sector size) */ + blocks = read_s32le(0x10,sf); /* interruptsTillEnd, "how may irqs until the end of that tracks data" AKA interleaved blocks */ + + /* per track info (channels must be the same per track, and data_size may be inaccurate for other tracks) */ + data_size = read_u32le(0x14,sf); + track_channels = read_s32le(0x18,sf); /* max 2 for AICA, N for PCM */ + /* 0x08: blocks / interruptsTillEnd (not including padding) */ + /* header track data reserved up to max 16 * 0x0c = 0xC0 + 0x18 = 0xD4 */ + /* after track headers there may be one phantom entry with empty data/channels but repeated interruptsTillEnd (bug?) */ + + channels = track_channels * tracks; + + loop_flag = 0; /* no loop info */ + start_offset = 0x800; + + /* all tracks/data is padded */ + if (blocks * channels * interleave != get_streamfile_size(sf) - start_offset) + goto fail; + + /* streams start with a "leadIn" silence that defaults to 2 blocks, but it's configurable */ + //start_offset += (interleave * channels) * 2; + + + vgmstream = allocate_vgmstream(channels,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_STR_SEGA; + vgmstream->sample_rate = sample_rate; + + switch (bps) { + case 4: /* common [GTA2 (DC)] */ + vgmstream->coding_type = coding_AICA_int; + vgmstream->num_samples = yamaha_bytes_to_samples(data_size, track_channels); + + for (int i = 0; i < channels; i++) { + vgmstream->ch[i].adpcm_step_index = 0x7f; + } + break; + + case 8: /* not seen (encoder only) */ + vgmstream->coding_type = coding_PCM8_U; + vgmstream->num_samples = pcm8_bytes_to_samples(data_size, track_channels); + break; + + case 16: /* common [San Francisco Rush 2049 (DC)] */ + vgmstream->coding_type = coding_PCM16LE; + vgmstream->num_samples = pcm16_bytes_to_samples(data_size, track_channels); + break; + + default: + goto fail; + } + + vgmstream->interleave_block_size = interleave; + vgmstream->layout_type = layout_interleave; + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; +fail: + close_vgmstream(vgmstream); + return NULL; +} + +/* .STR - mutant Sega Dreamcast stream [102 Dalmatians: Puppies to the Rescue (DC)] */ +VGMSTREAM* init_vgmstream_str_sega_custom(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + off_t start_offset; + int loop_flag, channels, sample_rate, interleave; + uint32_t data_size; + + /* checks */ + if (read_u32le(0x00,sf) != 0x2) + goto fail; + + if (read_u64be(0xD4,sf) != 0x00) + return NULL; + + if (!check_extensions(sf, "str")) + return NULL; + + /* this looks vaguely like a STR and could be a fully new thing, but game does include Audio64.drv */ + + loop_flag = 0; + channels = 2; + sample_rate = read_s32le(0x04,sf); + if (read_u32le(0x08,sf) != 16) + return NULL; + interleave = read_s32le(0x0c,sf); + if (read_u32le(0x10,sf) != 0x10000 || + read_u32le(0x14,sf) != 0x00 || + read_u32le(0x18,sf) != 0x00 || + read_u32le(0x1C,sf) != 0x1F) + return NULL; + + start_offset = 0x800; + data_size = get_streamfile_size(sf) - start_offset; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_STR_SEGA_custom; + vgmstream->sample_rate =sample_rate; + vgmstream->coding_type = coding_PCM16LE; + vgmstream->num_samples = pcm16_bytes_to_samples(data_size, channels); + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/str_wav.c b/Frameworks/vgmstream/vgmstream/src/meta/str_wav.c index 18fc59d9e..3fa77f3eb 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/str_wav.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/str_wav.c @@ -583,11 +583,17 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa return 1; } + /* Bad Boys II (PC)[2004] */ /* Pac-Man World 3 (PC)[2005] */ if ((read_u32be(0x04,sf_h) == 0x00000800 || read_u32be(0x04,sf_h) == 0x01000800) && /* rare, mu_spectral1_explore_2 */ read_u32le(0x24,sf_h) == read_u32le(0x114,sf_h) && /* sample rate repeat */ - read_u32le(0x130,sf_h) + read_u32le(0x134,sf_h) * 0x40 == header_size /* ~0x140 + cues */ + ( + // check if the header ends at table1 (Bad Boys) + read_u32le(0x128,sf_h) * 0x4 + read_u32le(0x12c, sf_h) == header_size || + // otherwise it ends at table2 + read_u32le(0x130,sf_h) + read_u32le(0x134,sf_h) * 0x40 == header_size /* ~0x140 + cues */ + ) ) { /* 0x08: null */ /* 0x0c: hashname */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/txth.c b/Frameworks/vgmstream/vgmstream/src/meta/txth.c index 73995bf8c..c7b3052c3 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/txth.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/txth.c @@ -142,6 +142,8 @@ typedef struct { int chunk_start_set; int chunk_size_set; int chunk_count_set; + int chunk_bsize_set; + int chunk_dsize_set; uint32_t base_offset; uint32_t is_offset_absolute; @@ -311,6 +313,10 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) { (int32_t*)&txth.loop_start_sample, (int32_t*)&txth.loop_end_sample); } + if (txth.debug) { + vgm_logi("TXTH: offset=%x, size=%x, coefs=%x + %x\n", txth.start_offset, txth.data_size, txth.coef_offset, txth.coef_spacing); + } + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(txth.channels,txth.loop_flag); @@ -827,7 +833,8 @@ static void set_body_chunk(txth_header* txth) { //todo maybe should only be done once, or have some count to retrigger to simplify? if (!txth->chunk_start_set || !txth->chunk_size_set || !txth->chunk_count_set) return; - if (txth->chunk_size == 0 && !(txth->chunk_bsize_offset || txth->chunk_dsize_offset)) + + if (txth->chunk_size == 0 && !(txth->chunk_bsize_set || txth->chunk_dsize_set)) return; if (txth->chunk_start > txth->data_size || txth->chunk_count == 0) return; @@ -853,6 +860,8 @@ static void set_body_chunk(txth_header* txth) { cfg.chunk_bsize_offset = txth->chunk_bsize_offset; cfg.chunk_dsize_offset = txth->chunk_dsize_offset; cfg.chunk_be = txth->chunk_big_endian; + cfg.chunk_bsize_set = txth->chunk_bsize_set; + cfg.chunk_dsize_set = txth->chunk_dsize_set; cfg.chunk_start = txth->chunk_start; cfg.chunk_size = txth->chunk_size; @@ -1473,10 +1482,12 @@ static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, cha else if (is_string(key,"chunk_size_offset")) { if (!parse_num(txth->sf_head,txth,val, &txth->chunk_bsize_offset)) goto fail; txth->chunk_size_set = 1; + txth->chunk_bsize_set = 1; } else if (is_string(key,"chunk_data_size_offset")) { if (!parse_num(txth->sf_head,txth,val, &txth->chunk_dsize_offset)) goto fail; txth->chunk_size_set = 1; + txth->chunk_dsize_set = 1; } else if (is_string(key,"chunk_endianness")) { if (!parse_endianness(txth, val, &txth->chunk_big_endian, NULL)) goto fail; @@ -1976,7 +1987,7 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_ offset += txth->base_offset; if (/*offset < 0 ||*/ offset > get_streamfile_size(sf)) { - vgm_logi("TXTH: wrong offset over file size (%x + %x)\n", offset - txth->base_offset, txth->base_offset); + vgm_logi("TXTH: wrong offset over file size (%x + %x)\n", offset - txth->base_offset, txth->base_offset); goto fail; } @@ -1989,7 +2000,7 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_ offset = offset + subsong_spacing * (txth->target_subsong - 1); if (txth->debug) - vgm_logi("TXTH: use value at 0x%x (%s %ib)\n", offset, big_endian ? "BE" : "LE", size * 8); + vgm_logi("TXTH: use value at 0x%x (%s %ib)\n", offset, big_endian ? "BE" : "LE", size * 8); switch(size) { case 1: value = read_u8(offset,sf); break; @@ -2008,7 +2019,7 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_ value_read = 1; if (txth->debug) - vgm_logi(hex ? "TXTH: use constant 0x%x\n" : "TXTH: use constant %i\n", value); + vgm_logi(hex ? "TXTH: use constant 0x%x\n" : "TXTH: use constant %i\n", value); } else { /* known field */ if ((n = is_string_field(val,"interleave"))) value = txth->interleave; @@ -2067,7 +2078,7 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_ value_read = 1; if (txth->debug) - vgm_logi("TXTH: use field value 0x%x\n", value); + vgm_logi("TXTH: use field value 0x%x\n", value); } /* apply simple left-to-right math though, for now "(" ")" are counted and validated @@ -2110,7 +2121,7 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_ *out_value = result; if (txth->debug) - vgm_logi("TXTH: final value: %u (0x%x)\n", result, result); + vgm_logi("TXTH: final value: %u (0x%x)\n", result, result); return 1; fail: diff --git a/Frameworks/vgmstream/vgmstream/src/meta/txth_streamfile.h b/Frameworks/vgmstream/vgmstream/src/meta/txth_streamfile.h index 7816ea3bb..604550eb4 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/txth_streamfile.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/txth_streamfile.h @@ -17,6 +17,8 @@ typedef struct { uint32_t chunk_bsize_offset; uint32_t chunk_dsize_offset; int chunk_be; + int chunk_bsize_set; + int chunk_dsize_set; } txth_io_config_data; typedef struct { @@ -72,15 +74,15 @@ static size_t txth_io_read(STREAMFILE* sf, uint8_t* dest, off_t offset, size_t l } /* chunk size reader (overwrites the above) */ - if (data->cfg.chunk_header_size && (data->cfg.chunk_bsize_offset || data->cfg.chunk_dsize_offset)) { + if (data->cfg.chunk_header_size && (data->cfg.chunk_bsize_set || data->cfg.chunk_dsize_set)) { read_u32_t read_u32 = data->cfg.chunk_be ? read_u32be : read_u32le; data->block_size = 0; data->data_size = 0; - if (data->cfg.chunk_bsize_offset) + if (data->cfg.chunk_bsize_set) data->block_size = read_u32(data->physical_offset + data->cfg.chunk_bsize_offset, sf); - if (data->cfg.chunk_dsize_offset) + if (data->cfg.chunk_dsize_set) data->data_size = read_u32(data->physical_offset + data->cfg.chunk_dsize_offset, sf); if (!data->block_size && !data->data_size) { /* bad read? */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c index 58e0de211..c7ddc43e1 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c @@ -62,8 +62,8 @@ typedef struct { int has_rs_files; off_t sequence_extra_offset; - off_t sequence_sequence_loop; - off_t sequence_sequence_single; + off_t sequence_sequence_loop_start; + off_t sequence_sequence_num_loops; off_t sequence_sequence_count; off_t sequence_entry_number; size_t sequence_entry_size; @@ -188,8 +188,8 @@ typedef struct { int sequence_chain[SB_MAX_CHAIN_COUNT]; /* sequence of entry numbers */ int sequence_banks[SB_MAX_CHAIN_COUNT]; /* sequence of bnk bank numbers */ int sequence_multibank; /* info flag */ - int sequence_loop; /* chain index to loop */ - int sequence_single; /* if que sequence plays once (loops by default) */ + int sequence_loop_start; /* chain index to loop */ + int sequence_num_loops; /* if que sequence plays once (loops by default) */ float duration; /* silence duration */ @@ -1467,7 +1467,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_sequence(ubi_sb_header* sb, STREAMFILE* data->segments[i] = init_vgmstream_ubi_sb_header(&temp_sb, sf_bank, sf); if (!data->segments[i]) goto fail; - if (i == sb->sequence_loop) + if (i == sb->sequence_loop_start) sb->loop_start = sb->num_samples; sb->num_samples += data->segments[i]->num_samples; @@ -1483,7 +1483,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_sequence(ubi_sb_header* sb, STREAMFILE* goto fail; /* build the base VGMSTREAM */ - vgmstream = allocate_vgmstream(data->output_channels, !sb->sequence_single); + vgmstream = allocate_vgmstream(data->output_channels, !sb->sequence_num_loops); if (!vgmstream) goto fail; vgmstream->meta_type = meta_UBI_SB; @@ -1625,7 +1625,7 @@ static void build_readable_name(char * buf, size_t buf_size, ubi_sb_header* sb) index = sb->header_index; //-1 if (sb->type == UBI_SEQUENCE) { - if (sb->sequence_single) { + if (sb->sequence_num_loops) { if (sb->sequence_count == 1) res_name = "single"; else @@ -1635,7 +1635,7 @@ static void build_readable_name(char * buf, size_t buf_size, ubi_sb_header* sb) if (sb->sequence_count == 1) res_name = "single-loop"; else - res_name = (sb->sequence_loop == 0) ? "multi-loop" : "intro-loop"; + res_name = (sb->sequence_loop_start == 0) ? "multi-loop" : "intro-loop"; } } else { @@ -1917,10 +1917,10 @@ static int parse_type_sequence(ubi_sb_header* sb, off_t offset, STREAMFILE* sf) goto fail; } - sb->extra_offset = read_32bit(offset + sb->cfg.sequence_extra_offset, sf) + sb->sectionX_offset; - sb->sequence_loop = read_32bit(offset + sb->cfg.sequence_sequence_loop, sf); - sb->sequence_single = read_32bit(offset + sb->cfg.sequence_sequence_single, sf); - sb->sequence_count = read_32bit(offset + sb->cfg.sequence_sequence_count, sf); + sb->extra_offset = read_32bit(offset + sb->cfg.sequence_extra_offset, sf) + sb->sectionX_offset; + sb->sequence_loop_start = read_32bit(offset + sb->cfg.sequence_sequence_loop_start, sf); + sb->sequence_num_loops = read_32bit(offset + sb->cfg.sequence_sequence_num_loops, sf); + sb->sequence_count = read_32bit(offset + sb->cfg.sequence_sequence_count, sf); if (sb->sequence_count > SB_MAX_CHAIN_COUNT) { VGM_LOG("UBI SB: incorrect sequence count %i vs %i\n", sb->sequence_count, SB_MAX_CHAIN_COUNT); @@ -2705,17 +2705,17 @@ static void config_sb_audio_ps2_old(ubi_sb_header *sb, off_t flag_bits, int stre } static void config_sb_sequence(ubi_sb_header* sb, off_t sequence_count, off_t entry_size) { /* sequence header and chain table */ - sb->cfg.sequence_sequence_loop = sequence_count - 0x10; - sb->cfg.sequence_sequence_single= sequence_count - 0x0c; - sb->cfg.sequence_sequence_count = sequence_count; - sb->cfg.sequence_entry_size = entry_size; - sb->cfg.sequence_entry_number = 0x00; + sb->cfg.sequence_sequence_loop_start = sequence_count - 0x10; + sb->cfg.sequence_sequence_num_loops = sequence_count - 0x0c; + sb->cfg.sequence_sequence_count = sequence_count; + sb->cfg.sequence_entry_size = entry_size; + sb->cfg.sequence_entry_number = 0x00; if (sb->is_bnm || sb->is_dat || sb->is_ps2_bnm) { - sb->cfg.sequence_sequence_loop = sequence_count - 0x0c; - sb->cfg.sequence_sequence_single= sequence_count - 0x08; + sb->cfg.sequence_sequence_loop_start = sequence_count - 0x0c; + sb->cfg.sequence_sequence_num_loops = sequence_count - 0x08; } else if (sb->is_blk) { - sb->cfg.sequence_sequence_loop = sequence_count - 0x14; - sb->cfg.sequence_sequence_single= sequence_count - 0x0c; + sb->cfg.sequence_sequence_loop_start = sequence_count - 0x14; + sb->cfg.sequence_sequence_num_loops = sequence_count - 0x0c; } } static void config_sb_layer_hs(ubi_sb_header* sb, off_t layer_count, off_t stream_size, off_t stream_offset, off_t stream_name) { diff --git a/Frameworks/vgmstream/vgmstream/src/meta/vag.c b/Frameworks/vgmstream/vgmstream/src/meta/vag.c index 94c60593a..791513fa8 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/vag.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/vag.c @@ -81,25 +81,24 @@ VGMSTREAM* init_vgmstream_vag(STREAMFILE* sf) { loop_flag = 0; break; - case 0x70474156: /* pGAV (little endian / stereo) [Jak 3 (PS2), Jak X (PS2)] */ + case 0x70474156: /* pGAV (little endian / stereo) [Jak II, Jak 3, Jak X (PS2)] */ meta_type = meta_VAG_custom; start_offset = 0x30; - if (is_id32be(0x20,sf, "Ster")) { - channels = 2; + if (is_id32be(0x2000,sf, "pGAV")) + interleave = 0x2000; /* Jak II & Jak 3 interleave, includes header */ + else if (is_id32be(0x1000,sf, "pGAV")) + interleave = 0x1000; /* Jak X interleave, includes header */ + else + interleave = 0; - if (is_id32be(0x2000,sf, "pGAV")) - interleave = 0x2000; /* Jak 3 interleave, includes header */ - else if (is_id32be(0x1000,sf, "pGAV")) - interleave = 0x1000; /* Jak X interleave, includes header */ - else - goto fail; + if (interleave) { + channels = 2; interleave_first = interleave - start_offset; /* interleave includes header */ interleave_first_skip = start_offset; } else { channels = 1; - interleave = 0; } channel_size = read_u32le(0x0C,sf) / channels; @@ -289,7 +288,8 @@ VGMSTREAM* init_vgmstream_vag(STREAMFILE* sf) { } /* ignore bigfiles and bad extractions (approximate) */ - if (channel_size * channels + interleave * channels + start_offset * channels + 0x8000 < get_streamfile_size(sf) || + /* padding is set to 2 MiB to avoid breaking Jak series' VAGs */ + if (channel_size * channels + interleave * channels + start_offset * channels + 0x200000 < get_streamfile_size(sf) || channel_size * channels > get_streamfile_size(sf)) { vgm_logi("VAG: wrong expected (incorrect extraction? %x * %i + %x + %x + ~ vs %x)\n", channel_size, channels, interleave * channels, start_offset * channels, (uint32_t)get_streamfile_size(sf)); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wb.c b/Frameworks/vgmstream/vgmstream/src/meta/wb.c new file mode 100644 index 000000000..55f1680a8 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/wb.c @@ -0,0 +1,45 @@ +#include "meta.h" +#include "../coding/coding.h" + + +/* .WB - from Shooting Love. ~TRIZEAL~ */ +VGMSTREAM* init_vgmstream_wb(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint32_t start_offset; + int channels, loop_flag; + + /* check header */ + if (read_u32le(0x00,sf) != 0x00000000) + return NULL; + if (read_u32le(0x0c,sf) + 0x10 != get_streamfile_size(sf)) + return NULL; + + /* .wb: actual extension */ + if (!check_extensions(sf,"wb")) + goto fail; + + channels = 2; + start_offset = 0x10; + loop_flag = read_32bitLE(0x04,sf) > 0; /* loop end may be defined */ + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_WB; + vgmstream->sample_rate = 48000; + vgmstream->num_samples = pcm16_bytes_to_samples(read_u32le(0x0C,sf), channels); + vgmstream->loop_start_sample = read_s32le(0x04,sf); + vgmstream->loop_end_sample = read_s32le(0x08,sf); + + vgmstream->coding_type = coding_PCM16LE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 2; + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wii_mus.c b/Frameworks/vgmstream/vgmstream/src/meta/wii_mus.c deleted file mode 100644 index 488930be4..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/wii_mus.c +++ /dev/null @@ -1,124 +0,0 @@ -#include "meta.h" -#include "../layout/layout.h" -#include "../coding/coding.h" -#include "../util.h" - -/* .mus, as seen in Star Wars The Force Unleashed for Wii */ -/* Doesn't seem to be working quite right yet, coef table looks odd */ -VGMSTREAM * init_vgmstream_wii_mus(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - off_t start_offset; - off_t interleave; - - int i; - struct { - uint16_t gain; - uint16_t initial_ps; - uint16_t initial_hist1; - uint16_t initial_hist2; - uint16_t loop_ps; - /* - uint16_t loop_hist1; - uint16_t loop_hist2; - */ - } channel[2]; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("mus",filename_extension(filename))) goto fail; - - start_offset = read_32bitBE(0x08,streamFile); - interleave = read_32bitBE(0x04,streamFile); - - for (i=0;i<2;i++) - { - channel[i].gain = read_16bitBE(0x30+i*0x2e,streamFile); - channel[i].initial_ps = read_16bitBE(0x32+i*0x2e,streamFile); - channel[i].initial_hist1 = read_16bitBE(0x34+i*0x2e,streamFile); - channel[i].initial_hist2 = read_16bitBE(0x36+i*0x2e,streamFile); - channel[i].loop_ps = read_16bitBE(0x38+i*0x2e,streamFile); - } - - /* check initial predictor/scale */ - if (channel[0].initial_ps != (uint8_t)read_8bit(start_offset,streamFile)) - goto fail; - if (channel[1].initial_ps != (uint8_t)read_8bit(start_offset+interleave,streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (channel[0].gain || - channel[1].gain) - goto fail; - -#if 0 - if (ch0_header.loop_flag) { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - loop_off = (loop_off/interleave*interleave*2) + (loop_off%interleave); - if (ch0_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) - goto fail; - if (ch1_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off+interleave,streamFile)) - goto fail; - } -#endif - - /* build the VGMSTREAM */ - - vgmstream = allocate_vgmstream(2,0); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = read_32bitBE(0x0,streamFile); - vgmstream->sample_rate = (uint16_t)read_16bitBE(0x6c,streamFile); - - /* TODO: adjust for interleave? */ -#if 0 - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; -#endif - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = interleave; - vgmstream->meta_type = meta_DSP_WII_MUS; - - /* coeffs */ - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x10 + i*2,streamFile); - vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x3e + i*2,streamFile); - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = channel[0].initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = channel[0].initial_hist2; - vgmstream->ch[1].adpcm_history1_16 = channel[1].initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = channel[1].initial_hist2; - - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) goto fail; - vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[1].streamfile) goto fail; - - /* open the file for reading */ - for (i=0;i<2;i++) { - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+i*interleave; - } - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) { - if (vgmstream->ch[0].streamfile) close_streamfile(vgmstream->ch[0].streamfile); - close_vgmstream(vgmstream); - } - return NULL; -} - diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xa.c b/Frameworks/vgmstream/vgmstream/src/meta/xa.c index 3bd7745e4..6200a5c4a 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xa.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xa.c @@ -39,8 +39,9 @@ VGMSTREAM* init_vgmstream_xa(STREAMFILE* sf) { * .pxa: Mortal Kombat 4 (PS1) * .grn: Micro Machines (CDi) * .an2: Croc (PS1) movies + * .xai: Quake II (PS1) * (extensionless): bigfiles [Castlevania: Symphony of the Night (PS1)] */ - if (!check_extensions(sf,"xa,str,pxa,grn,an2,")) + if (!check_extensions(sf,"xa,str,pxa,grn,an2,,xai")) goto fail; /* Proper XA comes in raw (BIN 2352 mode2/form2) CD sectors, that contain XA subheaders. diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xa_xa30.c b/Frameworks/vgmstream/vgmstream/src/meta/xa_xa30.c index e6f390f79..9b49c0460 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xa_xa30.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xa_xa30.c @@ -5,7 +5,7 @@ VGMSTREAM * init_vgmstream_xa_xa30(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; - int loop_flag, channel_count, codec; + int loop_flag, channel_count, codec, interleave_block_size; size_t stream_size; int total_subsongs, target_subsong = streamFile->stream_index; @@ -31,6 +31,7 @@ VGMSTREAM * init_vgmstream_xa_xa30(STREAMFILE *streamFile) { codec = read_32bitLE(0x0c,streamFile); start_offset = read_32bitLE(0x10 + 0x04*(target_subsong-1),streamFile); stream_size = read_32bitLE(0x18 + 0x04*(target_subsong-1),streamFile); + interleave_block_size = read_32bitLE(0x24, streamFile); /* build the VGMSTREAM */ @@ -47,14 +48,14 @@ VGMSTREAM * init_vgmstream_xa_xa30(STREAMFILE *streamFile) { case 0x00: /* PCM (rare, seen in Driver 3) */ vgmstream->coding_type = coding_PCM16LE; vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile) / 2; + vgmstream->interleave_block_size = interleave_block_size / 2; vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16); break; case 0x01: /* MS-IMA variation */ vgmstream->coding_type = coding_REF_IMA; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile); + vgmstream->interleave_block_size = interleave_block_size; vgmstream->num_samples = ms_ima_bytes_to_samples(stream_size, vgmstream->interleave_block_size, channel_count); break; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xbox_ims.c b/Frameworks/vgmstream/vgmstream/src/meta/xbox_ims.c index 1c6f60ad9..e69de29bb 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xbox_ims.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xbox_ims.c @@ -1,61 +0,0 @@ -#include "meta.h" -#include "../util.h" -#include "../layout/layout.h" - -/* matx - - MATX (found in Matrix) -*/ - -VGMSTREAM * init_vgmstream_xbox_matx(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - int loop_flag=0; - int channel_count; - int i; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("matx",filename_extension(filename))) goto fail; - - loop_flag = 0; - channel_count=read_16bitLE(0x4,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_16bitLE(0x06,streamFile) & 0xffff; - - vgmstream->coding_type = coding_XBOX_IMA; - vgmstream->layout_type = layout_blocked_matx; - vgmstream->meta_type = meta_XBOX_MATX; - - /* open the file for reading by each channel */ - { - for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[i].streamfile) goto fail; - } - } - - /* Calc num_samples */ - block_update_matx(0,vgmstream); - vgmstream->num_samples=0; - - do { - vgmstream->num_samples += vgmstream->current_block_size/36*64; - block_update_matx(vgmstream->next_block_offset,vgmstream); - } while (vgmstream->next_block_offsetget_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("xss",filename_extension(filename))) goto fail; +/* .XSS - found in Dino Crisis 3 (Xbox) */ +VGMSTREAM* init_vgmstream_xss(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint32_t start_offset; + int channels, loop_flag, sample_rate; - /* check header */ - if ((uint16_t)read_16bitLE(0x15A,streamFile) != 0x10) - goto fail; - if (read_32bitLE(0x154,streamFile) / read_32bitLE(0x150,streamFile) != - (uint16_t)read_16bitLE(0x158,streamFile)) - goto fail; + /* checks */ + /* 00: name + garbage data up to ? + * (due to garbage it's hard which values are from this header, but these seem consistent) */ + if (read_u32le(0x0c,sf) != 0x3a) + return NULL; + if (read_u32le(0x10,sf) != 0x00) + return NULL; - loop_flag = (read_32bitLE(0x144,streamFile)!=0); - channel_count = (uint16_t)read_16bitLE(0x14E,streamFile); + if (!check_extensions(sf,"xss")) + return NULL; + + /* some floats and stuff up to 0x100, then some sizes, then RIFF fmt-like header */ + uint32_t head_offset = 0x140; + if (read_u32le(head_offset+0x00, sf) != 0x40) + return NULL; + + loop_flag = (read_u32le(head_offset + 0x04,sf) != 0); + if (read_u16le(head_offset + 0x0c,sf) != 0x01) + return NULL; + channels = read_u16le(head_offset + 0x0E,sf); + sample_rate = read_u32le(head_offset + 0x10,sf); + /* 14: bitrate */ + /* 18: block size */ + if (read_u16le(head_offset + 0x1A,sf) != 0x10) + return NULL; + + start_offset = 0x800; + + /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + vgmstream = allocate_vgmstream(channels,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = 0x800; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x150,streamFile); - vgmstream->coding_type = coding_PCM16LE; - vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(0x144,streamFile)/2/channel_count; - vgmstream->loop_end_sample = read_32bitLE(0x148,streamFile)/2/channel_count; - } - - if (vgmstream->channels == 1) { - vgmstream->layout_type = layout_none; - } else if (vgmstream->channels > 1) { - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x2; - } - vgmstream->meta_type = meta_XSS; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = pcm16_bytes_to_samples(get_streamfile_size(sf) - start_offset, channels); + vgmstream->loop_start_sample = pcm16_bytes_to_samples(read_u32le(head_offset + 0x04,sf), channels); + vgmstream->loop_end_sample = pcm16_bytes_to_samples(read_u32le(head_offset + 0x08,sf), channels); - /* 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; - - } - } + vgmstream->coding_type = coding_PCM16LE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + if (!vgmstream_open_stream(vgmstream, sf, 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/util/endianness.h b/Frameworks/vgmstream/vgmstream/src/util/endianness.h index ef67ef055..ab95f352e 100644 --- a/Frameworks/vgmstream/vgmstream/src/util/endianness.h +++ b/Frameworks/vgmstream/vgmstream/src/util/endianness.h @@ -1,10 +1,12 @@ -#ifndef _UTIL_ENDIAN_H -#define _UTIL_ENDIAN_H +#ifndef _ENDIANNESS_H +#define _ENDIANNESS_H #include "../streamfile.h" #include "reader_get.h" #include "reader_sf.h" +typedef uint64_t (*read_u64_t)(off_t, STREAMFILE*); +typedef int64_t (*read_s64_t)(off_t, STREAMFILE*); typedef uint32_t (*read_u32_t)(off_t, STREAMFILE*); typedef int32_t (*read_s32_t)(off_t, STREAMFILE*); typedef uint16_t (*read_u16_t)(off_t, STREAMFILE*); diff --git a/Frameworks/vgmstream/vgmstream/src/util/layout_utils.c b/Frameworks/vgmstream/vgmstream/src/util/layout_utils.c new file mode 100644 index 000000000..70d39358a --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/util/layout_utils.c @@ -0,0 +1,71 @@ +#include "layout_utils.h" + +#include "../vgmstream.h" +#include "../layout/layout.h" + +bool layered_add_codec(VGMSTREAM* vs, int layers, int layer_channels) { + if (!vs || !vs->codec_data) { + goto fail; + } + + if (!layer_channels) + layer_channels = 1; + if (!layers) + layers = vs->channels / layer_channels; + + int i; + layered_layout_data* data; + + switch(vs->layout_type) { + case layout_segmented: //to be improved + goto fail; + + case layout_layered: + data = vs->layout_data; + + i = data->curr_layer; + break; + + default: + data = init_layout_layered(layers); + if (!data) goto fail; + vs->layout_data = data; + vs->layout_type = layout_layered; + + i = 0; + break; + } + + data->layers[i] = allocate_vgmstream(layer_channels, vs->loop_flag); + if (!data->layers[i]) goto fail; + + data->layers[i]->meta_type = vs->meta_type; + data->layers[i]->sample_rate = vs->sample_rate; + data->layers[i]->num_samples = vs->num_samples; + data->layers[i]->loop_start_sample = vs->loop_start_sample; + data->layers[i]->loop_end_sample = vs->loop_end_sample; + + data->layers[i]->codec_data = vs->codec_data; + if (!data->layers[i]->codec_data) goto fail; + data->layers[i]->coding_type = vs->coding_type; + data->layers[i]->layout_type = layout_none; + + vs->codec_data = NULL; /* moved to layer, don't hold it */ + + data->curr_layer++; + + return true; +fail: + return false; +} + +bool layered_add_done(VGMSTREAM* vs) { + //TODO: some extra checks/setup? + + if (!setup_layout_layered(vs->layout_data)) + goto fail; + + return true; +fail: + return false; +} diff --git a/Frameworks/vgmstream/vgmstream/src/util/layout_utils.h b/Frameworks/vgmstream/vgmstream/src/util/layout_utils.h new file mode 100644 index 000000000..d52472195 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/util/layout_utils.h @@ -0,0 +1,12 @@ +#ifndef _LAYOUTS_UTIL_H +#define _LAYOUTS_UTIL_H + +#include "../vgmstream.h" + +/* add a new layer from codec data (setups layout if needed) + * codec is passed in the vs for easier free/etc control */ +bool layered_add_codec(VGMSTREAM* vs, int layers, int layer_channels); + +/* call when done adding layers */ +bool layered_add_done(VGMSTREAM* vs); +#endif diff --git a/Frameworks/vgmstream/vgmstream/src/util/sf_utils.c b/Frameworks/vgmstream/vgmstream/src/util/sf_utils.c index d0cd061ec..03e1723a7 100644 --- a/Frameworks/vgmstream/vgmstream/src/util/sf_utils.c +++ b/Frameworks/vgmstream/vgmstream/src/util/sf_utils.c @@ -9,11 +9,18 @@ static void swap_extension(char* pathname, /*size_t*/ int pathname_len, const ch char* extension = (char*)filename_extension(pathname); //todo safeops if (extension[0] == '\0') { - strcat(pathname, "."); - strcat(pathname, swap); + if (swap[0] != '\0') { + strcat(pathname, "."); + strcat(pathname, swap); + } } else { - strcpy(extension, swap); + if (swap[0] != '\0') { + strcpy(extension, swap); + } else { + extension--; + extension[0] = '\0'; + } } } diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c index 866e40a71..1dcf641c6 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c @@ -103,16 +103,12 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_lp_ap_lep, init_vgmstream_sdt, init_vgmstream_aix, - init_vgmstream_ngc_tydsp, init_vgmstream_wvs_xbox, init_vgmstream_wvs_ngc, - init_vgmstream_dc_str, - init_vgmstream_dc_str_v2, - init_vgmstream_xbox_matx, + init_vgmstream_str_sega, + init_vgmstream_str_sega_custom, init_vgmstream_dec, init_vgmstream_vs, - init_vgmstream_dc_str, - init_vgmstream_dc_str_v2, init_vgmstream_xmu, init_vgmstream_xvas, init_vgmstream_sat_sap, @@ -130,7 +126,7 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_ps2_mihb, init_vgmstream_ngc_pdt_split, init_vgmstream_ngc_pdt, - init_vgmstream_wii_mus, + init_vgmstream_mus_krome, init_vgmstream_dc_asd, init_vgmstream_spsd, init_vgmstream_rsd, @@ -145,7 +141,7 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_gca, init_vgmstream_spt_spd, init_vgmstream_ish_isd, - init_vgmstream_gsp_gsb, + init_vgmstream_gsnd, init_vgmstream_ydsp, init_vgmstream_ngc_ssm, init_vgmstream_ps2_joe, @@ -171,7 +167,6 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_zsd, init_vgmstream_vgs_ps, init_vgmstream_redspark, - init_vgmstream_ivaud, init_vgmstream_wii_wsd, init_vgmstream_dsp_ndp, init_vgmstream_ps2_sps, @@ -189,7 +184,7 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_apple_caff, init_vgmstream_pc_mxst, init_vgmstream_sab, - init_vgmstream_wii_bns, + init_vgmstream_bns, init_vgmstream_wii_was, init_vgmstream_pona_3do, init_vgmstream_pona_psx, @@ -201,7 +196,7 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_dmsg, init_vgmstream_ngc_dsp_aaap, init_vgmstream_ngc_dsp_konami, - init_vgmstream_ps2_wb, + init_vgmstream_wb, init_vgmstream_bnsf, init_vgmstream_ps2_gcm, init_vgmstream_smpl, @@ -214,7 +209,6 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_dsp_str_ig, init_vgmstream_ea_swvr, init_vgmstream_ps2_b1s, - init_vgmstream_ps2_wad, init_vgmstream_dsp_xiii, init_vgmstream_dsp_cabelas, init_vgmstream_lpcm_shade, @@ -286,7 +280,7 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_ubi_raki, init_vgmstream_pasx, init_vgmstream_xma, - init_vgmstream_sxd, + init_vgmstream_sndx, init_vgmstream_ogl, init_vgmstream_mc3, init_vgmstream_ghs, @@ -523,6 +517,10 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_awd, init_vgmstream_rws_809, init_vgmstream_pwb, + init_vgmstream_squeakstream, + init_vgmstream_squeaksample, + init_vgmstream_snds, + init_vgmstream_adm2, /* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */ init_vgmstream_scd_pcm, @@ -533,6 +531,7 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_mic_koei, init_vgmstream_seb, init_vgmstream_tgc, + init_vgmstream_ivaud, /* need companion files */ init_vgmstream_pos, init_vgmstream_sli_loops, diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.h b/Frameworks/vgmstream/vgmstream/src/vgmstream.h index d7770803f..5fa0afead 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.h @@ -281,6 +281,7 @@ typedef struct { int input_channels; /* internal buffer channels */ int output_channels; /* resulting channels (after mixing, if applied) */ int external_looping; /* don't loop using per-layer loops, but layout's own looping */ + int curr_layer; /* helper */ } layered_layout_data; diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream_types.h b/Frameworks/vgmstream/vgmstream/src/vgmstream_types.h index 028730216..945681872 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream_types.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream_types.h @@ -26,6 +26,7 @@ typedef enum { coding_PCMFLOAT, /* 32-bit float PCM */ coding_PCM24LE, /* little endian 24-bit PCM */ coding_PCM24BE, /* big endian 24-bit PCM */ + coding_PCM32LE, /* little endian 32-bit PCM */ /* ADPCM */ coding_CRI_ADX, /* CRI ADX */ @@ -202,7 +203,6 @@ typedef enum { layout_blocked_wsi, layout_blocked_str_snds, layout_blocked_ws_aud, - layout_blocked_matx, layout_blocked_dec, layout_blocked_xvas, layout_blocked_vs, @@ -258,7 +258,7 @@ typedef enum { meta_DSP_SADB, /* .sad */ meta_DSP_WSI, /* .wsi */ meta_IDSP_TT, /* Traveller's Tales games */ - meta_DSP_WII_MUS, /* .mus */ + meta_MUS_KROME, meta_DSP_WII_WSD, /* Phantom Brave (WII) */ meta_WII_NDP, /* Vertigo (Wii) */ meta_DSP_YGO, /* Konami: Yu-Gi-Oh! The Falsebound Kingdom (NGC), Hikaru no Go 3 (NGC) */ @@ -275,8 +275,8 @@ typedef enum { meta_THP, /* THP movie files */ meta_SWAV, meta_NDS_RRDS, /* Ridge Racer DS */ - meta_WII_BNS, /* Wii BNS Banner Sound (similar to RSTM) */ - meta_WIIU_BTSND, /* Wii U Boot Sound */ + meta_BNS, + meta_BTSND, meta_ADX_03, /* CRI ADX "type 03" */ meta_ADX_04, /* CRI ADX "type 04" */ @@ -345,9 +345,8 @@ typedef enum { meta_PS2_VAS, /* Pro Baseball Spirits 5 */ meta_LP_AP_LEP, meta_SDT, /* Baldur's Gate - Dark Alliance */ - meta_NGC_TYDSP, /* Ty - The Tasmanian Tiger */ - meta_DC_STR, /* SEGA Stream Asset Builder */ - meta_DC_STR_V2, /* variant of SEGA Stream Asset Builder */ + meta_STR_SEGA, + meta_STR_SEGA_custom, meta_SAP, meta_DC_IDVI, /* Eldorado Gate */ meta_KRAW, /* Geometry Wars - Galaxies */ @@ -358,7 +357,7 @@ typedef enum { meta_IDSP_IE, /* Defencer (GC) */ meta_SPT_SPD, /* Various (SPT+SPT DSP) */ meta_ISH_ISD, /* Various (ISH+ISD DSP) */ - meta_GSP_GSB, /* Tecmo games (Super Swing Golf 1 & 2, Quamtum Theory) */ + meta_GSND, meta_YDSP, /* WWE Day of Reckoning */ meta_FFCC_STR, /* Final Fantasy: Crystal Chronicles */ meta_UBI_JADE, /* Beyond Good & Evil, Rayman Raving Rabbids */ @@ -392,7 +391,6 @@ typedef enum { meta_UBI_CKD, /* Ubisoft CKD RIFF header (Rayman Origins Wii) */ meta_RAW_WAVM, meta_WVS, - meta_XBOX_MATX, /* XBOX MATX */ meta_XMU, meta_XVAS, meta_EA_SCHL, /* Electronic Arts SCHl with variable header */ @@ -455,7 +453,7 @@ typedef enum { meta_AST_MMV, meta_DMSG, /* Nightcaster II - Equinox (XBOX) */ meta_NGC_DSP_AAAP, /* Turok: Evolution (NGC), Vexx (NGC) */ - meta_PS2_WB, /* Shooting Love. ~TRIZEAL~ */ + meta_WB, meta_S14, /* raw Siren 14, 24kbit mono */ meta_SSS, /* raw Siren 14, 48kbit stereo */ meta_PS2_GCM, /* NamCollection */ @@ -469,7 +467,6 @@ typedef enum { meta_DSP_STR_IG, /* Micro Machines, Superman Superman: Shadow of Apokolis */ meta_EA_SWVR, /* Future Cop L.A.P.D., Freekstyle */ meta_PS2_B1S, /* 7 Wonders of the ancient world */ - meta_PS2_WAD, /* The golden Compass */ meta_DSP_XIII, /* XIII, possibly more (Ubisoft header???) */ meta_DSP_CABELAS, /* Cabelas games */ meta_PS2_ADM, /* Dragon Quest V (PS2) */ @@ -532,7 +529,7 @@ typedef enum { meta_ASTB, meta_WWISE_RIFF, /* Audiokinetic Wwise RIFF/RIFX */ meta_UBI_RAKI, /* Ubisoft RAKI header (Rayman Legends, Just Dance 2017) */ - meta_SXD, /* Sony SXD (Gravity Rush, Freedom Wars PSV) */ + meta_SNDX, meta_OGL, /* Shin'en Wii/WiiU (Jett Rocket (Wii), FAST Racing NEO (WiiU)) */ meta_MC3, /* Paradigm games (T3 PS2, MX Rider PS2, MI: Operation Surma PS2) */ meta_GHS, @@ -540,7 +537,7 @@ typedef enum { meta_MTA2, meta_XA_XA30, meta_XA_04SW, - meta_TXTH, /* generic text header */ + meta_TXTH, meta_SK_AUD, /* Silicon Knights .AUD (Eternal Darkness GC) */ meta_AHX, meta_STMA, @@ -581,11 +578,11 @@ typedef enum { meta_DSP_MCADPCM, /* Skyrim (Switch) */ meta_UBI_LYN, /* Ubisoft LyN engine [The Adventures of Tintin (multi)] */ meta_MSB_MSH, /* sfx companion of MIH+MIB */ - meta_TXTP, /* generic text playlist */ + meta_TXTP, meta_SMC_SMH, /* Wangan Midnight (System 246) */ meta_PPST, /* PPST [Parappa the Rapper (PSP)] */ meta_SPS_N1, - meta_UBI_BAO, /* Ubisoft BAO */ + meta_UBI_BAO, meta_DSP_SWITCH_AUDIO, /* Gal Gun 2 (Switch) */ meta_H4M, /* Hudson HVQM4 video [Resident Evil 0 (GC), Tales of Symphonia (GC)] */ meta_ASF, /* Argonaut ASF [Croc 2 (PC)] */ @@ -694,13 +691,16 @@ typedef enum { meta_SSPF, meta_S3V, meta_ESF, - meta_ADM3, + meta_ADM, meta_TT_AD, meta_SNDZ, meta_VAB, meta_BIGRP, meta_DIC1, meta_AWD, + meta_SQUEAKSTREAM, + meta_SQUEAKSAMPLE, + meta_SNDS, } meta_t; diff --git a/Info.plist.template b/Info.plist.template index d23a2bef7..397db0f83 100644 --- a/Info.plist.template +++ b/Info.plist.template @@ -509,6 +509,7 @@ fda ffw filp + fish flx fsb fsv @@ -522,10 +523,11 @@ gcw genh gin + gmd gms grn - gsb gsf + gsp gtd gwm h4m @@ -534,7 +536,6 @@ hd3 hdr hdt - hgc1 his hps hsf @@ -638,7 +639,6 @@ mab mad map - matx mc3 mca mcadpcm @@ -797,8 +797,6 @@ sgb sgd sgt - sgx - sl3 slb sli smc @@ -858,10 +856,10 @@ tmx tra trk + trs tun txth txtp - tydsp u0 ue4opus ulw @@ -943,6 +941,7 @@ xa xa2 xa30 + xai xag xau xav