diff --git a/Cog.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Cog.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 000000000..18d981003
--- /dev/null
+++ b/Cog.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj
index e3b3ad16e..c7bbcf537 100644
--- a/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj
+++ b/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj
@@ -11,7 +11,63 @@
8301659A1F256BD000CA0941 /* txth.c in Sources */ = {isa = PBXBuildFile; fileRef = 830165971F256BD000CA0941 /* txth.c */; };
8301659B1F256BD000CA0941 /* ea_schl_fixed.c in Sources */ = {isa = PBXBuildFile; fileRef = 830165981F256BD000CA0941 /* ea_schl_fixed.c */; };
8301659C1F256BD000CA0941 /* nds_strm_ffta2.c in Sources */ = {isa = PBXBuildFile; fileRef = 830165991F256BD000CA0941 /* nds_strm_ffta2.c */; };
- 830165A21F256BF400CA0941 /* hwas_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 830165A11F256BF400CA0941 /* hwas_blocked.c */; };
+ 8306B08420984518000302D4 /* at3plus_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B08120984517000302D4 /* at3plus_decoder.c */; };
+ 8306B08520984518000302D4 /* yamaha_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B08220984517000302D4 /* yamaha_decoder.c */; };
+ 8306B08620984518000302D4 /* fadpcm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B08320984517000302D4 /* fadpcm_decoder.c */; };
+ 8306B0A220984552000302D4 /* blocked_bdsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0872098454C000302D4 /* blocked_bdsp.c */; };
+ 8306B0A320984552000302D4 /* blocked_ast.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0882098454C000302D4 /* blocked_ast.c */; };
+ 8306B0A420984552000302D4 /* segmented.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0892098454D000302D4 /* segmented.c */; };
+ 8306B0A520984552000302D4 /* blocked_ea_wve_au00.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B08A2098454D000302D4 /* blocked_ea_wve_au00.c */; };
+ 8306B0A620984552000302D4 /* blocked_ea_wve_ad10.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B08B2098454D000302D4 /* blocked_ea_wve_ad10.c */; };
+ 8306B0A720984552000302D4 /* blocked_xvas.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B08C2098454D000302D4 /* blocked_xvas.c */; };
+ 8306B0A820984552000302D4 /* blocked_ps2_iab.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B08D2098454D000302D4 /* blocked_ps2_iab.c */; };
+ 8306B0A920984552000302D4 /* blocked_adm.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B08E2098454E000302D4 /* blocked_adm.c */; };
+ 8306B0AA20984552000302D4 /* blocked_sthd.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B08F2098454E000302D4 /* blocked_sthd.c */; };
+ 8306B0AB20984552000302D4 /* layered.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0902098454E000302D4 /* layered.c */; };
+ 8306B0AC20984552000302D4 /* blocked_xa.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0912098454E000302D4 /* blocked_xa.c */; };
+ 8306B0AD20984552000302D4 /* blocked_caf.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0922098454E000302D4 /* blocked_caf.c */; };
+ 8306B0AE20984552000302D4 /* blocked_filp.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0932098454F000302D4 /* blocked_filp.c */; };
+ 8306B0AF20984552000302D4 /* blocked_rws.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0942098454F000302D4 /* blocked_rws.c */; };
+ 8306B0B020984552000302D4 /* blocked_ps2_strlr.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0952098454F000302D4 /* blocked_ps2_strlr.c */; };
+ 8306B0B120984552000302D4 /* blocked_halpst.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0962098454F000302D4 /* blocked_halpst.c */; };
+ 8306B0B220984552000302D4 /* blocked_mxch.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0972098454F000302D4 /* blocked_mxch.c */; };
+ 8306B0B320984552000302D4 /* blocked_thp.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B09820984550000302D4 /* blocked_thp.c */; };
+ 8306B0B420984552000302D4 /* blocked_tra.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B09920984550000302D4 /* blocked_tra.c */; };
+ 8306B0B520984552000302D4 /* blocked_emff.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B09A20984550000302D4 /* blocked_emff.c */; };
+ 8306B0B620984552000302D4 /* blocked_hwas.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B09B20984550000302D4 /* blocked_hwas.c */; };
+ 8306B0B720984552000302D4 /* blocked_str_snds.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B09C20984550000302D4 /* blocked_str_snds.c */; };
+ 8306B0B820984552000302D4 /* blocked_ws_aud.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B09D20984551000302D4 /* blocked_ws_aud.c */; };
+ 8306B0B920984552000302D4 /* blocked_matx.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B09E20984551000302D4 /* blocked_matx.c */; };
+ 8306B0BA20984552000302D4 /* blocked_wsi.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B09F20984551000302D4 /* blocked_wsi.c */; };
+ 8306B0BB20984552000302D4 /* blocked_gsb.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0A020984551000302D4 /* blocked_gsb.c */; };
+ 8306B0BC20984552000302D4 /* blocked_vs.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0A120984551000302D4 /* blocked_vs.c */; };
+ 8306B0D820984590000302D4 /* ea_eaac_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8306B0BD2098458B000302D4 /* ea_eaac_streamfile.h */; };
+ 8306B0D920984590000302D4 /* ngc_str_cauldron.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0BE2098458C000302D4 /* ngc_str_cauldron.c */; };
+ 8306B0DA20984590000302D4 /* ea_wve_au00.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0BF2098458C000302D4 /* ea_wve_au00.c */; };
+ 8306B0DB20984590000302D4 /* nxap.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0C02098458C000302D4 /* nxap.c */; };
+ 8306B0DC20984590000302D4 /* sthd.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0C12098458C000302D4 /* sthd.c */; };
+ 8306B0DD20984590000302D4 /* waf.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0C22098458C000302D4 /* waf.c */; };
+ 8306B0DE20984590000302D4 /* awc_xma_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8306B0C32098458C000302D4 /* awc_xma_streamfile.h */; };
+ 8306B0DF20984590000302D4 /* ea_wve_ad10.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0C42098458D000302D4 /* ea_wve_ad10.c */; };
+ 8306B0E020984590000302D4 /* ppst_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8306B0C52098458D000302D4 /* ppst_streamfile.h */; };
+ 8306B0E120984590000302D4 /* ubi_lyn_ogg_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8306B0C62098458D000302D4 /* ubi_lyn_ogg_streamfile.h */; };
+ 8306B0E220984590000302D4 /* smv.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0C72098458D000302D4 /* smv.c */; };
+ 8306B0E320984590000302D4 /* aax_utf.h in Headers */ = {isa = PBXBuildFile; fileRef = 8306B0C82098458D000302D4 /* aax_utf.h */; };
+ 8306B0E420984590000302D4 /* wave.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0C92098458E000302D4 /* wave.c */; };
+ 8306B0E520984590000302D4 /* ubi_lyn.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0CA2098458E000302D4 /* ubi_lyn.c */; };
+ 8306B0E620984590000302D4 /* msb_msh.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0CB2098458E000302D4 /* msb_msh.c */; };
+ 8306B0E720984590000302D4 /* opus_ppp.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0CC2098458E000302D4 /* opus_ppp.c */; };
+ 8306B0E820984590000302D4 /* opus_interleave_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8306B0CD2098458E000302D4 /* opus_interleave_streamfile.h */; };
+ 8306B0E920984590000302D4 /* opus.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0CE2098458E000302D4 /* opus.c */; };
+ 8306B0EA20984590000302D4 /* caf.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0CF2098458F000302D4 /* caf.c */; };
+ 8306B0EB20984590000302D4 /* wave_segmented.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0D02098458F000302D4 /* wave_segmented.c */; };
+ 8306B0EC20984590000302D4 /* pcm_sre.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0D12098458F000302D4 /* pcm_sre.c */; };
+ 8306B0ED20984590000302D4 /* txtp.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0D22098458F000302D4 /* txtp.c */; };
+ 8306B0EE20984590000302D4 /* smc_smh.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0D32098458F000302D4 /* smc_smh.c */; };
+ 8306B0EF20984590000302D4 /* ubi_bao.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0D420984590000302D4 /* ubi_bao.c */; };
+ 8306B0F020984590000302D4 /* atsl.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0D520984590000302D4 /* atsl.c */; };
+ 8306B0F120984590000302D4 /* ppst.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0D620984590000302D4 /* ppst.c */; };
+ 8306B0F220984590000302D4 /* ubi_jade.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0D720984590000302D4 /* ubi_jade.c */; };
830EBE102004655D0023AA10 /* atrac9_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBE0F2004655D0023AA10 /* atrac9_decoder.c */; };
830EBE132004656E0023AA10 /* xnb.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBE112004656E0023AA10 /* xnb.c */; };
830EBE142004656E0023AA10 /* ktss.c in Sources */ = {isa = PBXBuildFile; fileRef = 830EBE122004656E0023AA10 /* ktss.c */; };
@@ -39,7 +95,6 @@
83345A4A1F8AEAF900B2EAA4 /* ffmpeg_decoder_utils_switch_opus.c in Sources */ = {isa = PBXBuildFile; fileRef = 83345A491F8AEAF900B2EAA4 /* ffmpeg_decoder_utils_switch_opus.c */; };
83345A4F1F8AEB2800B2EAA4 /* nub_xma.c in Sources */ = {isa = PBXBuildFile; fileRef = 83345A4B1F8AEB2700B2EAA4 /* nub_xma.c */; };
83345A501F8AEB2800B2EAA4 /* pc_al2.c in Sources */ = {isa = PBXBuildFile; fileRef = 83345A4C1F8AEB2700B2EAA4 /* pc_al2.c */; };
- 83345A511F8AEB2800B2EAA4 /* nsw_opus.c in Sources */ = {isa = PBXBuildFile; fileRef = 83345A4D1F8AEB2800B2EAA4 /* nsw_opus.c */; };
83345A521F8AEB2800B2EAA4 /* xvag.c in Sources */ = {isa = PBXBuildFile; fileRef = 83345A4E1F8AEB2800B2EAA4 /* xvag.c */; };
833A7A2E1ED11961003EC53E /* xau.c in Sources */ = {isa = PBXBuildFile; fileRef = 833A7A2D1ED11961003EC53E /* xau.c */; };
8349A8DF1FE6251F00E26435 /* vorbis_custom_utils_vid1.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8DC1FE6251E00E26435 /* vorbis_custom_utils_vid1.c */; };
@@ -72,7 +127,6 @@
8349A91A1FE6258200E26435 /* vxn.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A9011FE6258000E26435 /* vxn.c */; };
8349A91B1FE6258200E26435 /* adx_keys.h in Headers */ = {isa = PBXBuildFile; fileRef = 8349A9021FE6258100E26435 /* adx_keys.h */; };
8349A91C1FE6258200E26435 /* mogg.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A9031FE6258100E26435 /* mogg.c */; };
- 8349A91D1FE6258200E26435 /* aax_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8349A9041FE6258100E26435 /* aax_streamfile.h */; };
8349A91E1FE6258200E26435 /* bar.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A9051FE6258100E26435 /* bar.c */; };
8349A91F1FE6258200E26435 /* naac.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A9061FE6258100E26435 /* naac.c */; };
834D3A6E19F47C98001C54F6 /* g1l.c in Sources */ = {isa = PBXBuildFile; fileRef = 834D3A6D19F47C98001C54F6 /* g1l.c */; };
@@ -84,8 +138,6 @@
836F6F1E18BDC2190095E648 /* acm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE018BDC2180095E648 /* acm_decoder.c */; };
836F6F1F18BDC2190095E648 /* acm_decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 836F6DE118BDC2180095E648 /* acm_decoder.h */; settings = {ATTRIBUTES = (Public, ); }; };
836F6F2018BDC2190095E648 /* adx_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE218BDC2180095E648 /* adx_decoder.c */; };
- 836F6F2118BDC2190095E648 /* aica_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE318BDC2180095E648 /* aica_decoder.c */; };
- 836F6F2218BDC2190095E648 /* at3_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE418BDC2180095E648 /* at3_decoder.c */; };
836F6F2318BDC2190095E648 /* coding.h in Headers */ = {isa = PBXBuildFile; fileRef = 836F6DE518BDC2180095E648 /* coding.h */; };
836F6F2518BDC2190095E648 /* g721_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE718BDC2180095E648 /* g721_decoder.c */; };
836F6F2618BDC2190095E648 /* g7221_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE818BDC2180095E648 /* g7221_decoder.c */; };
@@ -110,34 +162,11 @@
836F6F3A18BDC2190095E648 /* sdx2_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DFC18BDC2180095E648 /* sdx2_decoder.c */; };
836F6F3B18BDC2190095E648 /* ws_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DFD18BDC2180095E648 /* ws_decoder.c */; };
836F6F3C18BDC2190095E648 /* xa_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DFE18BDC2180095E648 /* xa_decoder.c */; };
- 836F6F3D18BDC2190095E648 /* aax_layout.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0018BDC2180095E648 /* aax_layout.c */; };
836F6F3E18BDC2190095E648 /* aix_layout.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0118BDC2180095E648 /* aix_layout.c */; };
- 836F6F3F18BDC2190095E648 /* ast_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0218BDC2180095E648 /* ast_blocked.c */; };
- 836F6F4018BDC2190095E648 /* bdsp_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0318BDC2180095E648 /* bdsp_blocked.c */; };
836F6F4118BDC2190095E648 /* blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0418BDC2180095E648 /* blocked.c */; };
- 836F6F4218BDC2190095E648 /* caf_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0518BDC2180095E648 /* caf_blocked.c */; };
- 836F6F4518BDC2190095E648 /* emff_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0818BDC2180095E648 /* emff_blocked.c */; };
- 836F6F4618BDC2190095E648 /* filp_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0918BDC2180095E648 /* filp_blocked.c */; };
- 836F6F4718BDC2190095E648 /* gsb_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0A18BDC2180095E648 /* gsb_blocked.c */; };
- 836F6F4818BDC2190095E648 /* halpst_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0B18BDC2180095E648 /* halpst_blocked.c */; };
- 836F6F4918BDC2190095E648 /* ims_block.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0C18BDC2180095E648 /* ims_block.c */; };
836F6F4A18BDC2190095E648 /* interleave.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0D18BDC2180095E648 /* interleave.c */; };
836F6F4D18BDC2190095E648 /* layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 836F6E1018BDC2180095E648 /* layout.h */; };
- 836F6F4F18BDC2190095E648 /* mus_acm_layout.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E1218BDC2180095E648 /* mus_acm_layout.c */; };
- 836F6F5018BDC2190095E648 /* mxch_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E1318BDC2180095E648 /* mxch_blocked.c */; };
836F6F5118BDC2190095E648 /* nolayout.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E1418BDC2180095E648 /* nolayout.c */; };
- 836F6F5218BDC2190095E648 /* ps2_adm_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E1518BDC2180095E648 /* ps2_adm_blocked.c */; };
- 836F6F5318BDC2190095E648 /* ps2_iab_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E1618BDC2180095E648 /* ps2_iab_blocked.c */; };
- 836F6F5418BDC2190095E648 /* ps2_strlr_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E1718BDC2180095E648 /* ps2_strlr_blocked.c */; };
- 836F6F5618BDC2190095E648 /* scd_int_layout.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E1918BDC2180095E648 /* scd_int_layout.c */; };
- 836F6F5718BDC2190095E648 /* str_snds_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E1A18BDC2180095E648 /* str_snds_blocked.c */; };
- 836F6F5818BDC2190095E648 /* thp_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E1B18BDC2180095E648 /* thp_blocked.c */; };
- 836F6F5918BDC2190095E648 /* tra_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E1C18BDC2180095E648 /* tra_blocked.c */; };
- 836F6F5A18BDC2190095E648 /* vs_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E1D18BDC2180095E648 /* vs_blocked.c */; };
- 836F6F5B18BDC2190095E648 /* ws_aud_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E1E18BDC2180095E648 /* ws_aud_blocked.c */; };
- 836F6F5C18BDC2190095E648 /* wsi_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E1F18BDC2180095E648 /* wsi_blocked.c */; };
- 836F6F5D18BDC2190095E648 /* xa_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2018BDC2180095E648 /* xa_blocked.c */; };
- 836F6F5E18BDC2190095E648 /* xvas_block.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2118BDC2180095E648 /* xvas_block.c */; };
836F6F6518BDC2190095E648 /* 2dx9.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2918BDC2180095E648 /* 2dx9.c */; };
836F6F6618BDC2190095E648 /* aax.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2A18BDC2180095E648 /* aax.c */; };
836F6F6718BDC2190095E648 /* acm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2B18BDC2180095E648 /* acm.c */; };
@@ -202,8 +231,6 @@
836F6FA818BDC2190095E648 /* nds_swav.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6C18BDC2180095E648 /* nds_swav.c */; };
836F6FA918BDC2190095E648 /* ngc_adpdtk.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6D18BDC2180095E648 /* ngc_adpdtk.c */; };
836F6FAA18BDC2190095E648 /* ngc_bh2pcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6E18BDC2180095E648 /* ngc_bh2pcm.c */; };
- 836F6FAB18BDC2190095E648 /* ngc_bo2.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6F18BDC2180095E648 /* ngc_bo2.c */; };
- 836F6FAC18BDC2190095E648 /* ngc_caf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7018BDC2180095E648 /* ngc_caf.c */; };
836F6FAD18BDC2190095E648 /* ngc_dsp_konami.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7118BDC2180095E648 /* ngc_dsp_konami.c */; };
836F6FAE18BDC2190095E648 /* ngc_dsp_mpds.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7218BDC2180095E648 /* ngc_dsp_mpds.c */; };
836F6FAF18BDC2190095E648 /* ngc_dsp_std.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7318BDC2180095E648 /* ngc_dsp_std.c */; };
@@ -265,7 +292,6 @@
836F6FEE18BDC2190095E648 /* ps2_p2bt.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB218BDC2180095E648 /* ps2_p2bt.c */; };
836F6FEF18BDC2190095E648 /* ps2_pnb.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB318BDC2180095E648 /* ps2_pnb.c */; };
836F6FF018BDC2190095E648 /* ps2_psh.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB418BDC2180095E648 /* ps2_psh.c */; };
- 836F6FF118BDC2190095E648 /* ps2_psw.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB518BDC2180095E648 /* ps2_psw.c */; };
836F6FF218BDC2190095E648 /* ps2_rnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB618BDC2180095E648 /* ps2_rnd.c */; };
836F6FF318BDC2190095E648 /* ps2_rstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB718BDC2180095E648 /* ps2_rstm.c */; };
836F6FF418BDC2190095E648 /* rws.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB818BDC2180095E648 /* rws.c */; };
@@ -348,7 +374,6 @@
836F704A18BDC2190095E648 /* xbox_wavm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0E18BDC2190095E648 /* xbox_wavm.c */; };
836F704B18BDC2190095E648 /* xbox_xmu.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0F18BDC2190095E648 /* xbox_xmu.c */; };
836F704C18BDC2190095E648 /* xbox_xvas.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F1018BDC2190095E648 /* xbox_xvas.c */; };
- 836F704D18BDC2190095E648 /* xbox_xwav.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F1118BDC2190095E648 /* xbox_xwav.c */; };
836F704E18BDC2190095E648 /* xss.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F1218BDC2190095E648 /* xss.c */; };
836F704F18BDC2190095E648 /* xwb.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F1318BDC2190095E648 /* xwb.c */; };
836F705018BDC2190095E648 /* ydsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F1418BDC2190095E648 /* ydsp.c */; };
@@ -366,7 +391,6 @@
83709E071ECBC1A4005C03D3 /* mss.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E011ECBC1A4005C03D3 /* mss.c */; };
83709E081ECBC1A4005C03D3 /* ps2_rxws.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E021ECBC1A4005C03D3 /* ps2_rxws.c */; };
83709E091ECBC1A4005C03D3 /* ta_aac.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E031ECBC1A4005C03D3 /* ta_aac.c */; };
- 83709E0A1ECBC1A4005C03D3 /* waa_wac_wad_wam.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E041ECBC1A4005C03D3 /* waa_wac_wad_wam.c */; };
83709E0D1ECBC1C3005C03D3 /* mc3_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E0B1ECBC1C3005C03D3 /* mc3_decoder.c */; };
83709E0E1ECBC1C3005C03D3 /* psv_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E0C1ECBC1C3005C03D3 /* psv_decoder.c */; };
8374EE3E1F787AB600033E90 /* ffmpeg_decoder_utils_ea_xma.c in Sources */ = {isa = PBXBuildFile; fileRef = 8374EE361F787AB500033E90 /* ffmpeg_decoder_utils_ea_xma.c */; };
@@ -388,7 +412,6 @@
838BDB7D1D3B1FCC0022CA6F /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB7C1D3B1FCC0022CA6F /* CoreVideo.framework */; };
838BDB7F1D3B1FD10022CA6F /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB7E1D3B1FD10022CA6F /* Cocoa.framework */; };
839B54521EEE1D9600048A2D /* ngc_ulw.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BD11F1EEE1CF200198540 /* ngc_ulw.c */; };
- 839B54571EEE1DA000048A2D /* rws_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BD1201EEE1D2A00198540 /* rws_blocked.c */; };
839E21E01F2EDAF100EE54D7 /* vorbis_custom_data_fsb.h in Headers */ = {isa = PBXBuildFile; fileRef = 839E21D61F2EDAF000EE54D7 /* vorbis_custom_data_fsb.h */; };
839E21E11F2EDAF100EE54D7 /* vorbis_custom_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 839E21D71F2EDAF000EE54D7 /* vorbis_custom_decoder.c */; };
839E21E21F2EDAF100EE54D7 /* vorbis_custom_utils_wwise.c in Sources */ = {isa = PBXBuildFile; fileRef = 839E21D81F2EDAF000EE54D7 /* vorbis_custom_utils_wwise.c */; };
@@ -405,7 +428,6 @@
83A21F86201D8981000F04B9 /* xwc.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F7D201D8980000F04B9 /* xwc.c */; };
83A21F87201D8981000F04B9 /* fsb_keys.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A21F7E201D8980000F04B9 /* fsb_keys.h */; };
83A21F88201D8981000F04B9 /* ogg_vorbis.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F7F201D8980000F04B9 /* ogg_vorbis.c */; };
- 83A21F89201D8982000F04B9 /* atsl3.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F80201D8980000F04B9 /* atsl3.c */; };
83A21F8A201D8982000F04B9 /* fsb_encrypted.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F81201D8981000F04B9 /* fsb_encrypted.c */; };
83A21F8B201D8982000F04B9 /* sps_n1.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F82201D8981000F04B9 /* sps_n1.c */; };
83A21F8C201D8982000F04B9 /* kma9.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F83201D8981000F04B9 /* kma9.c */; };
@@ -572,7 +594,63 @@
830165971F256BD000CA0941 /* txth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = txth.c; sourceTree = ""; };
830165981F256BD000CA0941 /* ea_schl_fixed.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_schl_fixed.c; sourceTree = ""; };
830165991F256BD000CA0941 /* nds_strm_ffta2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_strm_ffta2.c; sourceTree = ""; };
- 830165A11F256BF400CA0941 /* hwas_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hwas_blocked.c; sourceTree = ""; };
+ 8306B08120984517000302D4 /* at3plus_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = at3plus_decoder.c; sourceTree = ""; };
+ 8306B08220984517000302D4 /* yamaha_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yamaha_decoder.c; sourceTree = ""; };
+ 8306B08320984517000302D4 /* fadpcm_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fadpcm_decoder.c; sourceTree = ""; };
+ 8306B0872098454C000302D4 /* blocked_bdsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_bdsp.c; sourceTree = ""; };
+ 8306B0882098454C000302D4 /* blocked_ast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ast.c; sourceTree = ""; };
+ 8306B0892098454D000302D4 /* segmented.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = segmented.c; sourceTree = ""; };
+ 8306B08A2098454D000302D4 /* blocked_ea_wve_au00.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ea_wve_au00.c; sourceTree = ""; };
+ 8306B08B2098454D000302D4 /* blocked_ea_wve_ad10.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ea_wve_ad10.c; sourceTree = ""; };
+ 8306B08C2098454D000302D4 /* blocked_xvas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_xvas.c; sourceTree = ""; };
+ 8306B08D2098454D000302D4 /* blocked_ps2_iab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ps2_iab.c; sourceTree = ""; };
+ 8306B08E2098454E000302D4 /* blocked_adm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_adm.c; sourceTree = ""; };
+ 8306B08F2098454E000302D4 /* blocked_sthd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_sthd.c; sourceTree = ""; };
+ 8306B0902098454E000302D4 /* layered.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = layered.c; sourceTree = ""; };
+ 8306B0912098454E000302D4 /* blocked_xa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_xa.c; sourceTree = ""; };
+ 8306B0922098454E000302D4 /* blocked_caf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_caf.c; sourceTree = ""; };
+ 8306B0932098454F000302D4 /* blocked_filp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_filp.c; sourceTree = ""; };
+ 8306B0942098454F000302D4 /* blocked_rws.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_rws.c; sourceTree = ""; };
+ 8306B0952098454F000302D4 /* blocked_ps2_strlr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ps2_strlr.c; sourceTree = ""; };
+ 8306B0962098454F000302D4 /* blocked_halpst.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_halpst.c; sourceTree = ""; };
+ 8306B0972098454F000302D4 /* blocked_mxch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_mxch.c; sourceTree = ""; };
+ 8306B09820984550000302D4 /* blocked_thp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_thp.c; sourceTree = ""; };
+ 8306B09920984550000302D4 /* blocked_tra.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_tra.c; sourceTree = ""; };
+ 8306B09A20984550000302D4 /* blocked_emff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_emff.c; sourceTree = ""; };
+ 8306B09B20984550000302D4 /* blocked_hwas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_hwas.c; sourceTree = ""; };
+ 8306B09C20984550000302D4 /* blocked_str_snds.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_str_snds.c; sourceTree = ""; };
+ 8306B09D20984551000302D4 /* blocked_ws_aud.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ws_aud.c; sourceTree = ""; };
+ 8306B09E20984551000302D4 /* blocked_matx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_matx.c; sourceTree = ""; };
+ 8306B09F20984551000302D4 /* blocked_wsi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_wsi.c; sourceTree = ""; };
+ 8306B0A020984551000302D4 /* blocked_gsb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_gsb.c; sourceTree = ""; };
+ 8306B0A120984551000302D4 /* blocked_vs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_vs.c; sourceTree = ""; };
+ 8306B0BD2098458B000302D4 /* ea_eaac_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ea_eaac_streamfile.h; sourceTree = ""; };
+ 8306B0BE2098458C000302D4 /* ngc_str_cauldron.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_str_cauldron.c; sourceTree = ""; };
+ 8306B0BF2098458C000302D4 /* ea_wve_au00.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_wve_au00.c; sourceTree = ""; };
+ 8306B0C02098458C000302D4 /* nxap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nxap.c; sourceTree = ""; };
+ 8306B0C12098458C000302D4 /* sthd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sthd.c; sourceTree = ""; };
+ 8306B0C22098458C000302D4 /* waf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = waf.c; sourceTree = ""; };
+ 8306B0C32098458C000302D4 /* awc_xma_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = awc_xma_streamfile.h; sourceTree = ""; };
+ 8306B0C42098458D000302D4 /* ea_wve_ad10.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_wve_ad10.c; sourceTree = ""; };
+ 8306B0C52098458D000302D4 /* ppst_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ppst_streamfile.h; sourceTree = ""; };
+ 8306B0C62098458D000302D4 /* ubi_lyn_ogg_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ubi_lyn_ogg_streamfile.h; sourceTree = ""; };
+ 8306B0C72098458D000302D4 /* smv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = smv.c; sourceTree = ""; };
+ 8306B0C82098458D000302D4 /* aax_utf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aax_utf.h; sourceTree = ""; };
+ 8306B0C92098458E000302D4 /* wave.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wave.c; sourceTree = ""; };
+ 8306B0CA2098458E000302D4 /* ubi_lyn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ubi_lyn.c; sourceTree = ""; };
+ 8306B0CB2098458E000302D4 /* msb_msh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = msb_msh.c; sourceTree = ""; };
+ 8306B0CC2098458E000302D4 /* opus_ppp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = opus_ppp.c; sourceTree = ""; };
+ 8306B0CD2098458E000302D4 /* opus_interleave_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opus_interleave_streamfile.h; sourceTree = ""; };
+ 8306B0CE2098458E000302D4 /* opus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = opus.c; sourceTree = ""; };
+ 8306B0CF2098458F000302D4 /* caf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = caf.c; sourceTree = ""; };
+ 8306B0D02098458F000302D4 /* wave_segmented.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wave_segmented.c; sourceTree = ""; };
+ 8306B0D12098458F000302D4 /* pcm_sre.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pcm_sre.c; sourceTree = ""; };
+ 8306B0D22098458F000302D4 /* txtp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = txtp.c; sourceTree = ""; };
+ 8306B0D32098458F000302D4 /* smc_smh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = smc_smh.c; sourceTree = ""; };
+ 8306B0D420984590000302D4 /* ubi_bao.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ubi_bao.c; sourceTree = ""; };
+ 8306B0D520984590000302D4 /* atsl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = atsl.c; sourceTree = ""; };
+ 8306B0D620984590000302D4 /* ppst.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ppst.c; sourceTree = ""; };
+ 8306B0D720984590000302D4 /* ubi_jade.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ubi_jade.c; sourceTree = ""; };
830EBD9220045F190023AA10 /* libatrac9.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libatrac9.xcodeproj; path = ../libatrac9/libatrac9.xcodeproj; sourceTree = ""; };
830EBE0F2004655D0023AA10 /* atrac9_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = atrac9_decoder.c; sourceTree = ""; };
830EBE112004656E0023AA10 /* xnb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xnb.c; sourceTree = ""; };
@@ -589,7 +667,6 @@
831BA6171EAC61A500CF89B0 /* x360_pasx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x360_pasx.c; sourceTree = ""; };
831BA6221EAC61CB00CF89B0 /* coding_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = coding_utils.c; sourceTree = ""; };
831BD11F1EEE1CF200198540 /* ngc_ulw.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ngc_ulw.c; sourceTree = ""; };
- 831BD1201EEE1D2A00198540 /* rws_blocked.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = rws_blocked.c; sourceTree = ""; };
832389481D22419B00482226 /* clHCA.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = clHCA.c; sourceTree = ""; };
832389491D22419B00482226 /* clHCA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = clHCA.h; sourceTree = ""; };
8323894F1D2246C300482226 /* hca.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hca.c; sourceTree = ""; };
@@ -599,7 +676,6 @@
83345A491F8AEAF900B2EAA4 /* ffmpeg_decoder_utils_switch_opus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffmpeg_decoder_utils_switch_opus.c; sourceTree = ""; };
83345A4B1F8AEB2700B2EAA4 /* nub_xma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nub_xma.c; sourceTree = ""; };
83345A4C1F8AEB2700B2EAA4 /* pc_al2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pc_al2.c; sourceTree = ""; };
- 83345A4D1F8AEB2800B2EAA4 /* nsw_opus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nsw_opus.c; sourceTree = ""; };
83345A4E1F8AEB2800B2EAA4 /* xvag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xvag.c; sourceTree = ""; };
833A7A2D1ED11961003EC53E /* xau.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xau.c; sourceTree = ""; };
8349A8DC1FE6251E00E26435 /* vorbis_custom_utils_vid1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_utils_vid1.c; sourceTree = ""; };
@@ -632,7 +708,6 @@
8349A9011FE6258000E26435 /* vxn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vxn.c; sourceTree = ""; };
8349A9021FE6258100E26435 /* adx_keys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = adx_keys.h; sourceTree = ""; };
8349A9031FE6258100E26435 /* mogg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mogg.c; sourceTree = ""; };
- 8349A9041FE6258100E26435 /* aax_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aax_streamfile.h; sourceTree = ""; };
8349A9051FE6258100E26435 /* bar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bar.c; sourceTree = ""; };
8349A9061FE6258100E26435 /* naac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = naac.c; sourceTree = ""; };
834D3A6D19F47C98001C54F6 /* g1l.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = g1l.c; sourceTree = ""; };
@@ -646,8 +721,6 @@
836F6DE018BDC2180095E648 /* acm_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = acm_decoder.c; sourceTree = ""; };
836F6DE118BDC2180095E648 /* acm_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = acm_decoder.h; sourceTree = ""; };
836F6DE218BDC2180095E648 /* adx_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adx_decoder.c; sourceTree = ""; };
- 836F6DE318BDC2180095E648 /* aica_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aica_decoder.c; sourceTree = ""; };
- 836F6DE418BDC2180095E648 /* at3_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = at3_decoder.c; sourceTree = ""; };
836F6DE518BDC2180095E648 /* coding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coding.h; sourceTree = ""; };
836F6DE718BDC2180095E648 /* g721_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = g721_decoder.c; sourceTree = ""; };
836F6DE818BDC2180095E648 /* g7221_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = g7221_decoder.c; sourceTree = ""; };
@@ -672,34 +745,11 @@
836F6DFC18BDC2180095E648 /* sdx2_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sdx2_decoder.c; sourceTree = ""; };
836F6DFD18BDC2180095E648 /* ws_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ws_decoder.c; sourceTree = ""; };
836F6DFE18BDC2180095E648 /* xa_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xa_decoder.c; sourceTree = ""; };
- 836F6E0018BDC2180095E648 /* aax_layout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aax_layout.c; sourceTree = ""; };
836F6E0118BDC2180095E648 /* aix_layout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aix_layout.c; sourceTree = ""; };
- 836F6E0218BDC2180095E648 /* ast_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ast_blocked.c; sourceTree = ""; };
- 836F6E0318BDC2180095E648 /* bdsp_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bdsp_blocked.c; sourceTree = ""; };
836F6E0418BDC2180095E648 /* blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked.c; sourceTree = ""; };
- 836F6E0518BDC2180095E648 /* caf_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = caf_blocked.c; sourceTree = ""; };
- 836F6E0818BDC2180095E648 /* emff_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = emff_blocked.c; sourceTree = ""; };
- 836F6E0918BDC2180095E648 /* filp_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filp_blocked.c; sourceTree = ""; };
- 836F6E0A18BDC2180095E648 /* gsb_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gsb_blocked.c; sourceTree = ""; };
- 836F6E0B18BDC2180095E648 /* halpst_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = halpst_blocked.c; sourceTree = ""; };
- 836F6E0C18BDC2180095E648 /* ims_block.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ims_block.c; sourceTree = ""; };
836F6E0D18BDC2180095E648 /* interleave.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = interleave.c; sourceTree = ""; };
836F6E1018BDC2180095E648 /* layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = layout.h; sourceTree = ""; };
- 836F6E1218BDC2180095E648 /* mus_acm_layout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mus_acm_layout.c; sourceTree = ""; };
- 836F6E1318BDC2180095E648 /* mxch_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mxch_blocked.c; sourceTree = ""; };
836F6E1418BDC2180095E648 /* nolayout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nolayout.c; sourceTree = ""; };
- 836F6E1518BDC2180095E648 /* ps2_adm_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_adm_blocked.c; sourceTree = ""; };
- 836F6E1618BDC2180095E648 /* ps2_iab_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_iab_blocked.c; sourceTree = ""; };
- 836F6E1718BDC2180095E648 /* ps2_strlr_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_strlr_blocked.c; sourceTree = ""; };
- 836F6E1918BDC2180095E648 /* scd_int_layout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scd_int_layout.c; sourceTree = ""; };
- 836F6E1A18BDC2180095E648 /* str_snds_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = str_snds_blocked.c; sourceTree = ""; };
- 836F6E1B18BDC2180095E648 /* thp_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = thp_blocked.c; sourceTree = ""; };
- 836F6E1C18BDC2180095E648 /* tra_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tra_blocked.c; sourceTree = ""; };
- 836F6E1D18BDC2180095E648 /* vs_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vs_blocked.c; sourceTree = ""; };
- 836F6E1E18BDC2180095E648 /* ws_aud_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ws_aud_blocked.c; sourceTree = ""; };
- 836F6E1F18BDC2180095E648 /* wsi_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wsi_blocked.c; sourceTree = ""; };
- 836F6E2018BDC2180095E648 /* xa_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xa_blocked.c; sourceTree = ""; };
- 836F6E2118BDC2180095E648 /* xvas_block.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xvas_block.c; sourceTree = ""; };
836F6E2918BDC2180095E648 /* 2dx9.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = 2dx9.c; sourceTree = ""; };
836F6E2A18BDC2180095E648 /* aax.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aax.c; sourceTree = ""; };
836F6E2B18BDC2180095E648 /* acm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = acm.c; sourceTree = ""; };
@@ -764,8 +814,6 @@
836F6E6C18BDC2180095E648 /* nds_swav.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_swav.c; sourceTree = ""; };
836F6E6D18BDC2180095E648 /* ngc_adpdtk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_adpdtk.c; sourceTree = ""; };
836F6E6E18BDC2180095E648 /* ngc_bh2pcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_bh2pcm.c; sourceTree = ""; };
- 836F6E6F18BDC2180095E648 /* ngc_bo2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_bo2.c; sourceTree = ""; };
- 836F6E7018BDC2180095E648 /* ngc_caf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_caf.c; sourceTree = ""; };
836F6E7118BDC2180095E648 /* ngc_dsp_konami.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_dsp_konami.c; sourceTree = ""; };
836F6E7218BDC2180095E648 /* ngc_dsp_mpds.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_dsp_mpds.c; sourceTree = ""; };
836F6E7318BDC2180095E648 /* ngc_dsp_std.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_dsp_std.c; sourceTree = ""; };
@@ -827,7 +875,6 @@
836F6EB218BDC2180095E648 /* ps2_p2bt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_p2bt.c; sourceTree = ""; };
836F6EB318BDC2180095E648 /* ps2_pnb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_pnb.c; sourceTree = ""; };
836F6EB418BDC2180095E648 /* ps2_psh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_psh.c; sourceTree = ""; };
- 836F6EB518BDC2180095E648 /* ps2_psw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_psw.c; sourceTree = ""; };
836F6EB618BDC2180095E648 /* ps2_rnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rnd.c; sourceTree = ""; };
836F6EB718BDC2180095E648 /* ps2_rstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rstm.c; sourceTree = ""; };
836F6EB818BDC2180095E648 /* rws.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rws.c; sourceTree = ""; };
@@ -910,7 +957,6 @@
836F6F0E18BDC2190095E648 /* xbox_wavm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xbox_wavm.c; sourceTree = ""; };
836F6F0F18BDC2190095E648 /* xbox_xmu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xbox_xmu.c; sourceTree = ""; };
836F6F1018BDC2190095E648 /* xbox_xvas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xbox_xvas.c; sourceTree = ""; };
- 836F6F1118BDC2190095E648 /* xbox_xwav.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xbox_xwav.c; sourceTree = ""; };
836F6F1218BDC2190095E648 /* xss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xss.c; sourceTree = ""; };
836F6F1318BDC2190095E648 /* xwb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xwb.c; sourceTree = ""; };
836F6F1418BDC2190095E648 /* ydsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ydsp.c; sourceTree = ""; };
@@ -928,7 +974,6 @@
83709E011ECBC1A4005C03D3 /* mss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mss.c; sourceTree = ""; };
83709E021ECBC1A4005C03D3 /* ps2_rxws.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rxws.c; sourceTree = ""; };
83709E031ECBC1A4005C03D3 /* ta_aac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ta_aac.c; sourceTree = ""; };
- 83709E041ECBC1A4005C03D3 /* waa_wac_wad_wam.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = waa_wac_wad_wam.c; sourceTree = ""; };
83709E0B1ECBC1C3005C03D3 /* mc3_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mc3_decoder.c; sourceTree = ""; };
83709E0C1ECBC1C3005C03D3 /* psv_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = psv_decoder.c; sourceTree = ""; };
8374EE361F787AB500033E90 /* ffmpeg_decoder_utils_ea_xma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffmpeg_decoder_utils_ea_xma.c; sourceTree = ""; };
@@ -965,7 +1010,6 @@
83A21F7D201D8980000F04B9 /* xwc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xwc.c; sourceTree = ""; };
83A21F7E201D8980000F04B9 /* fsb_keys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fsb_keys.h; sourceTree = ""; };
83A21F7F201D8980000F04B9 /* ogg_vorbis.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ogg_vorbis.c; sourceTree = ""; };
- 83A21F80201D8980000F04B9 /* atsl3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = atsl3.c; sourceTree = ""; };
83A21F81201D8981000F04B9 /* fsb_encrypted.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fsb_encrypted.c; sourceTree = ""; };
83A21F82201D8981000F04B9 /* sps_n1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sps_n1.c; sourceTree = ""; };
83A21F83201D8981000F04B9 /* kma9.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kma9.c; sourceTree = ""; };
@@ -1153,14 +1197,14 @@
836F6DE018BDC2180095E648 /* acm_decoder.c */,
836F6DE118BDC2180095E648 /* acm_decoder.h */,
836F6DE218BDC2180095E648 /* adx_decoder.c */,
- 836F6DE318BDC2180095E648 /* aica_decoder.c */,
- 836F6DE418BDC2180095E648 /* at3_decoder.c */,
+ 8306B08120984517000302D4 /* at3plus_decoder.c */,
830EBE0F2004655D0023AA10 /* atrac9_decoder.c */,
831BA6221EAC61CB00CF89B0 /* coding_utils.c */,
836F6DE518BDC2180095E648 /* coding.h */,
8349A8DE1FE6251F00E26435 /* ea_mt_decoder.c */,
83AA5D0E1F6E2F5F0020821C /* ea_xa_decoder.c */,
83AA5D151F6E2F600020821C /* ea_xas_decoder.c */,
+ 8306B08320984517000302D4 /* fadpcm_decoder.c */,
8374EE361F787AB500033E90 /* ffmpeg_decoder_utils_ea_xma.c */,
83345A491F8AEAF900B2EAA4 /* ffmpeg_decoder_utils_switch_opus.c */,
8374EE3D1F787AB600033E90 /* ffmpeg_decoder_utils.c */,
@@ -1208,6 +1252,7 @@
839E21D81F2EDAF000EE54D7 /* vorbis_custom_utils_wwise.c */,
836F6DFD18BDC2180095E648 /* ws_decoder.c */,
836F6DFE18BDC2180095E648 /* xa_decoder.c */,
+ 8306B08220984517000302D4 /* yamaha_decoder.c */,
);
path = coding;
sourceTree = "";
@@ -1215,46 +1260,48 @@
836F6DFF18BDC2180095E648 /* layout */ = {
isa = PBXGroup;
children = (
- 836F6E0018BDC2180095E648 /* aax_layout.c */,
836F6E0118BDC2180095E648 /* aix_layout.c */,
- 836F6E0218BDC2180095E648 /* ast_blocked.c */,
- 836F6E0318BDC2180095E648 /* bdsp_blocked.c */,
+ 8306B08E2098454E000302D4 /* blocked_adm.c */,
+ 8306B0882098454C000302D4 /* blocked_ast.c */,
83AA5D1B1F6E2F7F0020821C /* blocked_awc.c */,
+ 8306B0872098454C000302D4 /* blocked_bdsp.c */,
+ 8306B0922098454E000302D4 /* blocked_caf.c */,
8349A8E21FE6253800E26435 /* blocked_dec.c */,
8349A8E31FE6253800E26435 /* blocked_ea_1snh.c */,
8349A8E41FE6253800E26435 /* blocked_ea_schl.c */,
8349A8E71FE6253900E26435 /* blocked_ea_sns.c */,
83EED5D5203A8BD7008BEB45 /* blocked_ea_swvr.c */,
+ 8306B08B2098454D000302D4 /* blocked_ea_wve_ad10.c */,
+ 8306B08A2098454D000302D4 /* blocked_ea_wve_au00.c */,
+ 8306B09A20984550000302D4 /* blocked_emff.c */,
+ 8306B0932098454F000302D4 /* blocked_filp.c */,
+ 8306B0A020984551000302D4 /* blocked_gsb.c */,
+ 8306B0962098454F000302D4 /* blocked_halpst.c */,
+ 8306B09B20984550000302D4 /* blocked_hwas.c */,
8349A8E51FE6253800E26435 /* blocked_ivaud.c */,
+ 8306B09E20984551000302D4 /* blocked_matx.c */,
+ 8306B0972098454F000302D4 /* blocked_mxch.c */,
+ 8306B08D2098454D000302D4 /* blocked_ps2_iab.c */,
+ 8306B0952098454F000302D4 /* blocked_ps2_strlr.c */,
+ 8306B0942098454F000302D4 /* blocked_rws.c */,
+ 8306B08F2098454E000302D4 /* blocked_sthd.c */,
+ 8306B09C20984550000302D4 /* blocked_str_snds.c */,
+ 8306B09820984550000302D4 /* blocked_thp.c */,
+ 8306B09920984550000302D4 /* blocked_tra.c */,
8349A8E61FE6253900E26435 /* blocked_vawx.c */,
83AA5D1A1F6E2F7F0020821C /* blocked_vgs.c */,
+ 8306B0A120984551000302D4 /* blocked_vs.c */,
+ 8306B09D20984551000302D4 /* blocked_ws_aud.c */,
+ 8306B09F20984551000302D4 /* blocked_wsi.c */,
+ 8306B0912098454E000302D4 /* blocked_xa.c */,
83A21F7A201D895B000F04B9 /* blocked_xvag.c */,
+ 8306B08C2098454D000302D4 /* blocked_xvas.c */,
836F6E0418BDC2180095E648 /* blocked.c */,
- 836F6E0518BDC2180095E648 /* caf_blocked.c */,
- 836F6E0818BDC2180095E648 /* emff_blocked.c */,
- 836F6E0918BDC2180095E648 /* filp_blocked.c */,
- 836F6E0A18BDC2180095E648 /* gsb_blocked.c */,
- 836F6E0B18BDC2180095E648 /* halpst_blocked.c */,
- 830165A11F256BF400CA0941 /* hwas_blocked.c */,
- 836F6E0C18BDC2180095E648 /* ims_block.c */,
836F6E0D18BDC2180095E648 /* interleave.c */,
+ 8306B0902098454E000302D4 /* layered.c */,
836F6E1018BDC2180095E648 /* layout.h */,
- 836F6E1218BDC2180095E648 /* mus_acm_layout.c */,
- 836F6E1318BDC2180095E648 /* mxch_blocked.c */,
836F6E1418BDC2180095E648 /* nolayout.c */,
- 836F6E1518BDC2180095E648 /* ps2_adm_blocked.c */,
- 836F6E1618BDC2180095E648 /* ps2_iab_blocked.c */,
- 836F6E1718BDC2180095E648 /* ps2_strlr_blocked.c */,
- 831BD1201EEE1D2A00198540 /* rws_blocked.c */,
- 836F6E1918BDC2180095E648 /* scd_int_layout.c */,
- 836F6E1A18BDC2180095E648 /* str_snds_blocked.c */,
- 836F6E1B18BDC2180095E648 /* thp_blocked.c */,
- 836F6E1C18BDC2180095E648 /* tra_blocked.c */,
- 836F6E1D18BDC2180095E648 /* vs_blocked.c */,
- 836F6E1E18BDC2180095E648 /* ws_aud_blocked.c */,
- 836F6E1F18BDC2180095E648 /* wsi_blocked.c */,
- 836F6E2018BDC2180095E648 /* xa_blocked.c */,
- 836F6E2118BDC2180095E648 /* xvas_block.c */,
+ 8306B0892098454D000302D4 /* segmented.c */,
);
path = layout;
sourceTree = "";
@@ -1263,7 +1310,7 @@
isa = PBXGroup;
children = (
836F6E2918BDC2180095E648 /* 2dx9.c */,
- 8349A9041FE6258100E26435 /* aax_streamfile.h */,
+ 8306B0C82098458D000302D4 /* aax_utf.h */,
836F6E2A18BDC2180095E648 /* aax.c */,
836F6E2B18BDC2180095E648 /* acm.c */,
836F6E2C18BDC2180095E648 /* ads.c */,
@@ -1278,9 +1325,10 @@
836F6E3318BDC2180095E648 /* akb.c */,
836F6E3418BDC2180095E648 /* apple_caff.c */,
836F6E3518BDC2180095E648 /* ast.c */,
- 83A21F80201D8980000F04B9 /* atsl3.c */,
+ 8306B0D520984590000302D4 /* atsl.c */,
83A21F7C201D897F000F04B9 /* atx.c */,
83EED5D2203A8BC7008BEB45 /* aus.c */,
+ 8306B0C32098458C000302D4 /* awc_xma_streamfile.h */,
83AA5D201F6E2F9B0020821C /* awc.c */,
836F6E3618BDC2180095E648 /* baf.c */,
8349A8F81FE6257E00E26435 /* bar_streamfile.h */,
@@ -1293,6 +1341,7 @@
836F6E3918BDC2180095E648 /* bnsf.c */,
836F6E3A18BDC2180095E648 /* brstm.c */,
83EDE5D71A70951A005F5D84 /* btsnd.c */,
+ 8306B0CF2098458F000302D4 /* caf.c */,
836F6E3B18BDC2180095E648 /* capdsp.c */,
836F6E3C18BDC2180095E648 /* Cstr.c */,
836F6E3D18BDC2180095E648 /* dc_asd.c */,
@@ -1306,10 +1355,13 @@
836F6E4418BDC2180095E648 /* dsp_bdsp.c */,
836F6E4518BDC2180095E648 /* dsp_sth_str.c */,
8349A8FF1FE6258000E26435 /* ea_1snh.c */,
+ 8306B0BD2098458B000302D4 /* ea_eaac_streamfile.h */,
8349A8F71FE6257E00E26435 /* ea_eaac.c */,
830165981F256BD000CA0941 /* ea_schl_fixed.c */,
836F6E4618BDC2180095E648 /* ea_schl.c */,
83EED5D1203A8BC7008BEB45 /* ea_swvr.c */,
+ 8306B0C42098458D000302D4 /* ea_wve_ad10.c */,
+ 8306B0BF2098458C000302D4 /* ea_wve_au00.c */,
836F6E4818BDC2180095E648 /* emff.c */,
836F6E4918BDC2180095E648 /* exakt_sc.c */,
836F6E4A18BDC2180095E648 /* excitebots.c */,
@@ -1348,6 +1400,7 @@
836F6E5F18BDC2180095E648 /* mn_str.c */,
8349A9031FE6258100E26435 /* mogg.c */,
836F6E6018BDC2180095E648 /* mp4.c */,
+ 8306B0CB2098458E000302D4 /* msb_msh.c */,
83709E011ECBC1A4005C03D3 /* mss.c */,
836F6E6118BDC2180095E648 /* msvp.c */,
836F6E6218BDC2180095E648 /* mus_acm.c */,
@@ -1365,8 +1418,6 @@
836F6E6C18BDC2180095E648 /* nds_swav.c */,
836F6E6D18BDC2180095E648 /* ngc_adpdtk.c */,
836F6E6E18BDC2180095E648 /* ngc_bh2pcm.c */,
- 836F6E6F18BDC2180095E648 /* ngc_bo2.c */,
- 836F6E7018BDC2180095E648 /* ngc_caf.c */,
836F6E7118BDC2180095E648 /* ngc_dsp_konami.c */,
836F6E7218BDC2180095E648 /* ngc_dsp_mpds.c */,
836F6E7318BDC2180095E648 /* ngc_dsp_std.c */,
@@ -1378,18 +1429,22 @@
836F6E7918BDC2180095E648 /* ngc_pdt.c */,
836F6E7A18BDC2180095E648 /* ngc_sck_dsp.c */,
836F6E7B18BDC2180095E648 /* ngc_ssm.c */,
+ 8306B0BE2098458C000302D4 /* ngc_str_cauldron.c */,
836F6E7C18BDC2180095E648 /* ngc_tydsp.c */,
831BD11F1EEE1CF200198540 /* ngc_ulw.c */,
8349A8FA1FE6257E00E26435 /* ngc_vid1.c */,
836F6E7E18BDC2180095E648 /* ngc_ymf.c */,
836F6E7F18BDC2180095E648 /* ngca.c */,
- 83345A4D1F8AEB2800B2EAA4 /* nsw_opus.c */,
83AB8C731E8072A100086084 /* nub_vag.c */,
83345A4B1F8AEB2700B2EAA4 /* nub_xma.c */,
836F6E8118BDC2180095E648 /* nwa.c */,
+ 8306B0C02098458C000302D4 /* nxap.c */,
83A21F7F201D8980000F04B9 /* ogg_vorbis.c */,
831BA60F1EAC61A500CF89B0 /* ogl.c */,
8349A8FB1FE6257F00E26435 /* omu.c */,
+ 8306B0CD2098458E000302D4 /* opus_interleave_streamfile.h */,
+ 8306B0CC2098458E000302D4 /* opus_ppp.c */,
+ 8306B0CE2098458E000302D4 /* opus.c */,
836F6E8318BDC2180095E648 /* otm.c */,
836F6E8418BDC2180095E648 /* p3d.c */,
8349A8FE1FE6257F00E26435 /* pc_adp_otns.c */,
@@ -1400,8 +1455,11 @@
836F6E8718BDC2180095E648 /* pc_smp.c */,
836F6E8818BDC2180095E648 /* pc_snds.c */,
83CAB8DC1F0B0744001BC993 /* pc_xa30.c */,
+ 8306B0D12098458F000302D4 /* pcm_sre.c */,
836F6E8B18BDC2180095E648 /* pona.c */,
836F6E8C18BDC2180095E648 /* pos.c */,
+ 8306B0C52098458D000302D4 /* ppst_streamfile.h */,
+ 8306B0D620984590000302D4 /* ppst.c */,
836F6E8D18BDC2180095E648 /* ps2_2pfs.c */,
836F6E8E18BDC2180095E648 /* ps2_adm.c */,
836F6E8F18BDC2180095E648 /* ps2_ads.c */,
@@ -1441,7 +1499,6 @@
8349A8F21FE6257D00E26435 /* ps2_pcm.c */,
836F6EB318BDC2180095E648 /* ps2_pnb.c */,
836F6EB418BDC2180095E648 /* ps2_psh.c */,
- 836F6EB518BDC2180095E648 /* ps2_psw.c */,
836F6EB618BDC2180095E648 /* ps2_rnd.c */,
836F6EB718BDC2180095E648 /* ps2_rstm.c */,
83709E021ECBC1A4005C03D3 /* ps2_rxws.c */,
@@ -1505,11 +1562,14 @@
831BA6111EAC61A500CF89B0 /* sgxd.c */,
839E21EA1F2EDB0500EE54D7 /* sk_aud.c */,
836F6EF218BDC2190095E648 /* sli.c */,
+ 8306B0D32098458F000302D4 /* smc_smh.c */,
+ 8306B0C72098458D000302D4 /* smv.c */,
83A21F82201D8981000F04B9 /* sps_n1.c */,
836F6EF318BDC2190095E648 /* spt_spd.c */,
8349A8F31FE6257D00E26435 /* sqex_scd_streamfile.h */,
836F6EF418BDC2190095E648 /* sqex_scd.c */,
83A21F84201D8981000F04B9 /* sqex_sead.c */,
+ 8306B0C12098458C000302D4 /* sthd.c */,
83AA5D231F6E2F9C0020821C /* stm.c */,
836F6EF618BDC2190095E648 /* str_asr.c */,
836F6EF718BDC2190095E648 /* str_snds.c */,
@@ -1520,7 +1580,12 @@
836F6EFA18BDC2190095E648 /* thp.c */,
836F6EFB18BDC2190095E648 /* tun.c */,
830165971F256BD000CA0941 /* txth.c */,
+ 8306B0D22098458F000302D4 /* txtp.c */,
+ 8306B0D420984590000302D4 /* ubi_bao.c */,
836F6EFC18BDC2190095E648 /* ubi_ckd.c */,
+ 8306B0D720984590000302D4 /* ubi_jade.c */,
+ 8306B0C62098458D000302D4 /* ubi_lyn_ogg_streamfile.h */,
+ 8306B0CA2098458E000302D4 /* ubi_lyn.c */,
831BA6131EAC61A500CF89B0 /* ubi_raki.c */,
8349A8F41FE6257D00E26435 /* ubi_sb.c */,
831BA6141EAC61A500CF89B0 /* vawx.c */,
@@ -1529,7 +1594,9 @@
8349A8F91FE6257E00E26435 /* vsf_tta.c */,
836F6EFF18BDC2190095E648 /* vsf.c */,
8349A9011FE6258000E26435 /* vxn.c */,
- 83709E041ECBC1A4005C03D3 /* waa_wac_wad_wam.c */,
+ 8306B0C22098458C000302D4 /* waf.c */,
+ 8306B0D02098458F000302D4 /* wave_segmented.c */,
+ 8306B0C92098458E000302D4 /* wave.c */,
83CAB8E11F0B0745001BC993 /* wii_04sw.c */,
836F6F0018BDC2190095E648 /* wii_bns.c */,
836F6F0118BDC2190095E648 /* wii_mus.c */,
@@ -1552,7 +1619,6 @@
836F6F0E18BDC2190095E648 /* xbox_wavm.c */,
836F6F0F18BDC2190095E648 /* xbox_xmu.c */,
836F6F1018BDC2190095E648 /* xbox_xvas.c */,
- 836F6F1118BDC2190095E648 /* xbox_xwav.c */,
8350C0541E071881009E0A93 /* xma.c */,
830EBE112004656E0023AA10 /* xnb.c */,
836F6F1218BDC2190095E648 /* xss.c */,
@@ -1603,11 +1669,11 @@
836F705518BDC2190095E648 /* streamtypes.h in Headers */,
836F6F1F18BDC2190095E648 /* acm_decoder.h in Headers */,
836F6F3518BDC2190095E648 /* nwa_decoder.h in Headers */,
- 8349A91D1FE6258200E26435 /* aax_streamfile.h in Headers */,
83A21F87201D8981000F04B9 /* fsb_keys.h in Headers */,
8349A90F1FE6258200E26435 /* aix_streamfile.h in Headers */,
8349A9111FE6258200E26435 /* bar_streamfile.h in Headers */,
836F6F2718BDC2190095E648 /* g72x_state.h in Headers */,
+ 8306B0E020984590000302D4 /* ppst_streamfile.h in Headers */,
839E21E01F2EDAF100EE54D7 /* vorbis_custom_data_fsb.h in Headers */,
836F705418BDC2190095E648 /* streamfile.h in Headers */,
8374EE401F787AB600033E90 /* ffmpeg_decoder_utils.h in Headers */,
@@ -1615,11 +1681,16 @@
8323894B1D22419B00482226 /* clHCA.h in Headers */,
839E21E81F2EDAF100EE54D7 /* mpeg_decoder.h in Headers */,
839E21E51F2EDAF100EE54D7 /* vorbis_custom_decoder.h in Headers */,
+ 8306B0E320984590000302D4 /* aax_utf.h in Headers */,
+ 8306B0E120984590000302D4 /* ubi_lyn_ogg_streamfile.h in Headers */,
836F705918BDC2190095E648 /* vgmstream.h in Headers */,
+ 8306B0DE20984590000302D4 /* awc_xma_streamfile.h in Headers */,
839E21E61F2EDAF100EE54D7 /* vorbis_custom_data_wwise.h in Headers */,
48C2650F1A5D420800A0A3D6 /* vorbisfile.h in Headers */,
836F705718BDC2190095E648 /* util.h in Headers */,
836F6F9A18BDC2190095E648 /* meta.h in Headers */,
+ 8306B0D820984590000302D4 /* ea_eaac_streamfile.h in Headers */,
+ 8306B0E820984590000302D4 /* opus_interleave_streamfile.h in Headers */,
8349A90C1FE6258200E26435 /* sqex_scd_streamfile.h in Headers */,
8349A91B1FE6258200E26435 /* adx_keys.h in Headers */,
836F6F4D18BDC2190095E648 /* layout.h in Headers */,
@@ -1787,12 +1858,14 @@
files = (
839E21E21F2EDAF100EE54D7 /* vorbis_custom_utils_wwise.c in Sources */,
83E56BA51F2EE3520026BC60 /* vorbis_custom_utils_ogl.c in Sources */,
+ 8306B0B020984552000302D4 /* blocked_ps2_strlr.c in Sources */,
8349A9071FE6258200E26435 /* dec.c in Sources */,
839E21E91F2EDAF100EE54D7 /* vorbis_custom_utils_sk.c in Sources */,
839E21E41F2EDAF100EE54D7 /* vorbis_custom_utils_fsb.c in Sources */,
839E21E11F2EDAF100EE54D7 /* vorbis_custom_decoder.c in Sources */,
839E21E71F2EDAF100EE54D7 /* mpeg_custom_utils.c in Sources */,
839E21E31F2EDAF100EE54D7 /* mpeg_custom_utils_ahx.c in Sources */,
+ 8306B0AF20984552000302D4 /* blocked_rws.c in Sources */,
839E21EB1F2EDB0600EE54D7 /* sk_aud.c in Sources */,
8301659A1F256BD000CA0941 /* txth.c in Sources */,
8301659B1F256BD000CA0941 /* ea_schl_fixed.c in Sources */,
@@ -1801,16 +1874,14 @@
83CAB8E21F0B0752001BC993 /* wii_04sw.c in Sources */,
8349A8DF1FE6251F00E26435 /* vorbis_custom_utils_vid1.c in Sources */,
83A21F8D201D8982000F04B9 /* sqex_sead.c in Sources */,
- 839B54571EEE1DA000048A2D /* rws_blocked.c in Sources */,
83EED5D3203A8BC7008BEB45 /* ea_swvr.c in Sources */,
839B54521EEE1D9600048A2D /* ngc_ulw.c in Sources */,
+ 8306B0EE20984590000302D4 /* smc_smh.c in Sources */,
836F6FAD18BDC2190095E648 /* ngc_dsp_konami.c in Sources */,
836F6FF818BDC2190095E648 /* ps2_smpl.c in Sources */,
836F6F8118BDC2190095E648 /* dsp_sth_str.c in Sources */,
- 836F6F5E18BDC2190095E648 /* xvas_block.c in Sources */,
836F703818BDC2190095E648 /* ubi_ckd.c in Sources */,
836F705318BDC2190095E648 /* streamfile.c in Sources */,
- 836F6F5C18BDC2190095E648 /* wsi_blocked.c in Sources */,
836F6F7418BDC2190095E648 /* bgw.c in Sources */,
836F6F7218BDC2190095E648 /* baf.c in Sources */,
83F5F8831908D0A400C8E65F /* fsb5.c in Sources */,
@@ -1825,7 +1896,7 @@
836F6F2F18BDC2190095E648 /* mtaf_decoder.c in Sources */,
83AA5D161F6E2F600020821C /* ea_xa_decoder.c in Sources */,
836F6F9B18BDC2190095E648 /* mn_str.c in Sources */,
- 836F6F5918BDC2190095E648 /* tra_blocked.c in Sources */,
+ 8306B0EB20984590000302D4 /* wave_segmented.c in Sources */,
836F6F9F18BDC2190095E648 /* musc.c in Sources */,
8349A9121FE6258200E26435 /* vsf_tta.c in Sources */,
836F6FCA18BDC2190095E648 /* ps2_adm.c in Sources */,
@@ -1837,26 +1908,30 @@
836F700018BDC2190095E648 /* ps2_svag.c in Sources */,
836F6FB618BDC2190095E648 /* ngc_sck_dsp.c in Sources */,
836F6F2818BDC2190095E648 /* ima_decoder.c in Sources */,
+ 8306B0DD20984590000302D4 /* waf.c in Sources */,
+ 8306B0B320984552000302D4 /* blocked_thp.c in Sources */,
836F702318BDC2190095E648 /* rsf.c in Sources */,
83299FD01E7660C7003A3242 /* bik.c in Sources */,
836F6F3318BDC2190095E648 /* ngc_dtk_decoder.c in Sources */,
+ 8306B0EF20984590000302D4 /* ubi_bao.c in Sources */,
836F6FBB18BDC2190095E648 /* ngca.c in Sources */,
+ 8306B0E220984590000302D4 /* smv.c in Sources */,
8349A91E1FE6258200E26435 /* bar.c in Sources */,
- 836F6F5218BDC2190095E648 /* ps2_adm_blocked.c in Sources */,
832389521D224C0800482226 /* hca_decoder.c in Sources */,
836F6F9418BDC2190095E648 /* ivb.c in Sources */,
- 836F6FF118BDC2190095E648 /* ps2_psw.c in Sources */,
836F6F8D18BDC2190095E648 /* gsp_gsb.c in Sources */,
836F704518BDC2190095E648 /* wvs.c in Sources */,
- 836F6F2218BDC2190095E648 /* at3_decoder.c in Sources */,
83EDE5D91A70951A005F5D84 /* btsnd.c in Sources */,
+ 8306B0E420984590000302D4 /* wave.c in Sources */,
836F6FFC18BDC2190095E648 /* ps2_ster.c in Sources */,
8349A9171FE6258200E26435 /* pc_adp_otns.c in Sources */,
836F701E18BDC2190095E648 /* redspark.c in Sources */,
+ 8306B0ED20984590000302D4 /* txtp.c in Sources */,
836F6FA018BDC2190095E648 /* musx.c in Sources */,
836F705818BDC2190095E648 /* vgmstream.c in Sources */,
8349A90A1FE6258200E26435 /* sab.c in Sources */,
836F6F6818BDC2190095E648 /* ads.c in Sources */,
+ 8306B08620984518000302D4 /* fadpcm_decoder.c in Sources */,
83AB8C761E8072A100086084 /* x360_ast.c in Sources */,
836F6F8B18BDC2190095E648 /* genh.c in Sources */,
8349A8EA1FE6253900E26435 /* blocked_ea_schl.c in Sources */,
@@ -1866,6 +1941,7 @@
836F703C18BDC2190095E648 /* wii_bns.c in Sources */,
830EBE132004656E0023AA10 /* xnb.c in Sources */,
835027131ED119E000C25929 /* mta2_decoder.c in Sources */,
+ 8306B0DB20984590000302D4 /* nxap.c in Sources */,
836F6FA718BDC2190095E648 /* nds_strm.c in Sources */,
8349A91A1FE6258200E26435 /* vxn.c in Sources */,
8349A8EB1FE6253900E26435 /* blocked_ivaud.c in Sources */,
@@ -1875,43 +1951,44 @@
8349A9141FE6258200E26435 /* omu.c in Sources */,
836F6FE418BDC2190095E648 /* ps2_leg.c in Sources */,
836F705618BDC2190095E648 /* util.c in Sources */,
+ 8306B0A820984552000302D4 /* blocked_ps2_iab.c in Sources */,
+ 8306B0EA20984590000302D4 /* caf.c in Sources */,
836F703618BDC2190095E648 /* thp.c in Sources */,
836F6F7818BDC2190095E648 /* Cstr.c in Sources */,
836F6F1E18BDC2190095E648 /* acm_decoder.c in Sources */,
836F6FD818BDC2190095E648 /* ps2_gbts.c in Sources */,
- 83709E0A1ECBC1A4005C03D3 /* waa_wac_wad_wam.c in Sources */,
836F6F7A18BDC2190095E648 /* dc_dcsw_dcs.c in Sources */,
- 836F6F5318BDC2190095E648 /* ps2_iab_blocked.c in Sources */,
831BA61A1EAC61A500CF89B0 /* ps2_vds_vdm.c in Sources */,
836F6FF218BDC2190095E648 /* ps2_rnd.c in Sources */,
83709E0D1ECBC1C3005C03D3 /* mc3_decoder.c in Sources */,
836F6FA818BDC2190095E648 /* nds_swav.c in Sources */,
- 836F6F3F18BDC2190095E648 /* ast_blocked.c in Sources */,
8374EE411F787AB600033E90 /* ffmpeg_decoder_utils.c in Sources */,
+ 8306B0D920984590000302D4 /* ngc_str_cauldron.c in Sources */,
833A7A2E1ED11961003EC53E /* xau.c in Sources */,
- 836F6F5018BDC2190095E648 /* mxch_blocked.c in Sources */,
836F6FB518BDC2190095E648 /* ngc_pdt.c in Sources */,
- 836F6F4F18BDC2190095E648 /* mus_acm_layout.c in Sources */,
- 836F6F4218BDC2190095E648 /* caf_blocked.c in Sources */,
836F6F6C18BDC2190095E648 /* ahx.c in Sources */,
83AB8C751E8072A100086084 /* nub_vag.c in Sources */,
836F702D18BDC2190095E648 /* sfl.c in Sources */,
836F6FEC18BDC2190095E648 /* ps2_mtaf.c in Sources */,
83D7318C1A749EEE00CA1366 /* g719_decoder.c in Sources */,
836F701118BDC2190095E648 /* ps3_cps.c in Sources */,
+ 8306B0DA20984590000302D4 /* ea_wve_au00.c in Sources */,
83A21F85201D8981000F04B9 /* atx.c in Sources */,
+ 8306B0E720984590000302D4 /* opus_ppp.c in Sources */,
836F701418BDC2190095E648 /* ps3_msf.c in Sources */,
836F6F6518BDC2190095E648 /* 2dx9.c in Sources */,
830EBE102004655D0023AA10 /* atrac9_decoder.c in Sources */,
836F700818BDC2190095E648 /* ps2_vms.c in Sources */,
836F702418BDC2190095E648 /* rwsd.c in Sources */,
830EBE142004656E0023AA10 /* ktss.c in Sources */,
- 836F6F5618BDC2190095E648 /* scd_int_layout.c in Sources */,
836F6F6618BDC2190095E648 /* aax.c in Sources */,
836F6FD618BDC2190095E648 /* ps2_exst.c in Sources */,
+ 8306B0BC20984552000302D4 /* blocked_vs.c in Sources */,
836F6F6718BDC2190095E648 /* acm.c in Sources */,
+ 8306B0DF20984590000302D4 /* ea_wve_ad10.c in Sources */,
836F6F8A18BDC2190095E648 /* gcsw.c in Sources */,
836F6F9C18BDC2190095E648 /* mp4.c in Sources */,
+ 8306B0A720984552000302D4 /* blocked_xvas.c in Sources */,
8349A9101FE6258200E26435 /* ea_eaac.c in Sources */,
836F700F18BDC2190095E648 /* ps2_xa30.c in Sources */,
8349A8ED1FE6253900E26435 /* blocked_ea_sns.c in Sources */,
@@ -1923,6 +2000,7 @@
83709E071ECBC1A4005C03D3 /* mss.c in Sources */,
836F6F8F18BDC2190095E648 /* his.c in Sources */,
836F6FE218BDC2190095E648 /* ps2_kces.c in Sources */,
+ 8306B08520984518000302D4 /* yamaha_decoder.c in Sources */,
836F6FEF18BDC2190095E648 /* ps2_pnb.c in Sources */,
836F6FCB18BDC2190095E648 /* ps2_ads.c in Sources */,
836F6FD318BDC2190095E648 /* ps2_ccc.c in Sources */,
@@ -1930,7 +2008,9 @@
83345A521F8AEB2800B2EAA4 /* xvag.c in Sources */,
836F704C18BDC2190095E648 /* xbox_xvas.c in Sources */,
836F6F3918BDC2190095E648 /* SASSC_decoder.c in Sources */,
+ 8306B0A920984552000302D4 /* blocked_adm.c in Sources */,
836F703A18BDC2190095E648 /* vs.c in Sources */,
+ 8306B0F220984590000302D4 /* ubi_jade.c in Sources */,
836F6FF918BDC2190095E648 /* ps2_snd.c in Sources */,
836F6F9018BDC2190095E648 /* idsp.c in Sources */,
836F6F2918BDC2190095E648 /* l5_555_decoder.c in Sources */,
@@ -1940,7 +2020,6 @@
836F6FC118BDC2190095E648 /* pc_adp.c in Sources */,
836F701A18BDC2190095E648 /* psx_fag.c in Sources */,
836F703B18BDC2190095E648 /* vsf.c in Sources */,
- 836F6F3D18BDC2190095E648 /* aax_layout.c in Sources */,
836F6F8218BDC2190095E648 /* ea_schl.c in Sources */,
836F700A18BDC2190095E648 /* ps2_vpk.c in Sources */,
836F6F7318BDC2190095E648 /* bcstm.c in Sources */,
@@ -1951,32 +2030,34 @@
836F6F3218BDC2190095E648 /* ngc_dsp_decoder.c in Sources */,
836F704218BDC2190095E648 /* wii_sts.c in Sources */,
836F703918BDC2190095E648 /* vgs.c in Sources */,
- 830165A21F256BF400CA0941 /* hwas_blocked.c in Sources */,
836F6F2C18BDC2190095E648 /* mp4_aac_decoder.c in Sources */,
836F701F18BDC2190095E648 /* riff.c in Sources */,
83AA5D191F6E2F600020821C /* ea_xas_decoder.c in Sources */,
836F6F9318BDC2190095E648 /* ivaud.c in Sources */,
836F6F8518BDC2190095E648 /* exakt_sc.c in Sources */,
836F6FA618BDC2190095E648 /* nds_sad.c in Sources */,
+ 8306B0F120984590000302D4 /* ppst.c in Sources */,
836F702B18BDC2190095E648 /* sdt.c in Sources */,
836F6FDA18BDC2190095E648 /* ps2_hgc1.c in Sources */,
836F702C18BDC2190095E648 /* seg.c in Sources */,
836F700918BDC2190095E648 /* ps2_voi.c in Sources */,
836F6F3E18BDC2190095E648 /* aix_layout.c in Sources */,
836F6FE018BDC2190095E648 /* ps2_joe.c in Sources */,
+ 8306B0A220984552000302D4 /* blocked_bdsp.c in Sources */,
836F700118BDC2190095E648 /* ps2_tec.c in Sources */,
- 836F6F4718BDC2190095E648 /* gsb_blocked.c in Sources */,
836F703018BDC2190095E648 /* sqex_scd.c in Sources */,
+ 8306B0A320984552000302D4 /* blocked_ast.c in Sources */,
836F6FD518BDC2190095E648 /* ps2_enth.c in Sources */,
+ 8306B0DC20984590000302D4 /* sthd.c in Sources */,
836F6FAE18BDC2190095E648 /* ngc_dsp_mpds.c in Sources */,
836F705218BDC2190095E648 /* zwdsp.c in Sources */,
836F6FFB18BDC2190095E648 /* ps2_sps.c in Sources */,
836F6FFF18BDC2190095E648 /* ps2_strlr.c in Sources */,
836F6F2018BDC2190095E648 /* adx_decoder.c in Sources */,
8349A8EC1FE6253900E26435 /* blocked_vawx.c in Sources */,
- 836F6F4018BDC2190095E648 /* bdsp_blocked.c in Sources */,
836F700418BDC2190095E648 /* ps2_vas.c in Sources */,
836F6F9818BDC2190095E648 /* mattel_hyperscan.c in Sources */,
+ 8306B0BA20984552000302D4 /* blocked_wsi.c in Sources */,
83BAFB6C19F45EB3005DAB60 /* bfstm.c in Sources */,
836F704418BDC2190095E648 /* ws_aud.c in Sources */,
83709E081ECBC1A4005C03D3 /* ps2_rxws.c in Sources */,
@@ -1990,36 +2071,35 @@
836F6F7118BDC2190095E648 /* ast.c in Sources */,
836F6FE318BDC2190095E648 /* ps2_khv.c in Sources */,
836F701318BDC2190095E648 /* ps3_klbs.c in Sources */,
- 836F6F5818BDC2190095E648 /* thp_blocked.c in Sources */,
836F6F6B18BDC2190095E648 /* agsc.c in Sources */,
836F6FF018BDC2190095E648 /* ps2_psh.c in Sources */,
836F700E18BDC2190095E648 /* ps2_xa2.c in Sources */,
836F6FF718BDC2190095E648 /* ps2_sl3.c in Sources */,
836F6F3118BDC2190095E648 /* ngc_afc_decoder.c in Sources */,
836F6FE718BDC2190095E648 /* ps2_mib.c in Sources */,
- 836F6FAB18BDC2190095E648 /* ngc_bo2.c in Sources */,
836F6F9918BDC2190095E648 /* maxis_xa.c in Sources */,
836F702118BDC2190095E648 /* rs03.c in Sources */,
836F6F8418BDC2190095E648 /* emff.c in Sources */,
836F704118BDC2190095E648 /* wii_str.c in Sources */,
836F6F8818BDC2190095E648 /* fsb.c in Sources */,
- 836F6F4618BDC2190095E648 /* filp_blocked.c in Sources */,
836F6FE518BDC2190095E648 /* ps2_lpcm.c in Sources */,
836F6FB318BDC2190095E648 /* ngc_lps.c in Sources */,
836F6FC018BDC2190095E648 /* p3d.c in Sources */,
836F6FC718BDC2190095E648 /* pona.c in Sources */,
+ 8306B0B820984552000302D4 /* blocked_ws_aud.c in Sources */,
836F6FE618BDC2190095E648 /* ps2_mcg.c in Sources */,
836F6F5118BDC2190095E648 /* nolayout.c in Sources */,
83AA5D241F6E2F9C0020821C /* awc.c in Sources */,
8349A8E91FE6253900E26435 /* blocked_ea_1snh.c in Sources */,
+ 8306B0E620984590000302D4 /* msb_msh.c in Sources */,
836F702918BDC2190095E648 /* sat_sap.c in Sources */,
836F6F3718BDC2190095E648 /* pcm_decoder.c in Sources */,
831BA6281EAC61CB00CF89B0 /* coding_utils.c in Sources */,
- 836F6F5B18BDC2190095E648 /* ws_aud_blocked.c in Sources */,
836F700218BDC2190095E648 /* ps2_tk5.c in Sources */,
83AA5D271F6E2F9C0020821C /* stm.c in Sources */,
831BA61D1EAC61A500CF89B0 /* ubi_raki.c in Sources */,
836F703F18BDC2190095E648 /* wii_smp.c in Sources */,
+ 8306B0A520984552000302D4 /* blocked_ea_wve_au00.c in Sources */,
836F6FB818BDC2190095E648 /* ngc_tydsp.c in Sources */,
836F701518BDC2190095E648 /* ps3_past.c in Sources */,
836F6F7C18BDC2190095E648 /* dc_kcey.c in Sources */,
@@ -2035,6 +2115,7 @@
836F6FFE18BDC2190095E648 /* ps2_str.c in Sources */,
836F6F4A18BDC2190095E648 /* interleave.c in Sources */,
83EDE5D81A70951A005F5D84 /* mca.c in Sources */,
+ 8306B0AE20984552000302D4 /* blocked_filp.c in Sources */,
831BA61B1EAC61A500CF89B0 /* sgxd.c in Sources */,
838BDB6C1D3AFAB10022CA6F /* ffmpeg_decoder.c in Sources */,
8349A8E11FE6251F00E26435 /* ea_mt_decoder.c in Sources */,
@@ -2047,24 +2128,25 @@
836F6FC318BDC2190095E648 /* pc_smp.c in Sources */,
836F6FCE18BDC2190095E648 /* ps2_ast.c in Sources */,
8349A9091FE6258200E26435 /* pc_ast.c in Sources */,
- 836F6F5418BDC2190095E648 /* ps2_strlr_blocked.c in Sources */,
8349A91C1FE6258200E26435 /* mogg.c in Sources */,
836F703D18BDC2190095E648 /* wii_mus.c in Sources */,
836F700D18BDC2190095E648 /* ps2_wmus.c in Sources */,
831BA61C1EAC61A500CF89B0 /* sxd.c in Sources */,
836F6F8018BDC2190095E648 /* dsp_bdsp.c in Sources */,
836F6F9618BDC2190095E648 /* lsf.c in Sources */,
+ 8306B0AB20984552000302D4 /* layered.c in Sources */,
8374EE3E1F787AB600033E90 /* ffmpeg_decoder_utils_ea_xma.c in Sources */,
- 83345A511F8AEB2800B2EAA4 /* nsw_opus.c in Sources */,
+ 8306B0EC20984590000302D4 /* pcm_sre.c in Sources */,
836F6FC818BDC2190095E648 /* pos.c in Sources */,
8350C05A1E071990009E0A93 /* ps2_svag_snk.c in Sources */,
836F6F8918BDC2190095E648 /* gca.c in Sources */,
- 836F6F5718BDC2190095E648 /* str_snds_blocked.c in Sources */,
836F6FA418BDC2190095E648 /* nds_hwas.c in Sources */,
83A21F8A201D8982000F04B9 /* fsb_encrypted.c in Sources */,
+ 8306B0B120984552000302D4 /* blocked_halpst.c in Sources */,
836F6FD018BDC2190095E648 /* ps2_b1s.c in Sources */,
836F701218BDC2190095E648 /* ps3_ivag.c in Sources */,
83AA5D181F6E2F600020821C /* mpeg_custom_utils_awc.c in Sources */,
+ 8306B0BB20984552000302D4 /* blocked_gsb.c in Sources */,
836F6F7718BDC2190095E648 /* capdsp.c in Sources */,
836F6FB018BDC2190095E648 /* ngc_dsp_ygo.c in Sources */,
836F703318BDC2190095E648 /* str_snds.c in Sources */,
@@ -2077,13 +2159,18 @@
836F6FB418BDC2190095E648 /* ngc_nst_dsp.c in Sources */,
836F6FDB18BDC2190095E648 /* ps2_hsf.c in Sources */,
836F6FF618BDC2190095E648 /* ps2_sfs.c in Sources */,
+ 8306B08420984518000302D4 /* at3plus_decoder.c in Sources */,
8349A90E1FE6258200E26435 /* scd_pcm.c in Sources */,
836F6F9518BDC2190095E648 /* kraw.c in Sources */,
836F6FB718BDC2190095E648 /* ngc_ssm.c in Sources */,
+ 8306B0E920984590000302D4 /* opus.c in Sources */,
83709E051ECBC1A4005C03D3 /* gtd.c in Sources */,
+ 8306B0A420984552000302D4 /* segmented.c in Sources */,
83A21F86201D8981000F04B9 /* xwc.c in Sources */,
+ 8306B0A620984552000302D4 /* blocked_ea_wve_ad10.c in Sources */,
83AA5D1E1F6E2F800020821C /* blocked_awc.c in Sources */,
836F704A18BDC2190095E648 /* xbox_wavm.c in Sources */,
+ 8306B0B220984552000302D4 /* blocked_mxch.c in Sources */,
836F6F8618BDC2190095E648 /* excitebots.c in Sources */,
836F6FF418BDC2190095E648 /* rws.c in Sources */,
836F6F2518BDC2190095E648 /* g721_decoder.c in Sources */,
@@ -2092,19 +2179,17 @@
83709E091ECBC1A4005C03D3 /* ta_aac.c in Sources */,
836F6F9118BDC2190095E648 /* ios_psnd.c in Sources */,
836F700618BDC2190095E648 /* ps2_vgs.c in Sources */,
- 836F6F2118BDC2190095E648 /* aica_decoder.c in Sources */,
836F700318BDC2190095E648 /* ps2_vag.c in Sources */,
836F6FAA18BDC2190095E648 /* ngc_bh2pcm.c in Sources */,
831BA6211EAC61A500CF89B0 /* x360_pasx.c in Sources */,
836F6F3018BDC2190095E648 /* nds_procyon_decoder.c in Sources */,
8349A8E81FE6253900E26435 /* blocked_dec.c in Sources */,
831BA6181EAC61A500CF89B0 /* adx.c in Sources */,
- 836F6F5A18BDC2190095E648 /* vs_blocked.c in Sources */,
836F6FB118BDC2190095E648 /* ngc_ffcc_str.c in Sources */,
+ 8306B0B620984552000302D4 /* blocked_hwas.c in Sources */,
836F6FC218BDC2190095E648 /* pc_mxst.c in Sources */,
836F6FC918BDC2190095E648 /* ps2_2pfs.c in Sources */,
836F704818BDC2190095E648 /* xbox_ims.c in Sources */,
- 836F6F4918BDC2190095E648 /* ims_block.c in Sources */,
836F6F7518BDC2190095E648 /* bnsf.c in Sources */,
836F704318BDC2190095E648 /* wpd.c in Sources */,
8349A9081FE6258200E26435 /* ezw.c in Sources */,
@@ -2114,7 +2199,6 @@
836F6F8E18BDC2190095E648 /* halpst.c in Sources */,
836F6FEE18BDC2190095E648 /* ps2_p2bt.c in Sources */,
836F702618BDC2190095E648 /* s14_sss.c in Sources */,
- 836F6F4818BDC2190095E648 /* halpst_blocked.c in Sources */,
83AA5D1D1F6E2F800020821C /* blocked_vgs.c in Sources */,
8323894A1D22419B00482226 /* clHCA.c in Sources */,
836F702E18BDC2190095E648 /* sli.c in Sources */,
@@ -2125,20 +2209,24 @@
836F6F3618BDC2190095E648 /* ogg_vorbis_decoder.c in Sources */,
836F704718BDC2190095E648 /* xbox_hlwav.c in Sources */,
83345A4F1F8AEB2800B2EAA4 /* nub_xma.c in Sources */,
+ 8306B0E520984590000302D4 /* ubi_lyn.c in Sources */,
836F6F7618BDC2190095E648 /* brstm.c in Sources */,
836F700718BDC2190095E648 /* ps2_vgv.c in Sources */,
836F704F18BDC2190095E648 /* xwb.c in Sources */,
+ 8306B0AD20984552000302D4 /* blocked_caf.c in Sources */,
+ 8306B0AA20984552000302D4 /* blocked_sthd.c in Sources */,
8350270D1ED119D200C25929 /* ps3_mta2.c in Sources */,
836F6FE918BDC2190095E648 /* ps2_mihb.c in Sources */,
836F6FA918BDC2190095E648 /* ngc_adpdtk.c in Sources */,
836F6FDC18BDC2190095E648 /* ps2_iab.c in Sources */,
- 836F6FAC18BDC2190095E648 /* ngc_caf.c in Sources */,
836F6F3818BDC2190095E648 /* psx_decoder.c in Sources */,
836F6F2D18BDC2190095E648 /* mpeg_decoder.c in Sources */,
836F6F2618BDC2190095E648 /* g7221_decoder.c in Sources */,
836F6FA218BDC2190095E648 /* naomi_adpcm.c in Sources */,
836F6FBF18BDC2190095E648 /* otm.c in Sources */,
+ 8306B0B420984552000302D4 /* blocked_tra.c in Sources */,
836F6FDD18BDC2190095E648 /* ps2_ikm.c in Sources */,
+ 8306B0B520984552000302D4 /* blocked_emff.c in Sources */,
836F6FBD18BDC2190095E648 /* nwa.c in Sources */,
83A21F8C201D8982000F04B9 /* kma9.c in Sources */,
836F6FC418BDC2190095E648 /* pc_snds.c in Sources */,
@@ -2146,9 +2234,7 @@
836F6FD118BDC2190095E648 /* ps2_bg00.c in Sources */,
836F6F4118BDC2190095E648 /* blocked.c in Sources */,
836F6F3B18BDC2190095E648 /* ws_decoder.c in Sources */,
- 836F6F4518BDC2190095E648 /* emff_blocked.c in Sources */,
838BDB6E1D3B043C0022CA6F /* ffmpeg.c in Sources */,
- 836F6F5D18BDC2190095E648 /* xa_blocked.c in Sources */,
836F6F3418BDC2190095E648 /* nwa_decoder.c in Sources */,
836F6F2E18BDC2190095E648 /* msadpcm_decoder.c in Sources */,
836F6F9218BDC2190095E648 /* ish_isd.c in Sources */,
@@ -2157,18 +2243,20 @@
836F703518BDC2190095E648 /* svs.c in Sources */,
836F6FA318BDC2190095E648 /* naomi_spsd.c in Sources */,
836F6F9D18BDC2190095E648 /* msvp.c in Sources */,
+ 8306B0B920984552000302D4 /* blocked_matx.c in Sources */,
83A21F7B201D895B000F04B9 /* blocked_xvag.c in Sources */,
836F6FBA18BDC2190095E648 /* ngc_ymf.c in Sources */,
- 83A21F89201D8982000F04B9 /* atsl3.c in Sources */,
836F705018BDC2190095E648 /* ydsp.c in Sources */,
+ 8306B0B720984552000302D4 /* blocked_str_snds.c in Sources */,
836F702718BDC2190095E648 /* sat_baka.c in Sources */,
83345A4A1F8AEAF900B2EAA4 /* ffmpeg_decoder_utils_switch_opus.c in Sources */,
836F704B18BDC2190095E648 /* xbox_xmu.c in Sources */,
832389501D2246C300482226 /* hca.c in Sources */,
836F701B18BDC2190095E648 /* psx_gms.c in Sources */,
+ 8306B0F020984590000302D4 /* atsl.c in Sources */,
836F700518BDC2190095E648 /* ps2_vbk.c in Sources */,
836F6FDF18BDC2190095E648 /* ps2_int.c in Sources */,
- 836F704D18BDC2190095E648 /* xbox_xwav.c in Sources */,
+ 8306B0AC20984552000302D4 /* blocked_xa.c in Sources */,
836F6F7B18BDC2190095E648 /* dc_idvi.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/acm_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/acm_decoder.c
index edc53d742..2b12c3836 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/acm_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/acm_decoder.c
@@ -817,23 +817,65 @@ void acm_reset(ACMStream *acm)
memset(acm->wrapbuf, 0, acm->wrapbuf_len * sizeof(int));
}
-/* interface to vgmstream */
-void decode_acm(ACMStream * acm, sample * outbuf,
- int32_t samples_to_do, int channelspacing) {
+
+/***********************************************
+ * interface to vgmstream
+ ***********************************************/
+
+acm_codec_data *init_acm(STREAMFILE *streamFile) {
+ acm_codec_data* data = NULL;
+ ACMStream *acm_stream = NULL;
+ char filename[PATH_LIMIT];
+
+ data = calloc(1,sizeof(acm_codec_data));
+ if (!data) goto fail;
+
+ streamFile->get_name(streamFile,filename,sizeof(filename));
+ if (acm_open_decoder(&acm_stream,streamFile,filename) != ACM_OK)
+ goto fail;
+
+ data->file = acm_stream;
+
+ return data;
+
+fail:
+ free_acm(data);
+ return NULL;
+}
+
+void decode_acm(acm_codec_data *data, sample * outbuf, int32_t samples_to_do, int channelspacing) {
+ ACMStream * acm = data->file;
int32_t samples_read = 0;
+
while (samples_read < samples_to_do) {
- int32_t bytes_read_just_now;
- bytes_read_just_now =
- acm_read(acm,(char*)(
- outbuf+samples_read*channelspacing),
- (samples_to_do-samples_read)*sizeof(sample)*
- channelspacing,0,2,1);
+ int32_t bytes_read_just_now = acm_read(
+ acm,
+ (char*)(outbuf+samples_read*channelspacing),
+ (samples_to_do-samples_read)*sizeof(sample)*channelspacing,
+ 0,2,1);
if (bytes_read_just_now > 0) {
- samples_read +=
- bytes_read_just_now/sizeof(sample)/channelspacing;
+ samples_read += bytes_read_just_now/sizeof(sample)/channelspacing;
} else {
return;
}
}
}
+
+void reset_acm(VGMSTREAM *vgmstream) {
+ acm_codec_data *data = vgmstream->codec_data;
+
+ if (data && data->file) {
+ acm_reset(data->file);
+ }
+}
+
+void free_acm(acm_codec_data *data) {
+ if (data) {
+ if (data->file) {
+ acm_close(data->file);
+ }
+ free(data);
+ }
+}
+
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/aica_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/aica_decoder.c
deleted file mode 100644
index 556f1986b..000000000
--- a/Frameworks/vgmstream/vgmstream/src/coding/aica_decoder.c
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "../util.h"
-#include "coding.h"
-
-/* fixed point (.8) amount to scale the current step size by */
-/* part of the same series as used in MS ADPCM "ADPCMTable" */
-static const unsigned int scale_step[16] =
-{
- 230, 230, 230, 230, 307, 409, 512, 614,
- 230, 230, 230, 230, 307, 409, 512, 614
-};
-
-/* expand an unsigned four bit delta to a wider signed range */
-static const int scale_delta[16] =
-{
- 1, 3, 5, 7, 9, 11, 13, 15,
- -1, -3, -5, -7, -9,-11,-13,-15
-};
-
-/* Yamaha AICA ADPCM (as seen in Dreamcast) */
-
-void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
- int i;
- int32_t sample_count;
- int32_t hist1 = stream->adpcm_history1_16;
- uint32_t step_size = stream->adpcm_step_index;
-
- for (i=first_sample,sample_count=0; ioffset+i/2,stream->streamfile) >>
- (i&1?4:0)
- )&0xf;
-
- int32_t sample_delta = (int32_t)step_size * scale_delta[sample_nibble];
- int32_t new_sample;
-
- new_sample = hist1 + sample_delta/8;
-
- outbuf[sample_count] = clamp16(new_sample);
-
- hist1 = outbuf[sample_count];
-
- step_size = (step_size * scale_step[sample_nibble])/0x100;
- if (step_size < 0x7f) step_size = 0x7f;
- if (step_size > 0x6000) step_size = 0x6000;
- }
-
- stream->adpcm_history1_16 = hist1;
- stream->adpcm_step_index = step_size;
-}
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/at3_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/at3plus_decoder.c
similarity index 98%
rename from Frameworks/vgmstream/vgmstream/src/coding/at3_decoder.c
rename to Frameworks/vgmstream/vgmstream/src/coding/at3plus_decoder.c
index 57f56ef9b..ff00f8bbf 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/at3_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/at3plus_decoder.c
@@ -51,6 +51,7 @@ void decode_at3plus(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing,
void reset_at3plus(VGMSTREAM *vgmstream) {
maiatrac3plus_codec_data *data = vgmstream->codec_data;
+ if (!data) return;
if (data->handle)
Atrac3plusDecoder_closeContext(data->handle);
@@ -62,6 +63,8 @@ void seek_at3plus(VGMSTREAM *vgmstream, int32_t num_sample) {
int blocks_to_skip = num_sample / 2048;
int samples_to_discard = num_sample % 2048;
maiatrac3plus_codec_data *data = (maiatrac3plus_codec_data *)(vgmstream->codec_data);
+ if (!data) return;
+
vgmstream->loop_ch[0].offset =
vgmstream->loop_ch[0].channel_start_offset +
vgmstream->interleave_block_size * blocks_to_skip;
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/atrac9_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/atrac9_decoder.c
index 95c8c0020..fad4c0532 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/atrac9_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/atrac9_decoder.c
@@ -152,6 +152,7 @@ decode_fail:
void reset_atrac9(VGMSTREAM *vgmstream) {
atrac9_codec_data *data = vgmstream->codec_data;
+ if (!data) return;
if (!data->handle)
goto fail;
@@ -184,6 +185,7 @@ fail:
void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample) {
atrac9_codec_data *data = vgmstream->codec_data;
+ if (!data) return;
reset_atrac9(vgmstream);
@@ -196,8 +198,7 @@ void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample) {
}
void free_atrac9(atrac9_codec_data *data) {
- if (!data)
- return;
+ if (!data) return;
if (data->handle) Atrac9ReleaseHandle(data->handle);
free(data->data_buffer);
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding.h b/Frameworks/vgmstream/vgmstream/src/coding/coding.h
index d3a350f8d..b9de6322a 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/coding.h
+++ b/Frameworks/vgmstream/vgmstream/src/coding/coding.h
@@ -17,8 +17,9 @@ void g72x_init_state(struct g72x_state *state_ptr);
/* ima_decoder */
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
-void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
-void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
+void decode_xbox_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
+void decode_xbox_ima_mch(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
+void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first);
void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
@@ -36,6 +37,7 @@ size_t ima_bytes_to_samples(size_t bytes, int channels);
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels);
size_t xbox_ima_bytes_to_samples(size_t bytes, int channels);
size_t ubi_ima_bytes_to_samples(size_t bytes, int channels, STREAMFILE *streamFile, off_t offset);
+size_t apple_ima4_bytes_to_samples(size_t bytes, int channels);
/* ngc_dsp_decoder */
void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
@@ -57,7 +59,6 @@ void decode_ngc_afc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
/* pcm_decoder */
void decode_pcm16LE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
-void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm16BE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
@@ -74,10 +75,10 @@ size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
/* psx_decoder */
void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
-void decode_psx_bmdx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size);
void decode_hevag(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
size_t ps_bytes_to_samples(size_t bytes, int channels);
+size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, int channels);
/* xa_decoder */
void decode_xa(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
@@ -102,7 +103,10 @@ void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* acm_decoder */
-void decode_acm(ACMStream * acm, sample * outbuf, int32_t samples_to_do, int channelspacing);
+acm_codec_data *init_acm();
+void decode_acm(acm_codec_data *data, sample * outbuf, int32_t samples_to_do, int channelspacing);
+void reset_acm(VGMSTREAM *vgmstream);
+void free_acm(acm_codec_data *data);
/* nwa_decoder */
void decode_nwa(NWAData *nwa, sample *outbuf, int32_t samples_to_do);
@@ -112,8 +116,12 @@ void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first
void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do);
long msadpcm_bytes_to_samples(long bytes, int block_size, int channels);
-/* aica_decoder */
-void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
+/* yamaha_decoder */
+void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
+void decode_yamaha(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
+void decode_yamaha_nxap(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
+size_t aica_bytes_to_samples(size_t bytes, int channels);
+size_t yamaha_bytes_to_samples(size_t bytes, int channels);
/* nds_procyon_decoder */
void decode_nds_procyon(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
@@ -136,6 +144,9 @@ void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
/* mc3_decoder */
void decode_mc3(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
+/* fadpcm_decoder */
+void decode_fadpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
+
/* ea_mt_decoder*/
ea_mt_codec_data *init_ea_mt(int channel_count, int type);
void decode_ea_mt(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c b/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c
index d0cec7fc7..466054b41 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c
@@ -297,15 +297,9 @@ fail:
int ffmpeg_make_riff_xma2_from_xma2_chunk(uint8_t * buf, size_t buf_size, off_t xma2_offset, size_t xma2_size, size_t data_size, STREAMFILE *streamFile) {
uint8_t chunk[0x100];
size_t riff_size;
- size_t xma2_final_size = xma2_size;
- int xma2_chunk_version = read_8bit(xma2_offset,streamFile);
- /* FFmpeg can't parse v3 "XMA2" chunks so we'll have to extend (8 bytes in the middle) */
- if (xma2_chunk_version == 3)
- xma2_final_size += 0x8;
- riff_size = 4+4+ 4 + 4+4+xma2_final_size + 4+4;
-
- if (buf_size < riff_size || xma2_final_size > 0x100)
+ riff_size = 4+4+ 4 + 4+4+xma2_size + 4+4;
+ if (buf_size < riff_size || xma2_size > 0x100)
goto fail;
if (read_streamfile(chunk,xma2_offset,xma2_size, streamFile) != xma2_size)
goto fail;
@@ -316,20 +310,11 @@ int ffmpeg_make_riff_xma2_from_xma2_chunk(uint8_t * buf, size_t buf_size, off_t
memcpy(buf+0x08, "WAVE", 4);
memcpy(buf+0x0c, "XMA2", 4);
- put_32bitLE(buf+0x10, xma2_final_size);
- if (xma2_chunk_version == 3) {
- /* old XMA2 v3: change to v4 (extra 8 bytes in the middle); always BE */
- put_8bit (buf+0x14 + 0x00, 4); /* v4 */
- memcpy (buf+0x14 + 0x01, chunk+1, 0xF); /* first v3 part (fixed) */
- put_32bitBE(buf+0x14 + 0x10, 0x000010D6); /* extra v4 BE: "EncodeOptions" (not used by FFmpeg) */
- put_32bitBE(buf+0x14 + 0x14, 0); /* extra v4 BE: "PsuedoBytesPerSec" (not used by FFmpeg) */
- memcpy (buf+0x14 + 0x18, chunk+0x10, xma2_size - 0x10); /* second v3 part (variable size) */
- } else {
- memcpy(buf+0x14, chunk, xma2_size);
- }
+ put_32bitLE(buf+0x10, xma2_size);
+ memcpy(buf+0x14, chunk, xma2_size);
- memcpy(buf+0x14+xma2_final_size, "data", 4);
- put_32bitLE(buf+0x14+xma2_final_size+4, data_size); /* data size */
+ memcpy(buf+0x14+xma2_size, "data", 4);
+ put_32bitLE(buf+0x14+xma2_size+4, data_size); /* data size */
return riff_size;
@@ -436,20 +421,19 @@ fail:
static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int start_packet, int channels_per_packet, int bytes_per_packet, int samples_per_frame, int samples_per_subframe, int bits_frame_size) {
int frames = 0, samples = 0, loop_start_frame = 0, loop_end_frame = 0, start_skip = 0, end_skip = 0;
- uint32_t first_frame_b, packet_skip_count = 0, frame_size_b, packet_size_b, header_size_b;
- uint64_t offset_b, packet_offset_b, frame_offset_b;
- size_t size;
+ size_t first_frame_b, packet_skip_count = 0, frame_size_b, packet_size_b, header_size_b;
+ off_t offset_b, packet_offset_b, frame_offset_b;
- uint32_t packet_size = bytes_per_packet;
+ size_t packet_size = bytes_per_packet;
off_t offset = msd->data_offset;
- uint32_t stream_offset_b = msd->data_offset * 8;
+ off_t max_offset = msd->data_offset + msd->data_size;
+ off_t stream_offset_b = msd->data_offset * 8;
offset += start_packet * packet_size;
- size = offset + msd->data_size;
packet_size_b = packet_size * 8;
/* read packets */
- while (offset < size) {
+ while (offset < max_offset) {
offset_b = offset * 8; /* global offset in bits */
offset += packet_size; /* global offset in bytes */
@@ -678,7 +662,7 @@ void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_
return;
}
samples_per_frame = wma_get_samples_per_frame(version, sample_rate, decode_flags);
- bits_frame_size = floor(log(block_align) / log(2)) + 4; /* max bits needed to represent this block_align */
+ bits_frame_size = (int)floor(log(block_align) / log(2)) + 4; /* max bits needed to represent this block_align */
samples_per_subframe = 0; /* not really needed WMAPro can't use loop subframes (complex subframe lengths) */
msd->xma_version = 0; /* signal it's not XMA */
@@ -705,7 +689,8 @@ void wma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_ali
else {
/* variable frames per packet (mini-header values) */
off_t offset = msd->data_offset;
- while (offset < msd->data_size) { /* read packets (superframes) */
+ off_t max_offset = msd->data_offset + msd->data_size;
+ while (offset < max_offset) { /* read packets (superframes) */
int packet_frames;
uint8_t header = read_8bit(offset, streamFile); /* upper nibble: index; lower nibble: frames */
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ea_mt_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ea_mt_decoder.c
index fa02d8c5c..1ecc4106d 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/ea_mt_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/ea_mt_decoder.c
@@ -534,6 +534,8 @@ static void flush_ea_mt_internal(VGMSTREAM *vgmstream, int is_start) {
int i;
size_t bytes;
+ if (!data) return;
+
/* the decoder needs to be notified when offsets change */
for (i = 0; i < vgmstream->channels; i++) {
UTKContext *ctx = data->utk_context[i];
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/fadpcm_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/fadpcm_decoder.c
new file mode 100644
index 000000000..331e94c47
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/coding/fadpcm_decoder.c
@@ -0,0 +1,81 @@
+#include "coding.h"
+
+
+/* FADPCM table */
+static const int8_t fadpcm_coefs[8][2] = {
+ { 0 , 0 },
+ { 60 , 0 },
+ { 122 , 60 },
+ { 115 , 52 },
+ { 98 , 55 },
+ { 0 , 0 },
+ { 0 , 0 },
+ { 0 , 0 },
+};
+
+/* FMOD's FADPCM, basically XA/PSX ADPCM with a fancy header layout.
+ * Code/layout could be simplified but tries to emulate FMOD's code.
+ * Algorithm and tables debugged from their PC DLLs. */
+void decode_fadpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
+ off_t frame_offset;
+ int i, j, k;
+ int block_samples, num_frame, samples_done = 0, sample_count = 0;
+ uint32_t coefs, shifts;
+ int32_t hist1; //= stream->adpcm_history1_32;
+ int32_t hist2; //= stream->adpcm_history2_32;
+
+ /* external interleave (fixed size), mono */
+ block_samples = (0x8c - 0xc) * 2;
+ num_frame = first_sample / block_samples;
+ first_sample = first_sample % block_samples;
+
+ frame_offset = stream->offset + 0x8c*num_frame;
+
+
+ /* parse 0xc header (header samples are not written to outbuf) */
+ coefs = read_32bitLE(frame_offset + 0x00, stream->streamfile);
+ shifts = read_32bitLE(frame_offset + 0x04, stream->streamfile);
+ hist1 = read_16bitLE(frame_offset + 0x08, stream->streamfile);
+ hist2 = read_16bitLE(frame_offset + 0x0a, stream->streamfile);
+
+
+ /* decode nibbles, grouped in 8 sets of 0x10 * 0x04 * 2 */
+ for (i = 0; i < 8; i++) {
+ int32_t coef1, coef2, shift, coef_index, shift_factor;
+ off_t group_offset = frame_offset + 0x0c + 0x10*i;
+
+ /* each set has its own coefs/shifts (indexes > 7 are repeat, ex. 0x9 is 0x2) */
+ coef_index = ((coefs >> i*4) & 0x0f) % 0x07;
+ shift_factor = (shifts >> i*4) & 0x0f;
+
+ coef1 = fadpcm_coefs[coef_index][0];
+ coef2 = fadpcm_coefs[coef_index][1];
+ shift = 0x16 - shift_factor;
+
+ for (j = 0; j < 4; j++) {
+ uint32_t nibbles = read_32bitLE(group_offset + 0x04*j, stream->streamfile);
+
+ for (k = 0; k < 8; k++) {
+ int32_t new_sample;
+
+ new_sample = (nibbles >> k*4) & 0x0f;
+ new_sample = (new_sample << 28) >> shift; /* sign extend + scale */
+ new_sample = (new_sample - hist2*coef2 + hist1*coef1);
+ new_sample = new_sample >> 6; /* (new_sample / 64) has minor rounding differences */
+ new_sample = clamp16(new_sample);
+
+ if (sample_count >= first_sample && samples_done < samples_to_do) {
+ outbuf[samples_done * channelspacing] = new_sample;
+ samples_done++;
+ }
+ sample_count++;
+
+ hist2 = hist1;
+ hist1 = new_sample;
+ }
+ }
+ }
+
+ //stream->adpcm_history1_32 = hist1;
+ //stream->adpcm_history2_32 = hist2;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c
index df24db802..f9ef42f0c 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c
@@ -364,6 +364,10 @@ ffmpeg_codec_data * init_ffmpeg_config(STREAMFILE *streamFile, uint8_t * header,
memcpy(&data->config, config, sizeof(ffmpeg_custom_config));
}
+ /* ignore bad combos */
+ if ((header && !header_size) || (!header && header_size))
+ goto fail;
+
/* fake header to trick FFmpeg into demuxing/decoding the stream */
if (header_size > 0) {
data->header_size = header_size;
@@ -706,6 +710,7 @@ end:
void reset_ffmpeg(VGMSTREAM *vgmstream) {
ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data;
+ if (!data) return;
if (data->formatCtx) {
avformat_seek_file(data->formatCtx, data->streamIndex, 0, 0, 0, AVSEEK_FLAG_ANY);
@@ -733,6 +738,7 @@ void reset_ffmpeg(VGMSTREAM *vgmstream) {
void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data;
int64_t ts;
+ if (!data) return;
/* Start from 0 and discard samples until loop_start (slower but not too noticeable).
* Due to various FFmpeg quirks seeking to a sample is erratic in many formats (would need extra steps). */
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/g719_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/g719_decoder.c
index 9c01f8e0d..ab3cb8293 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/g719_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/g719_decoder.c
@@ -53,6 +53,7 @@ void decode_g719(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int
void reset_g719(VGMSTREAM *vgmstream) {
g719_codec_data *data = vgmstream->codec_data;
int i;
+ if (!data) return;
for (i = 0; i < vgmstream->channels; i++)
{
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/g7221_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/g7221_decoder.c
index 5f5aa761e..648a8b575 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/g7221_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/g7221_decoder.c
@@ -52,6 +52,7 @@ void decode_g7221(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, in
void reset_g7221(VGMSTREAM *vgmstream) {
g7221_codec_data *data = vgmstream->codec_data;
int i;
+ if (!data) return;
for (i = 0; i < vgmstream->channels; i++)
{
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c
index c8476b7f3..8288229f3 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c
@@ -2,7 +2,6 @@
void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) {
int samples_done = 0;
-
int32_t samples_remain = clHCA_samplesPerBlock - data->sample_ptr;
void *hca_data = NULL;
@@ -84,7 +83,8 @@ void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do, i
void reset_hca(VGMSTREAM *vgmstream) {
hca_codec_data *data = vgmstream->codec_data;
- /*clHCA *hca = (clHCA *)(data + 1);*/
+ if (!data) return;
+
data->curblock = 0;
data->sample_ptr = clHCA_samplesPerBlock;
data->samples_discard = 0;
@@ -92,6 +92,8 @@ void reset_hca(VGMSTREAM *vgmstream) {
void loop_hca(VGMSTREAM *vgmstream) {
hca_codec_data *data = (hca_codec_data *)(vgmstream->codec_data);
+ if (!data) return;
+
data->curblock = data->info.loopStart;
data->sample_ptr = clHCA_samplesPerBlock;
data->samples_discard = 0;
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c
index bdb09b4e8..9fc8902d7 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c
@@ -8,14 +8,7 @@
* All IMAs are mostly the same with these variations:
* - interleave: blocks and channels are handled externally (layouts) or internally (mixed channels)
* - block header: none (external), normal (4 bytes of history 16b + step 8b + reserved 8b) or others; per channel/global
- * - expand type: ms-ima style or others; low or high nibble first
- *
- * todo:
- * MS IMAs have the last sample of the prev block in the block header. In Microsoft's implementation, the header sample
- * is written first and last sample is skipped (since they match). vgmstream ignores the header sample and
- * writes the last one instead. This means the very first sample in the first header in a stream is incorrectly skipped.
- * Header step should be 8 bit.
- * Officially defined in "Microsoft Multimedia Standards Update" doc (RIFFNEW.pdf).
+ * - expand type: IMA style or variations; low or high nibble first
*/
static const int ADPCMTable[89] = {
@@ -39,15 +32,15 @@ static const int IMA_IndexTable[16] = {
};
-/* Standard IMA (most common) */
+/* Original IMA expansion, using shift+ADDs to avoid MULs (slow back then) */
static void std_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) {
int sample_nibble, sample_decoded, step, delta;
- /* calculate diff = [signed] (step / 8) + (step / 4) + (step / 2) + (step) [when code = 4+2+1]
- * simplified through math, using bitwise ops to avoid rounding:
- * diff = (code + 1/2) * (step / 4)
- * > diff = (step * nibble / 4) + (step / 8)
- * > diff = (((step * nibble) + (step / 2)) / 4) */
+ /* simplified through math from:
+ * - diff = (code + 1/2) * (step / 4)
+ * > diff = ((step * nibble) + (step / 2)) / 4
+ * > diff = (step * nibble / 4) + (step / 8)
+ * final diff = [signed] (step / 8) + (step / 4) + (step / 2) + (step) [when code = 4+2+1] */
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; /* ADPCM code */
sample_decoded = *hist1; /* predictor value */
@@ -81,7 +74,33 @@ static void std_ima_expand_nibble_16(VGMSTREAMCHANNEL * stream, off_t byte_offse
if (sample_nibble & 8) delta = -delta;
sample_decoded += delta;
- *hist1 = clamp16(sample_decoded); //no need for this actually
+ *hist1 = clamp16(sample_decoded); /* no need for this, actually */
+ *step_index += IMA_IndexTable[sample_nibble];
+ if (*step_index < 0) *step_index=0;
+ if (*step_index > 88) *step_index=88;
+}
+
+/* Original IMA expansion, but using MULs rather than shift+ADDs (faster for newer processors).
+ * There is minor rounding difference between ADD and MUL expansions, noticeable/propagated in non-headered IMAs. */
+static void std_ima_expand_nibble_mul(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) {
+ int sample_nibble, sample_decoded, step, delta;
+
+ /* simplified through math from:
+ * - diff = (code + 1/2) * (step / 4)
+ * > diff = (code + 1/2) * step) / 4) * (2 / 2)
+ * > diff = (code + 1/2) * 2 * step / 8
+ * final diff = [signed] ((code * 2 + 1) * step) / 8 */
+
+ sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
+ sample_decoded = *hist1;
+ step = ADPCMTable[*step_index];
+
+ delta = (sample_nibble & 0x7);
+ delta = ((delta * 2 + 1) * step) >> 3;
+ if (sample_nibble & 8) delta = -delta;
+ sample_decoded += delta;
+
+ *hist1 = clamp16(sample_decoded);
*step_index += IMA_IndexTable[sample_nibble];
if (*step_index < 0) *step_index=0;
if (*step_index > 88) *step_index=88;
@@ -96,7 +115,8 @@ static void n3ds_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset,
step = ADPCMTable[*step_index];
sample_decoded = sample_decoded << 3;
- delta = step * (sample_nibble & 7) * 2 + step; /* custom */
+ delta = (sample_nibble & 0x07);
+ delta = step * delta * 2 + step; /* custom */
if (sample_nibble & 8) delta = -delta;
sample_decoded += delta;
sample_decoded = sample_decoded >> 3;
@@ -149,24 +169,6 @@ static void otns_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset,
if (*step_index > 88) *step_index=88;
}
-/* Ubisoft games, algorithm by Zench (https://bitbucket.org/Zenchreal/decubisnd) */
-static void ubi_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) {
- int sample_nibble, sample_decoded, step, delta;
-
- sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
- sample_decoded = *hist1;
- step = ADPCMTable[*step_index];
-
- delta = (((sample_nibble & 7) * 2 + 1) * step) >> 3; /* custom */
- if (sample_nibble & 8) delta = -delta;
- sample_decoded += delta;
-
- *hist1 = clamp16(sample_decoded);
- *step_index += IMA_IndexTable[sample_nibble];
- if (*step_index < 0) *step_index=0;
- if (*step_index > 88) *step_index=88;
-}
-
/* ************************************ */
/* DVI/IMA */
/* ************************************ */
@@ -176,7 +178,6 @@ static void ubi_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset,
* For vgmstream, low nibble is called "IMA ADPCM" and high nibble is "DVI IMA ADPCM" (same thing though). */
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * 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;
-
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@@ -186,7 +187,7 @@ void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
- /* decode nibbles */
+ /* decode nibbles (layout: varies) */
for (i = first_sample; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
off_t byte_offset = is_stereo ?
stream->offset + i : /* stereo: one nibble per channel */
@@ -205,7 +206,6 @@ void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
-
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@@ -227,7 +227,6 @@ void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count;
-
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@@ -249,7 +248,6 @@ void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count;
-
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@@ -275,20 +273,20 @@ void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample *
/* MS-IMA */
/* ************************************ */
-/* IMA with variable-sized frames, header and custom nibble layout (outputs non-aligned number of samples).
+/* IMA with custom frame sizes, header and nibble layout. Outputs an odd number of samples per frame,
+ * so to simplify calcs this decodes full frames, thus hist doesn't need to be mantained.
* Officially defined in "Microsoft Multimedia Standards Update" doc (RIFFNEW.pdf). */
void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, samples_read = 0, samples_done = 0, max_samples;
-
int32_t hist1;// = stream->adpcm_history1_32;
int step_index;// = stream->adpcm_step_index;
- /* internal interleave (configurable size), mixed channels (4 byte per ch) */
+ /* internal interleave (configurable size), mixed channels */
int block_samples = ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1;
first_sample = first_sample % block_samples;
- /* normal header (hist+step+reserved per channel) */
- {
+ /* normal header (hist+step+reserved), per channel */
+ { //if (first_sample == 0) {
off_t header_offset = stream->offset + 0x04*channel;
hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
@@ -296,7 +294,7 @@ void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * ou
if (step_index < 0) step_index = 0;
if (step_index > 88) step_index = 88;
- /* write header sample */
+ /* write header sample (odd samples per block) */
if (samples_read >= first_sample && samples_done < samples_to_do) {
outbuf[samples_done * channelspacing] = (short)hist1;
samples_done++;
@@ -308,12 +306,12 @@ void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * ou
if (max_samples > samples_to_do + first_sample - samples_done)
max_samples = samples_to_do + first_sample - samples_done; /* for smaller last block */
- /* decode nibbles (layout: alternates 4*2 nibbles per channel) */
+ /* decode nibbles (layout: alternates 4 bytes/4*2 nibbles per channel) */
for (i = 0; i < max_samples; i++) {
off_t byte_offset = stream->offset + 0x04*vgmstream->channels + 0x04*channel + 0x04*vgmstream->channels*(i/8) + (i%8)/2;
int nibble_shift = (i&1?4:0); /* low nibble first */
- std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
+ std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); /* original expand */
if (samples_read >= first_sample && samples_done < samples_to_do) {
outbuf[samples_done * channelspacing] = (short)(hist1);
@@ -331,24 +329,23 @@ void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * ou
//stream->adpcm_step_index = step_index;
}
-/* Reflection's MS-IMA (some layout info from XA2WAV by Deniz Oezmen) */
+/* Reflection's MS-IMA with custom nibble layout (some info from XA2WAV by Deniz Oezmen) */
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, samples_read = 0, samples_done = 0, max_samples;
-
int32_t hist1;// = stream->adpcm_history1_32;
int step_index;// = stream->adpcm_step_index;
- /* internal interleave (configurable size), mixed channels (4 byte per ch) */
+ /* internal interleave (configurable size), mixed channels */
int block_channel_size = (vgmstream->interleave_block_size - 0x04*vgmstream->channels) / vgmstream->channels;
int block_samples = ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1;
first_sample = first_sample % block_samples;
- /* normal header (hist+step+reserved per channel) */
- {
+ /* normal header (hist+step+reserved), per channel */
+ { //if (first_sample == 0) {
off_t header_offset = stream->offset + 0x04*channel;
hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
- step_index = read_8bit(header_offset+0x02,stream->streamfile); /* 0x03: reserved */
+ step_index = read_8bit(header_offset+0x02,stream->streamfile);
if (step_index < 0) step_index = 0;
if (step_index > 88) step_index = 88;
@@ -391,90 +388,93 @@ void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * o
/* XBOX-IMA */
/* ************************************ */
-/* MS-IMA with fixed frame size, skips last sample per channel (for aligment) and custom multichannel nibble layout.
- * For multichannel the layout is (I think) mixed stereo channels (ex. 6ch: 2ch + 2ch + 2ch) */
-void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
- int i, sample_count;
-
+/* MS-IMA with fixed frame size, and outputs an even number of samples per frame (skips last nibble).
+ * Defined in Xbox's SDK. Multichannel interleaves 2ch*N/2, or 1ch*N with odd num_channels
+ * (seen in some Koei .wav, could be simplified as interleaved stereo) --unsure if official. */
+void decode_xbox_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
+ int i, sample_count = 0;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
- off_t offset = stream->offset;
-
- //internal interleave (0x20+4 size), mixed channels (4 byte per ch, mixed stereo)
- int block_samples = (vgmstream->channels==1) ?
- 32 :
- 32*(vgmstream->channels&2);//todo this can be zero in 4/5/8ch = SEGFAULT using % below
+ /* internal interleave (fixed size), mixed channels */
+ int block_samples = (0x24-0x4) * 2;
first_sample = first_sample % block_samples;
- //normal header (per channel)
+ /* normal header (hist+step+reserved), per stereo/mono channel in blocks */
if (first_sample == 0) {
- off_t header_offset;
- header_offset = stream->offset + 4*(channel%2);
+ off_t header_offset = (channelspacing & 1) ?
+ stream->offset + 0x24*(channel) + 0x00:
+ stream->offset + 0x48*(channel/2) + 0x04*(channel%2);
- hist1 = read_16bitLE(header_offset,stream->streamfile);
- step_index = read_16bitLE(header_offset+2,stream->streamfile);
- if (step_index < 0) step_index=0;
- if (step_index > 88) step_index=88;
- }
-
- for (i=first_sample,sample_count=0; ioffset + 4*(channel%2) + 4 + i/8*4 + (i%8)/2 :
- stream->offset + 4*(channel%2) + 4*2 + i/8*4*2 + (i%8)/2;
- nibble_shift = (i&1?4:0); //low nibble first
-
- std_ima_expand_nibble(stream, offset,nibble_shift, &hist1, &step_index);
- outbuf[sample_count] = (short)(hist1);
- }
-
- //internal interleave: increment offset on complete frame
- if (channelspacing==1) { /* mono */
- if (offset-stream->offset == 32+3) // ??
- stream->offset += 0x24;
- } else {
- if (offset-stream->offset == 64+(4*(channel%2))+3) // ??
- stream->offset += 0x24*channelspacing;
- }
-
- stream->adpcm_history1_32 = hist1;
- stream->adpcm_step_index = step_index;
-}
-
-/* mono XBOX-IMA ADPCM for interleave */
-void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
- int i, sample_count = 0, num_frame;
- int32_t hist1 = stream->adpcm_history1_32;
- int step_index = stream->adpcm_step_index;
-
- //external interleave
- int block_samples = (0x24 - 0x4) * 2; /* block size - header, 2 samples per byte */
- num_frame = first_sample / block_samples;
- first_sample = first_sample % block_samples;
-
- //normal header
- if (first_sample == 0) {
- off_t header_offset = stream->offset + 0x24*num_frame;
-
- hist1 = read_16bitLE(header_offset,stream->streamfile);
- step_index = read_8bit(header_offset+2,stream->streamfile);
+ hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
+ step_index = read_8bit(header_offset+0x02,stream->streamfile);
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
- //must write history from header as last nibble/sample in block is almost always 0 / not encoded
+ /* write header sample (even samples per block, skips last nibble) */
outbuf[sample_count] = (short)(hist1);
sample_count += channelspacing;
first_sample += 1;
samples_to_do -= 1;
}
- for (i=first_sample; i < first_sample + samples_to_do; i++) { /* first_sample + samples_to_do should be block_samples at most */
- off_t byte_offset = (stream->offset + 0x24*num_frame + 0x4) + (i-1)/2;
- int nibble_shift = ((i-1)&1?4:0); //low nibble first
+ /* decode nibbles (layout: alternates 4 bytes/4*2 nibbles per channel, in stereo blocks) */
+ for (i = first_sample; i < first_sample + samples_to_do; i++) {
+ off_t byte_offset = (channelspacing & 1) ?
+ (stream->offset + 0x24*(channel) + 0x04) + (i-1)/2:
+ (stream->offset + 0x48*(channel/2) + 0x04*2) + 0x04*(channel%2) + 0x04*2*((i-1)/8) + ((i-1)%8)/2;
+ int nibble_shift = ((i-1)&1?4:0); /* low nibble first */
- //last nibble/sample in block is ignored (next header sample contains it)
+ /* must skip last nibble per official decoder, probably not needed though */
+ if (i < block_samples) {
+ std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
+ outbuf[sample_count] = (short)(hist1);
+ sample_count += channelspacing;
+ }
+ }
+
+ /* internal interleave: increment offset on complete frame */
+ if (i == block_samples) {
+ stream->offset += 0x24*channelspacing;
+ }
+
+ stream->adpcm_history1_32 = hist1;
+ stream->adpcm_step_index = step_index;
+}
+
+/* Multichannel XBOX-IMA ADPCM, with all channels mixed in the same block (equivalent to multichannel MS-IMA; seen in .rsd XADP). */
+void decode_xbox_ima_mch(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
+ int i, sample_count = 0, num_frame;
+ int32_t hist1 = stream->adpcm_history1_32;
+ int step_index = stream->adpcm_step_index;
+
+ /* external interleave (fixed size), multichannel */
+ int block_samples = (0x24 - 0x4) * 2;
+ num_frame = first_sample / block_samples;
+ first_sample = first_sample % block_samples;
+
+ /* normal header (hist+step+reserved), multichannel */
+ if (first_sample == 0) {
+ off_t header_offset = stream->offset + 0x24*channelspacing*num_frame + 0x04*channel;
+
+ hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
+ step_index = read_8bit(header_offset+0x02,stream->streamfile);
+ if (step_index < 0) step_index=0;
+ if (step_index > 88) step_index=88;
+
+ /* write header sample (even samples per block, skips last nibble) */
+ outbuf[sample_count] = (short)(hist1);
+ sample_count += channelspacing;
+ first_sample += 1;
+ samples_to_do -= 1;
+ }
+
+ /* decode nibbles (layout: alternates 4 bytes/4*2 nibbles per channel) */
+ for (i = first_sample; i < first_sample + samples_to_do; i++) {
+ off_t byte_offset = (stream->offset + 0x24*channelspacing*num_frame + 0x04*channelspacing) + 0x04*channel + 0x04*channelspacing*((i-1)/8) + ((i-1)%8)/2;
+ int nibble_shift = ((i-1)&1?4:0); /* low nibble first */
+
+ /* must skip last nibble per spec, rarely needed though */
if (i < block_samples) {
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
outbuf[sample_count] = (short)(hist1);
@@ -486,39 +486,86 @@ void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
stream->adpcm_step_index = step_index;
}
-void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
- int i, sample_count;
-
- int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16?
+/* Mono XBOX-IMA ADPCM, used for interleave. Also defined in Xbox's SDK. */
+void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
+ int i, sample_count = 0, num_frame;
+ int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
- //external interleave
+ /* external interleave (fixed size), mono */
+ int block_samples = (0x24 - 0x4) * 2;
+ num_frame = first_sample / block_samples;
+ first_sample = first_sample % block_samples;
- //normal header
+ /* normal header (hist+step+reserved), single channel */
+ if (first_sample == 0) {
+ off_t header_offset = stream->offset + 0x24*num_frame;
+
+ hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
+ step_index = read_8bit(header_offset+0x02,stream->streamfile);
+ if (step_index < 0) step_index=0;
+ if (step_index > 88) step_index=88;
+
+ /* write header sample (even samples per block, skips last nibble) */
+ outbuf[sample_count] = (short)(hist1);
+ sample_count += channelspacing;
+ first_sample += 1;
+ samples_to_do -= 1;
+ }
+
+ /* decode nibbles (layout: all nibbles from one channel) */
+ for (i = first_sample; i < first_sample + samples_to_do; i++) {
+ off_t byte_offset = (stream->offset + 0x24*num_frame + 0x4) + (i-1)/2;
+ int nibble_shift = ((i-1)&1?4:0); /* low nibble first */
+
+ /* must skip last nibble per spec, rarely needed though (ex. Gauntlet Dark Legacy) */
+ if (i < block_samples) {
+ std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
+ outbuf[sample_count] = (short)(hist1);
+ sample_count += channelspacing;
+ }
+ }
+
+ stream->adpcm_history1_32 = hist1;
+ stream->adpcm_step_index = step_index;
+}
+
+/* Similar to MS-IMA with even number of samples, header sample is not written (setup only).
+ * Apparently clamps to -32767 unlike standard's -32768 (probably not noticeable).
+ * Info here: http://problemkaputt.de/gbatek.htm#dssoundnotes */
+void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
+ int i, sample_count;
+ int32_t hist1 = stream->adpcm_history1_32;
+ int step_index = stream->adpcm_step_index;
+
+ /* external interleave (configurable size), mono */
+
+ /* normal header (hist+step+reserved), single channel */
if (first_sample == 0) {
off_t header_offset = stream->offset;
hist1 = read_16bitLE(header_offset,stream->streamfile);
step_index = read_16bitLE(header_offset+2,stream->streamfile);
-
- //todo clip step_index?
+ if (step_index < 0) step_index=0; /* probably pre-adjusted */
+ if (step_index > 88) step_index=88;
}
+ /* decode nibbles (layout: all nibbles from the channel) */
for (i=first_sample,sample_count=0; ioffset + 4 + i/2;
- int nibble_shift = (i&1?4:0); //low nibble first
+ off_t byte_offset = stream->offset + 0x04 + i/2;
+ int nibble_shift = (i&1?4:0); /* low nibble first */
+ //todo waveform has minor deviations using known expands
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
outbuf[sample_count] = (short)(hist1);
}
- stream->adpcm_history1_16 = hist1;
+ stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
}
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
-
int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16?
int step_index = stream->adpcm_step_index;
@@ -548,7 +595,6 @@ void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
int i, sample_count;
-
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@@ -583,7 +629,6 @@ void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * ou
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
-
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@@ -613,6 +658,7 @@ void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
stream->adpcm_step_index = step_index;
}
+/* Apple's IMA4, a.k.a QuickTime IMA. 2 byte header and header sample is not written (setup only). */
void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count, num_frame;
int16_t hist1 = stream->adpcm_history1_16;//todo unneeded 16?
@@ -647,91 +693,99 @@ void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelsp
/* XBOX-IMA with modified data layout */
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
- int i, sample_count;
-
+ int i, sample_count = 0;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
- //internal interleave
- int block_samples = (0x24 - 4) * 2; /* block size - header, 2 samples per byte */
+ /* internal interleave (configurable size), mixed channels */
+ int block_samples = (0x24 - 0x4) * 2;
first_sample = first_sample % block_samples;
- //interleaved header (all hist per channel + all step_index per channel)
+ /* interleaved header (all hist per channel + all step_index+reserved per channel) */
if (first_sample == 0) {
- off_t hist_offset = stream->offset + 2*channel;
- off_t step_offset = stream->offset + 2*channel + 2*vgmstream->channels;
+ off_t hist_offset = stream->offset + 0x02*channel + 0x00;
+ off_t step_offset = stream->offset + 0x02*channel + 0x02*vgmstream->channels;
- hist1 = read_16bitLE(hist_offset,stream->streamfile);
+ hist1 = read_16bitLE(hist_offset,stream->streamfile);
step_index = read_8bit(step_offset,stream->streamfile);
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
- }
- for (i=first_sample,sample_count=0; ioffset + 4*vgmstream->channels + 2*channel + i/4*2*vgmstream->channels + (i%4)/2;//2-byte per channel
- int nibble_shift = (i&1?4:0); //low nibble first
-
- std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
- outbuf[sample_count] = (short)(hist1);
- }
-
- //internal interleave: increment offset on complete frame
- if (i == block_samples) stream->offset += 36*vgmstream->channels;
-
- stream->adpcm_history1_32 = hist1;
- stream->adpcm_step_index = step_index;
-}
-
-/* XBOX-IMA with modified data layout */
-void decode_wwise_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
- int i, sample_count = 0;
-
- int32_t hist1 = stream->adpcm_history1_32;
- int step_index = stream->adpcm_step_index;
-
- //internal interleave (configurable size), block-interleave multichannel (ex. if block is 0xD8 in 6ch: 6 blocks of 4+0x20)
- int block_samples = (vgmstream->interleave_block_size - 4*vgmstream->channels) * 2 / vgmstream->channels;
- first_sample = first_sample % block_samples;
-
- //block-interleaved header (1 header per channel block); can be LE or BE
- if (first_sample == 0) {
- int16_t (*read_16bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_16bitBE : read_16bitLE;
- off_t header_offset = stream->offset + (vgmstream->interleave_block_size / vgmstream->channels)*channel;
-
- hist1 = read_16bit(header_offset,stream->streamfile);
- step_index = read_8bit(header_offset+2,stream->streamfile);
- if (step_index < 0) step_index=0;
- if (step_index > 88) step_index=88;
-
- //must write history from header as last nibble/sample in block is almost always 0 / not encoded
+ /* write header sample (even samples per block, skips last nibble) */
outbuf[sample_count] = (short)(hist1);
sample_count += channelspacing;
first_sample += 1;
samples_to_do -= 1;
}
- for (i=first_sample; i < first_sample + samples_to_do; i++) { /* first_sample + samples_to_do should be block_samples at most */
- off_t byte_offset = stream->offset + (vgmstream->interleave_block_size / vgmstream->channels)*channel + 4 + (i-1)/2;
- int nibble_shift = ((i-1)&1?4:0); //low nibble first
+ /* decode nibbles (layout: 2 bytes/2*2 nibbles per channel) */
+ for (i = first_sample; i < first_sample + samples_to_do; i++) {
+ off_t byte_offset = stream->offset + 0x04*vgmstream->channels + 0x02*channel + (i-1)/4*2*vgmstream->channels + ((i-1)%4)/2;
+ int nibble_shift = ((i-1)&1?4:0); /* low nibble first */
- //last nibble/sample in block is ignored (next header sample contains it)
+ /* must skip last nibble per official decoder, probably not needed though */
if (i < block_samples) {
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
outbuf[sample_count] = (short)(hist1);
- sample_count+=channelspacing;
+ sample_count += channelspacing;
}
}
- //internal interleave: increment offset on complete frame
- if (i == block_samples) stream->offset += vgmstream->interleave_block_size;
+ /* internal interleave: increment offset on complete frame */
+ if (i == block_samples) {
+ stream->offset += 0x24*vgmstream->channels;
+ }
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
}
-//todo atenuation: apparently from hcs's analysis Wwise IMA expands nibbles slightly different, reducing clipping/dbs
-/*
-From Wwise_v2015.1.6_Build5553_SDK.Linux
-<_ZN13CAkADPCMCodec12DecodeSampleEiii>:
+
+/* mono XBOX-IMA with header endianness and alt nibble expand (per hcs's decompilation) */
+void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
+ int i, sample_count = 0, num_frame;
+ int32_t hist1 = stream->adpcm_history1_32;
+ int step_index = stream->adpcm_step_index;
+
+ /* external interleave (fixed size), mono */
+ int block_samples = (0x24 - 0x4) * 2;
+ num_frame = first_sample / block_samples;
+ first_sample = first_sample % block_samples;
+
+ /* normal header (hist+step+reserved), single channel */
+ if (first_sample == 0) {
+ int16_t (*read_16bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_16bitBE : read_16bitLE;
+ off_t header_offset = stream->offset + 0x24*num_frame;
+
+ hist1 = read_16bit(header_offset,stream->streamfile);
+ step_index = read_8bit(header_offset+2,stream->streamfile);
+ if (step_index < 0) step_index=0;
+ if (step_index > 88) step_index=88;
+
+ /* write header sample (even samples per block, skips last nibble) */
+ outbuf[sample_count] = (short)(hist1);
+ sample_count += channelspacing;
+ first_sample += 1;
+ samples_to_do -= 1;
+ }
+
+ /* decode nibbles (layout: all nibbles from one channel) */
+ for (i = first_sample; i < first_sample + samples_to_do; i++) {
+ off_t byte_offset = (stream->offset + 0x24*num_frame + 0x4) + (i-1)/2;
+ int nibble_shift = ((i-1)&1?4:0); /* low nibble first */
+
+ /* must skip last nibble like other XBOX-IMAs, often needed (ex. Bayonetta 2 sfx) */
+ if (i < block_samples) {
+ std_ima_expand_nibble_mul(stream, byte_offset,nibble_shift, &hist1, &step_index);
+ outbuf[sample_count] = (short)(hist1);
+ sample_count += channelspacing;
+ }
+ }
+
+ stream->adpcm_history1_32 = hist1;
+ stream->adpcm_step_index = step_index;
+}
+/* from hcs's analysis Wwise IMA expands nibbles slightly different, reducing dbs. Just "MUL" expand?
+<_ZN13CAkADPCMCodec12DecodeSampleEiii>: //From Wwise_v2015.1.6_Build5553_SDK.Linux
10: 83 e0 07 and $0x7,%eax ; sample
13: 01 c0 add %eax,%eax ; sample*2
15: 83 c0 01 add $0x1,%eax ; sample*2+1
@@ -740,8 +794,6 @@ From Wwise_v2015.1.6_Build5553_SDK.Linux
1f: 85 c0 test %eax,%eax ; result negative?
21: 0f 48 c2 cmovs %edx,%eax ; adjust if negative to fix rounding for below division
24: c1 f8 03 sar $0x3,%eax ; (sample*2+1)*scale/8
-
-Different rounding model vs IMA's shift-and-add (also "adjust" step may be unnecessary).
*/
/* MS-IMA with possibly the XBOX-IMA model of even number of samples per block (more tests are needed) */
@@ -832,7 +884,7 @@ void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
(!(i%2) ? 4:0) : /* mono mode (high first) */
(channel==0 ? 4:0); /* stereo mode (high=L,low=R) */
- ubi_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
+ std_ima_expand_nibble_mul(stream, byte_offset,nibble_shift, &hist1, &step_index);
outbuf[sample_count] = (short)(hist1); /* all samples are written */
}
@@ -849,7 +901,7 @@ size_t ima_bytes_to_samples(size_t bytes, int channels) {
}
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels) {
- /* MS IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */
+ /* MS-IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */
return (bytes / block_align) * ((block_align - 0x04*channels) * 2 / channels + 1)
+ ((bytes % block_align) ? (((bytes % block_align) - 0x04*channels) * 2 / channels + 1) : 0);
}
@@ -858,7 +910,13 @@ size_t xbox_ima_bytes_to_samples(size_t bytes, int channels) {
int block_align = 0x24 * channels;
/* XBOX IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */
return (bytes / block_align) * (block_align - 4 * channels) * 2 / channels
- + ((bytes % block_align) ? ((bytes % block_align) - 4 * channels) * 2 / channels : 0); //todo probably not possible (aligned)
+ + ((bytes % block_align) ? ((bytes % block_align) - 4 * channels) * 2 / channels : 0); /* unlikely (encoder aligns) */
+}
+
+size_t apple_ima4_bytes_to_samples(size_t bytes, int channels) {
+ int block_align = 0x22 * channels;
+ return (bytes / block_align) * (block_align - 0x02*channels) * 2 / channels
+ + ((bytes % block_align) ? ((bytes % block_align) - 0x02*channels) * 2 / channels : 0);
}
size_t ubi_ima_bytes_to_samples(size_t bytes, int channels, STREAMFILE *streamFile, off_t offset) {
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/mp4_aac_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/mp4_aac_decoder.c
index 4675b78fc..3712362f1 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/mp4_aac_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/mp4_aac_decoder.c
@@ -86,6 +86,8 @@ void decode_mp4_aac(mp4_aac_codec_data * data, sample * outbuf, int32_t samples_
void reset_mp4_aac(VGMSTREAM *vgmstream) {
mp4_aac_codec_data *data = vgmstream->codec_data;
+ if (!data) return;
+
data->sampleId = 0;
data->sample_ptr = data->samples_per_frame;
data->samples_discard = 0;
@@ -93,6 +95,8 @@ void reset_mp4_aac(VGMSTREAM *vgmstream) {
void seek_mp4_aac(VGMSTREAM *vgmstream, int32_t num_sample) {
mp4_aac_codec_data *data = (mp4_aac_codec_data *)(vgmstream->codec_data);
+ if (!data) return;
+
data->sampleId = 0;
data->sample_ptr = data->samples_per_frame;
data->samples_discard = num_sample;
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils.c b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils.c
index f225f931d..a7737ddf9 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils.c
@@ -58,7 +58,11 @@ int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, m
break;
case MPEG_LYN:
- goto fail; /* not fully implemented */
+ if (data->config.interleave <= 0)
+ goto fail; /* needs external fixed size */
+ data->default_buffer_size = data->config.interleave;
+ //todo simplify/unify XVAG/P3D/SCD/LYN and just feed arbitrary chunks to the decoder
+ break;
case MPEG_STANDARD:
case MPEG_AHX:
@@ -137,9 +141,9 @@ int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
case MPEG_P3D: /* fixed interleave, not frame-aligned (ie. blocks may end/start in part of a frame) */
case MPEG_SCD:
+ case MPEG_LYN:
current_interleave = data->config.interleave;
-#if 1
/* check if current interleave block is short */
{
off_t block_offset = stream->offset - stream->channel_start_offset;
@@ -148,7 +152,7 @@ int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
if (data->config.data_size && block_offset + next_block >= data->config.data_size)
current_interleave = (data->config.data_size % next_block) / data->streams_size; /* short_interleave*/
}
-#endif
+
current_interleave_pre = current_interleave*num_stream;
current_interleave_post = current_interleave*(data->streams_size-1) - current_interleave_pre;
@@ -162,7 +166,7 @@ int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
break;
}
if (!current_data_size || current_data_size > ms->buffer_size) {
- VGM_LOG("MPEG: incorrect data_size 0x%x\n", current_data_size);
+ VGM_LOG("MPEG: incorrect data_size 0x%x vs buffer 0x%x\n", current_data_size, ms->buffer_size);
goto fail;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils_ealayer3.c b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils_ealayer3.c
index c8d827f18..6c1c6d76a 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils_ealayer3.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils_ealayer3.c
@@ -147,10 +147,12 @@ int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *
if (!ealayer3_skip_data(stream, data, num_stream, 0))
goto fail;
-
}
- // todo rarely there is a block between granules (ex. EAL3 v2P in FIFA 2016)
+ /* In EAL3 V2P sometimes there is a new SNS/SPS block between granules. Instead of trying to fix it here
+ * or in blocked layout (too complex/patchy), SNS/SPS uses a custom streamfile that simply removes all
+ * block headers, so this parser only sees raw EALayer3 data. It also discards samples, which confuses
+ * blocked layout calculations */
/* get second frame/granule (MPEG1 only) if first granule was found */
granule_found = 0;
@@ -298,7 +300,7 @@ static int ealayer3_parse_frame_v2(vgm_bitstream *is, ealayer3_frame_info * eaf)
if (!ok) goto fail;
}
VGM_ASSERT(eaf->v2_extended_flag && eaf->v2_common_size == 0, "EA EAL3: v2 empty frame\n"); /* seen in V2S */
- VGM_ASSERT(eaf->v2_extended_flag && eaf->v2_mode_value > 0, "EA EAL3: v2_mode=%x with 0x%x\n", eaf->v2_mode, eaf->v2_mode_value);
+ VGM_ASSERT(eaf->v2_extended_flag && eaf->v2_mode_value > 0, "EA EAL3: v2_mode=%x with value=0x%x\n", eaf->v2_mode, eaf->v2_mode_value);
//VGM_ASSERT(eaf->v2_pcm_number > 0, "EA EAL3: v2_pcm_number 0x%x\n", eaf->v2_pcm_number);
eaf->pcm_size = (2*eaf->v2_pcm_number * eaf->channels);
@@ -550,8 +552,6 @@ static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
size_t bytes_filled;
int i;
- if (!eaf->pcm_size)
- return 1;
bytes_filled = sizeof(sample)*ms->samples_filled*data->channels_per_frame;
if (bytes_filled + eaf->pcm_size > ms->output_buffer_size) {
@@ -561,6 +561,9 @@ static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
if (eaf->v1_pcm_number) {
+ if (!eaf->pcm_size)
+ return 1;
+
VGM_ASSERT(eaf->v1_pcm_decode_discard > 576, "MPEG EAL3: big discard %i at 0x%lx\n", eaf->v1_pcm_decode_discard, stream->offset);
VGM_ASSERT(eaf->v1_pcm_number > 0x100, "MPEG EAL3: big samples %i at 0x%lx\n", eaf->v1_pcm_number, stream->offset);
@@ -583,6 +586,7 @@ static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
decode_to_discard = data->samples_per_frame;//+ eaf->v1_pcm_number;
}
else {
+ // todo also discard
if (decode_to_discard == 0) /* seems ok? */
decode_to_discard += data->samples_per_frame;//+ eaf->v1_pcm_number;
else if (decode_to_discard == 576) /* untested */
@@ -594,17 +598,6 @@ static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
if (eaf->v2_extended_flag) {
- if (eaf->v2_pcm_number) {
- /* read + write PCM block samples (always BE) */
- for (i = 0; i < eaf->v2_pcm_number * data->channels_per_frame; i++) {
- off_t pcm_offset = stream->offset + eaf->pre_size + eaf->common_size + sizeof(sample)*i;
- int16_t pcm_sample = read_16bitBE(pcm_offset,stream->streamfile);
- put_16bitLE(ms->output_buffer + bytes_filled + sizeof(sample)*i, pcm_sample);
- }
- ms->samples_filled += eaf->v2_pcm_number;
- }
-
-#if 0
/* todo supposed skip modes (only seen 0x00):
*
* AB00CCCC CCCCCCCC if A is set: DDEEEEEE EEEEFFFF FFFFFFGG GGGGGGGG
@@ -620,16 +613,27 @@ static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
* if 3: 576
*/
+ //;VGM_LOG("EA EAL3 v2: off=%lx, mode=%x, value=%x, pcm=%x, size=%x\n", stream->offset, eaf->v2_mode, eaf->v2_mode_value, eaf->v2_pcm_number, eaf->v2_common_size);
+
+ if (eaf->v2_pcm_number) {
+ /* read + write PCM block samples (always BE) */
+ for (i = 0; i < eaf->v2_pcm_number * data->channels_per_frame; i++) {
+ off_t pcm_offset = stream->offset + eaf->pre_size + eaf->common_size + sizeof(sample)*i;
+ int16_t pcm_sample = read_16bitBE(pcm_offset,stream->streamfile);
+ put_16bitLE(ms->output_buffer + bytes_filled + sizeof(sample)*i, pcm_sample);
+ }
+ ms->samples_filled += eaf->v2_pcm_number;
+ }
+
/* modify decoded samples depending on flag */
if (eaf->v2_mode == 0x00) {
- size_t decode_to_discard = eaf->v2_mode_value;
-
- if (decode_to_discard == 576)
- decode_to_discard = data->samples_per_frame;//+ eaf->v2_pcm_number;
+ size_t decode_to_discard = eaf->v2_mode_value; /* (usually 0 in V2P, varies in V2S) */
+ if (decode_to_discard == 0)
+ decode_to_discard = 576;
+ //todo output seems correct-ish but reaches file end and tries to parse more frames
ms->decode_to_discard += decode_to_discard;
}
-#endif
}
return 1;
@@ -638,7 +642,7 @@ fail:
}
-/* Skip EA-frames from other streams for multichannel (interleaved 1 EA-frame per stream).
+/* Skip EA-frames from other streams for .sns/sps multichannel (interleaved 1 EA-frame per stream).
* Due to EALayer3 being in blocks and other complexities (we can't go past a block) all
* streams's offsets should start in the first stream's EA-frame.
*
@@ -649,6 +653,8 @@ fail:
* - skip one EA-frame per following streams until offset is in first stream's EA-frame
* (ie. 1st stream skips 2, 2nd stream skips 1, 3rd stream skips 0)
* - repeat again for granule1
+ *
+ * EALayer3 v1 in SCHl uses external offsets and 1ch multichannel instead.
*/
static int ealayer3_skip_data(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, int at_start) {
int ok, i;
@@ -657,6 +663,9 @@ static int ealayer3_skip_data(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, i
uint8_t ibuf[EALAYER3_EA_FRAME_BUFFER_SIZE];
int skips = at_start ? num_stream : data->streams_size - 1 - num_stream;
+ /* v1 does multichannel with set offsets */
+ if (data->type == MPEG_EAL31)
+ return 1;
for (i = 0; i < skips; i++) {
is.buf = ibuf;
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c
index 1c1385acc..ba7f77d96 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c
@@ -130,6 +130,8 @@ mpeg_codec_data *init_mpeg_custom(STREAMFILE *streamFile, off_t start_offset, co
memcpy(&data->config, config, sizeof(mpeg_custom_config));
data->config.channels = channels;
+ data->default_buffer_size = MPEG_DATA_BUFFER_SIZE;
+
/* init per subtype */
switch(data->type) {
case MPEG_EAL31:
@@ -144,6 +146,7 @@ mpeg_codec_data *init_mpeg_custom(STREAMFILE *streamFile, off_t start_offset, co
if (channels <= 0 || channels > 16) goto fail; /* arbitrary max */
if (channels < data->channels_per_frame) goto fail;
+ if (data->default_buffer_size > 0x8000) goto fail;
/* init streams */
@@ -160,7 +163,7 @@ mpeg_codec_data *init_mpeg_custom(STREAMFILE *streamFile, off_t start_offset, co
if (!data->streams[i]->output_buffer) goto fail;
/* one per stream as sometimes mpg123 can't read the whole buffer in one pass */
- data->streams[i]->buffer_size = MPEG_DATA_BUFFER_SIZE;
+ data->streams[i]->buffer_size = data->default_buffer_size;
data->streams[i]->buffer = calloc(sizeof(uint8_t), data->streams[i]->buffer_size);
if (!data->streams[i]->buffer) goto fail;
}
@@ -499,6 +502,7 @@ void free_mpeg(mpeg_codec_data *data) {
void reset_mpeg(VGMSTREAM *vgmstream) {
off_t input_offset;
mpeg_codec_data *data = vgmstream->codec_data;
+ if (!data) return;
/* reset multistream */ //todo check if stream offsets are properly reset
@@ -523,6 +527,7 @@ void reset_mpeg(VGMSTREAM *vgmstream) {
void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
off_t input_offset;
mpeg_codec_data *data = vgmstream->codec_data;
+ if (!data) return;
/* seek multistream */
if (!data->custom) {
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c
index 17fba4b8f..6e25a9286 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c
@@ -22,15 +22,21 @@ void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t sa
void reset_ogg_vorbis(VGMSTREAM *vgmstream) {
+ OggVorbis_File *ogg_vorbis_file;
ogg_vorbis_codec_data *data = vgmstream->codec_data;
- OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
+ if (!data) return;
+
+ ogg_vorbis_file = &(data->ogg_vorbis_file);
ov_pcm_seek(ogg_vorbis_file, 0);
}
void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) {
+ OggVorbis_File *ogg_vorbis_file;
ogg_vorbis_codec_data *data = (ogg_vorbis_codec_data *)(vgmstream->codec_data);
- OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
+ if (!data) return;
+
+ ogg_vorbis_file = &(data->ogg_vorbis_file);
ov_pcm_seek_lap(ogg_vorbis_file, num_sample);
}
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c
index 3e016f949..406f0dff8 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c
@@ -78,15 +78,6 @@ void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspa
}
}
-void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * 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*2*channelspacing,stream->streamfile)^stream->key_xor;
- }
-}
-
static int expand_ulaw(uint8_t ulawbyte) {
int sign, segment, quantization, new_sample;
const int bias = 0x84;
@@ -177,7 +168,7 @@ void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
int sample_pcm;
sample_float = (float*)&sample_int;
- sample_pcm = floor((*sample_float) * 32767.f + .5f);
+ sample_pcm = (int)floor((*sample_float) * 32767.f + .5f);
outbuf[sample_count] = clamp16(sample_pcm);
}
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/psx_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/psx_decoder.c
index a85250ad5..0fcc3751b 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/psx_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/psx_decoder.c
@@ -110,52 +110,6 @@ void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
stream->adpcm_history2_32=hist2;
}
-/* encrypted */
-void decode_psx_bmdx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
-
- int predict_nr, shift_factor, sample;
- int32_t hist1=stream->adpcm_history1_32;
- int32_t hist2=stream->adpcm_history2_32;
-
- short scale;
- int i;
- int32_t sample_count;
- uint8_t flag;
-
- int framesin = first_sample/28;
- int head = read_8bit(stream->offset+framesin*16,stream->streamfile) ^ stream->bmdx_xor;
-
- predict_nr = ((head >> 4) & 0xf);
- shift_factor = (head & 0xf);
- flag = read_8bit(stream->offset+framesin*16+1,stream->streamfile);
-
- first_sample = first_sample % 28;
-
- for (i=first_sample,sample_count=0; ioffset+(framesin*16)+2+i/2,stream->streamfile);
- if (i/2 == 0)
- sample_byte = (short)(int8_t)(sample_byte+stream->bmdx_add);
-
- scale = ((i&1 ?
- sample_byte >> 4 :
- sample_byte & 0x0f)<<12);
-
- sample=(int)((scale >> shift_factor)+hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]);
- }
-
- outbuf[sample_count] = clamp16(sample);
- hist2=hist1;
- hist1=sample;
- }
- stream->adpcm_history1_32=hist1;
- stream->adpcm_history2_32=hist2;
-}
-
/* some games have garbage (?) in their flags, this decoder just ignores that byte */
void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
@@ -257,5 +211,9 @@ void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int cha
size_t ps_bytes_to_samples(size_t bytes, int channels) {
- return bytes / channels / 16 * 28;
+ return bytes / channels / 0x10 * 28;
+}
+
+size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, int channels) {
+ return bytes / channels / frame_size * 28;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_decoder.c
index 29d20a321..b41dbd226 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_decoder.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_decoder.c
@@ -180,7 +180,7 @@ static void pcm_convert_float_to_16(vorbis_custom_codec_data * data, sample * ou
sample *ptr = outbuf + i;
float *mono = pcm[i];
for (j = 0; j < samples_to_do; j++) {
- int val = floor(mono[j] * 32767.f + .5f);
+ int val = (int)floor(mono[j] * 32767.f + .5f);
if (val > 32767) val = 32767;
if (val < -32768) val = -32768;
@@ -207,6 +207,7 @@ void free_vorbis_custom(vorbis_custom_codec_data * data) {
void reset_vorbis_custom(VGMSTREAM *vgmstream) {
vorbis_custom_codec_data *data = vgmstream->codec_data;
+ if (!data) return;
/* Seeking is provided by the Ogg layer, so with custom vorbis we'd need seek tables instead.
* To avoid having to parse different formats we'll just discard until the expected sample */
@@ -216,6 +217,7 @@ void reset_vorbis_custom(VGMSTREAM *vgmstream) {
void seek_vorbis_custom(VGMSTREAM *vgmstream, int32_t num_sample) {
vorbis_custom_codec_data *data = vgmstream->codec_data;
+ if (!data) return;
/* Seeking is provided by the Ogg layer, so with custom vorbis we'd need seek tables instead.
* To avoid having to parse different formats we'll just discard until the expected sample */
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_fsb.c b/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_fsb.c
index 3198da0cc..a8fd60f63 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_fsb.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_fsb.c
@@ -146,7 +146,12 @@ static int build_header_comment(uint8_t * buf, size_t bufsize) {
static int build_header_setup(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile) {
int bytes;
- /* try to load from external files first */
+ /* try to locate from the precompiled list */
+ bytes = load_fvs_array(buf, bufsize, setup_id, streamFile);
+ if (bytes)
+ return bytes;
+
+ /* try to load from external files */
bytes = load_fvs_file_single(buf, bufsize, setup_id, streamFile);
if (bytes)
return bytes;
@@ -155,11 +160,6 @@ static int build_header_setup(uint8_t * buf, size_t bufsize, uint32_t setup_id,
if (bytes)
return bytes;
- /* try to locate from the precompiled list */
- bytes = load_fvs_array(buf, bufsize, setup_id, streamFile);
- if (bytes)
- return bytes;
-
/* not found */
VGM_LOG("FSB Vorbis: setup_id %08x not found\n", setup_id);
return 0;
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_wwise.c b/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_wwise.c
index 73ee1508c..8ddafb51c 100644
--- a/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_wwise.c
+++ b/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_wwise.c
@@ -13,11 +13,11 @@
/* DEFS */
/* **************************************************************************** */
-static int build_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_short, int blocksize_long);
-static int build_header_comment(uint8_t * buf, size_t bufsize);
-static int get_packet_header(STREAMFILE *streamFile, off_t offset, wwise_header_t header_type, int * granulepos, size_t * packet_size, int big_endian);
-static int rebuild_packet(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian);
-static int rebuild_setup(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian, int channels);
+static size_t build_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_short, int blocksize_long);
+static size_t build_header_comment(uint8_t * buf, size_t bufsize);
+static size_t get_packet_header(STREAMFILE *streamFile, off_t offset, wwise_header_t header_type, int * granulepos, size_t * packet_size, int big_endian);
+static size_t rebuild_packet(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian);
+static size_t rebuild_setup(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian, int channels);
static int ww2ogg_generate_vorbis_packet(vgm_bitstream * ow, vgm_bitstream * iw, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian);
static int ww2ogg_generate_vorbis_setup(vgm_bitstream * ow, vgm_bitstream * iw, vorbis_custom_codec_data * data, int channels, size_t packet_size, STREAMFILE *streamFile);
@@ -126,7 +126,7 @@ fail:
/* **************************************************************************** */
/* loads info from a wwise packet header */
-static int get_packet_header(STREAMFILE *streamFile, off_t offset, wwise_header_t header_type, int * granulepos, size_t * packet_size, int big_endian) {
+static size_t get_packet_header(STREAMFILE *streamFile, off_t offset, wwise_header_t header_type, int * granulepos, size_t * packet_size, int big_endian) {
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE;
@@ -153,7 +153,7 @@ static int get_packet_header(STREAMFILE *streamFile, off_t offset, wwise_header_
}
/* Transforms a Wwise data packet into a real Vorbis one (depending on config) */
-static int rebuild_packet(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian) {
+static size_t rebuild_packet(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian) {
vgm_bitstream ow, iw;
int rc, granulepos;
size_t header_size, packet_size;
@@ -196,7 +196,7 @@ fail:
/* Transforms a Wwise setup packet into a real Vorbis one (depending on config). */
-static int rebuild_setup(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian, int channels) {
+static size_t rebuild_setup(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian, int channels) {
vgm_bitstream ow, iw;
int rc, granulepos;
size_t header_size, packet_size;
@@ -238,8 +238,8 @@ fail:
return 0;
}
-static int build_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_0_exp, int blocksize_1_exp) {
- int bytes = 0x1e;
+static size_t build_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_0_exp, int blocksize_1_exp) {
+ size_t bytes = 0x1e;
uint8_t blocksizes;
if (bytes > bufsize) return 0;
@@ -260,8 +260,8 @@ static int build_header_identification(uint8_t * buf, size_t bufsize, int channe
return bytes;
}
-static int build_header_comment(uint8_t * buf, size_t bufsize) {
- int bytes = 0x19;
+static size_t build_header_comment(uint8_t * buf, size_t bufsize) {
+ size_t bytes = 0x19;
if (bytes > bufsize) return 0;
@@ -1098,13 +1098,13 @@ static unsigned int ww2ogg_tremor_book_maptype1_quantvals(unsigned int entries,
static int load_wvc(uint8_t * ibuf, size_t ibufsize, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE *streamFile) {
size_t bytes;
- /* try to load from external file (ignoring type, just use file if found) */
- bytes = load_wvc_file(ibuf, ibufsize, codebook_id, streamFile);
+ /* try to locate from the precompiled list */
+ bytes = load_wvc_array(ibuf, ibufsize, codebook_id, setup_type);
if (bytes)
return bytes;
- /* try to locate from the precompiled list */
- bytes = load_wvc_array(ibuf, ibufsize, codebook_id, setup_type);
+ /* try to load from external file (ignoring type, just use file if found) */
+ bytes = load_wvc_file(ibuf, ibufsize, codebook_id, streamFile);
if (bytes)
return bytes;
diff --git a/Frameworks/vgmstream/vgmstream/src/coding/yamaha_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/yamaha_decoder.c
new file mode 100644
index 000000000..15b1e9af3
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/coding/yamaha_decoder.c
@@ -0,0 +1,158 @@
+#include "../util.h"
+#include "coding.h"
+
+/* fixed point (.8) amount to scale the current step size by */
+/* part of the same series as used in MS ADPCM "ADPCMTable" */
+static const unsigned int scale_step[16] = {
+ 230, 230, 230, 230, 307, 409, 512, 614,
+ 230, 230, 230, 230, 307, 409, 512, 614
+};
+
+/* expand an unsigned four bit delta to a wider signed range */
+static const int scale_delta[16] = {
+ 1, 3, 5, 7, 9, 11, 13, 15,
+ -1, -3, -5, -7, -9,-11,-13,-15
+};
+
+
+/* raw Yamaha ADPCM a.k.a AICA as it's mainly used in Naomi/Dreamcast (also in RIFF and older arcade sound chips). */
+void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo) {
+ int i, sample_count;
+
+ int32_t hist1 = stream->adpcm_history1_16;
+ int step_size = stream->adpcm_step_index;
+
+ /* no header (external setup), pre-clamp for wrong values */
+ if (step_size < 0x7f) step_size = 0x7f;
+ if (step_size > 0x6000) step_size = 0x6000;
+
+ for (i=first_sample,sample_count=0; ioffset + i : /* stereo: one nibble per channel */
+ stream->offset + i/2; /* mono: consecutive nibbles */
+ int nibble_shift = is_stereo ?
+ (!(channel&1) ? 0:4) : /* even = low/L, odd = high/R */
+ (!(i&1) ? 0:4); /* low nibble first */
+
+ /* Yamaha/AICA expand, but same result as IMA's (((delta * 2 + 1) * step) >> 3) */
+ sample_nibble = ((read_8bit(byte_offset,stream->streamfile) >> nibble_shift))&0xf;
+ sample_delta = (step_size * scale_delta[sample_nibble]) / 8;
+ sample_decoded = hist1 + sample_delta;
+
+ outbuf[sample_count] = clamp16(sample_decoded);
+ hist1 = outbuf[sample_count];
+
+ step_size = (step_size * scale_step[sample_nibble]) >> 8;
+ if (step_size < 0x7f) step_size = 0x7f;
+ if (step_size > 0x6000) step_size = 0x6000;
+ }
+
+ stream->adpcm_history1_16 = hist1;
+ stream->adpcm_step_index = step_size;
+}
+
+/* Yamaha ADPCM, in headered frames like MS-IMA. Possibly originated from Yamaha's SMAF tools
+ * (Windows ACM encoder/decoder was given in their site). Some info from Rockbox's yamaha_adpcm.c */
+void decode_yamaha(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
+ int i, sample_count, num_frame;
+ int32_t hist1 = stream->adpcm_history1_32;
+ int step_size = stream->adpcm_step_index;
+
+ /* external interleave */
+ int block_samples = (0x40 - 0x04*channelspacing) * 2 / channelspacing;
+ num_frame = first_sample / block_samples;
+ first_sample = first_sample % block_samples;
+
+ /* header (hist+step) */
+ if (first_sample == 0) {
+ off_t header_offset = stream->offset + 0x40*num_frame + 0x04*channel;
+
+ hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
+ step_size = read_16bitLE(header_offset+0x02,stream->streamfile);
+ if (step_size < 0x7f) step_size = 0x7f;
+ if (step_size > 0x6000) step_size = 0x6000;
+ }
+
+ /* decode nibbles (layout: varies) */
+ for (i=first_sample,sample_count=0; ioffset + 0x40*num_frame + 0x04*channelspacing) + i : /* stereo: one nibble per channel */
+ (stream->offset + 0x40*num_frame + 0x04*channelspacing) + i/2; /* mono: consecutive nibbles */
+ int nibble_shift = (channelspacing == 2) ?
+ (!(channel&1) ? 0:4) :
+ (!(i&1) ? 0:4); /* even = low, odd = high */
+
+ /* Yamaha/AICA expand, but same result as IMA's (((delta * 2 + 1) * step) >> 3) */
+ sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
+ sample_delta = (step_size * scale_delta[sample_nibble]) / 8;
+ sample_decoded = hist1 + sample_delta;
+
+ outbuf[sample_count] = clamp16(sample_decoded);
+ hist1 = outbuf[sample_count];
+
+ step_size = (step_size * scale_step[sample_nibble]) >> 8;
+ if (step_size < 0x7f) step_size = 0x7f;
+ if (step_size > 0x6000) step_size = 0x6000;
+ }
+
+ stream->adpcm_history1_32 = hist1;
+ stream->adpcm_step_index = step_size;
+}
+
+/* Yamaha ADPCM with unknown expand variation (noisy), step size is double of normal Yamaha? */
+void decode_yamaha_nxap(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
+ int i, sample_count, num_frame;
+ int32_t hist1 = stream->adpcm_history1_32;
+ int step_size = stream->adpcm_step_index;
+
+ /* external interleave */
+ int block_samples = (0x40 - 0x4) * 2;
+ num_frame = first_sample / block_samples;
+ first_sample = first_sample % block_samples;
+
+ /* header (hist+step) */
+ if (first_sample == 0) {
+ off_t header_offset = stream->offset + 0x40*num_frame;
+
+ hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
+ step_size = read_16bitLE(header_offset+0x02,stream->streamfile);
+ if (step_size < 0x7f) step_size = 0x7f;
+ if (step_size > 0x6000) step_size = 0x6000;
+ }
+
+ /* decode nibbles (layout: all nibbles from one channel) */
+ for (i=first_sample,sample_count=0; ioffset + 0x40*num_frame + 0x04) + i/2;
+ int nibble_shift = (i&1?4:0); /* low nibble first */
+
+ /* Yamaha expand? */
+ sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
+ sample_delta = (step_size * scale_delta[sample_nibble] / 4) / 8; //todo not ok
+ sample_decoded = hist1 + sample_delta;
+
+ outbuf[sample_count] = clamp16(sample_decoded);
+ hist1 = outbuf[sample_count];
+
+ step_size = (step_size * scale_step[sample_nibble]) >> 8;
+ if (step_size < 0x7f) step_size = 0x7f;
+ if (step_size > 0x6000) step_size = 0x6000;
+ }
+
+ stream->adpcm_history1_32 = hist1;
+ stream->adpcm_step_index = step_size;
+}
+
+size_t aica_bytes_to_samples(size_t bytes, int channels) {
+ /* 2 samples per byte (2 nibbles) in stereo or mono config */
+ return bytes * 2 / channels;
+}
+
+size_t yamaha_bytes_to_samples(size_t bytes, int channels) {
+ int block_align = 0x40;
+
+ return (bytes / block_align) * (block_align - 0x04*channels) * 2 / channels
+ + ((bytes % block_align) ? ((bytes % block_align) - 0x04*channels) * 2 / channels : 0);
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/formats.c b/Frameworks/vgmstream/vgmstream/src/formats.c
index 445b64e3c..8ba3bb0ff 100644
--- a/Frameworks/vgmstream/vgmstream/src/formats.c
+++ b/Frameworks/vgmstream/vgmstream/src/formats.c
@@ -19,6 +19,7 @@ static const char* extension_list[] = {
//"ac3", //FFmpeg, not parsed //common?
"ace", //fake, for tri-Ace's formats (to be removed)
"acm",
+ "ad", //txth/reserved [Xenosaga Freaks (PS2)]
"adm",
"adp",
"adpcm",
@@ -43,7 +44,9 @@ static const char* extension_list[] = {
"ast",
"at3",
"at9",
+ "atsl",
"atsl3",
+ "atsl4",
"atx",
"aud",
"aus",
@@ -86,10 +89,11 @@ static const char* extension_list[] = {
"cbd2",
"ccc",
"cd",
- "cfn",
+ "cfn", //fake extension/header id for .caf (to be removed)
"ckd",
"cnk",
"cps",
+ "cvs",
"cxs",
"da",
@@ -105,8 +109,10 @@ static const char* extension_list[] = {
"dvi",
"dxh",
+ "e4x",
"eam",
"emff",
+ "eno",
"enth",
"exa",
"ezw",
@@ -116,6 +122,7 @@ static const char* extension_list[] = {
"filp",
"flx",
"fsb",
+ "fsv",
"fwav",
"g1l",
@@ -159,10 +166,12 @@ static const char* extension_list[] = {
"khv",
"km9",
"kovs", //.kvs header id
+ "kns",
"kraw",
- "ktss",
+ "ktss", //.kns header id
"kvs",
+ "l",
"laac", //fake extension, for AAC (tri-Ace/FFmpeg)
"lac3", //fake extension, for AC3
"leg",
@@ -170,6 +179,7 @@ static const char* extension_list[] = {
"logg", //fake extension, for OGGs
"lopus", //fake extension, for OPUS
"lpcm",
+ "lpk",
"lps",
"lsf",
"lstm", //fake extension, for STMs
@@ -179,6 +189,7 @@ static const char* extension_list[] = {
"matx",
"mc3",
"mca",
+ "mcadpcm",
"mcg",
"mds",
"mdsp",
@@ -193,9 +204,13 @@ static const char* extension_list[] = {
//"mpc", //FFmpeg, not parsed (musepack) //common
"mpdsp",
"mpds",
+ "ms",
"msa",
+ "msb",
+ "msd",
"msf",
"mss",
+ "msv", //txh/reserved [Fight Club (PS2)]
"msvp",
"mta2",
"mtaf",
@@ -221,6 +236,7 @@ static const char* extension_list[] = {
"omu",
//"opus", //common
"otm",
+ "ovb",
"p1d", //txth/reserved [Farming Simulator 18 (3DS)]
"p2bt",
@@ -228,19 +244,24 @@ static const char* extension_list[] = {
"past",
"pcm",
"pdt",
+ "pk",
"pnb",
"pona",
"pos",
"ps2stm", //fake extension for .stm (to be removed)
- "psh",
+ "psh", // fake extension for VSV(?) Dawn of Mana needs to be checked again
"psnd",
- "psw",
+ "psw", //fake extension for .wam
+ "r",
+ "rac", //txth/reserved [Manhunt (Xbox)]
"rak",
"ras",
"raw",
"rkv",
"rnd",
+ "rof",
+ "rpgmvo",
"rrds",
"rsd",
"rsf",
@@ -282,9 +303,12 @@ static const char* extension_list[] = {
"sgd",
"sgx",
"sl3",
+ "slb", //txth/reserved [THE Nekomura no Hitobito (PS2)]
"sli",
+ "smc",
"smp",
"smpl", //fake extension (to be removed)
+ "smv",
"snd",
"snds",
"sng",
@@ -292,6 +316,7 @@ static const char* extension_list[] = {
"snr",
"sns",
"snu",
+ "son",
"spd",
"spm",
"sps",
@@ -305,6 +330,7 @@ static const char* extension_list[] = {
//"stm", //common
"stma", //fake extension (to be removed)
"str",
+ "stream",
"strm",
"sts",
"stx",
@@ -313,16 +339,19 @@ static const char* extension_list[] = {
"swag",
"swav",
"swd",
+ "switch_audio"
"sx",
"sxd",
"sxd2",
"tec",
"thp",
- "tk1",
"tk5",
"tra",
+ "trj",
+ "trm",
"tun",
+ "txtp",
"tydsp",
"ulw",
@@ -335,24 +364,29 @@ static const char* extension_list[] = {
"vawx",
"vb",
"vbk",
+ "vbx", //txth/reserved [THE Taxi 2 (PS2)]
"vds",
"vdm",
"vgs",
"vgv",
"vig",
+ "vis", //txth/reserved [AirForce Delta (PS2)]
"vms",
"voi",
"vpk",
"vs",
"vsf",
+ "vsv", // official extension for PSH? TODO: recheck Dawn of Mana
"vxn",
"waa",
"wac",
"wad",
+ "waf",
"wam",
"was",
//"wav", //common
+ "wave",
"wavm",
"wb",
"wem",
@@ -364,6 +398,7 @@ static const char* extension_list[] = {
"wsd",
"wsi",
"wv2", //txth/reserved [Slave Zero (PC)]
+ "wve",
"wvs",
"xa",
@@ -379,7 +414,7 @@ static const char* extension_list[] = {
"xss",
"xvag",
"xvas",
- "xwav",
+ "xwav",//fake, to be removed
"xwb",
"xwc",
"xwm", //FFmpeg, not parsed (XWMA)
@@ -425,7 +460,6 @@ typedef struct {
static const coding_info coding_info_list[] = {
{coding_PCM16LE, "Little Endian 16-bit PCM"},
- {coding_PCM16LE_XOR_int, "Little Endian 16-bit PCM with 2 byte interleave and XOR obfuscation"},
{coding_PCM16BE, "Big Endian 16-bit PCM"},
{coding_PCM16_int, "16-bit PCM with 2 byte interleave (block)"},
{coding_PCM8, "8-bit PCM"},
@@ -454,9 +488,8 @@ static const coding_info coding_info_list[] = {
{coding_XA, "CD-ROM XA 4-bit ADPCM"},
{coding_PSX, "Playstation 4-bit ADPCM"},
{coding_PSX_badflags, "Playstation 4-bit ADPCM (bad flags)"},
- {coding_PSX_bmdx, "Playstation 4-bit ADPCM (BMDX encryption)"},
{coding_PSX_cfg, "Playstation 4-bit ADPCM (configurable)"},
- {coding_HEVAG, "Playstation Vita HEVAG 4-bit ADPCM"},
+ {coding_HEVAG, "Sony HEVAG 4-bit ADPCM"},
{coding_EA_XA, "Electronic Arts EA-XA 4-bit ADPCM v1"},
{coding_EA_XA_int, "Electronic Arts EA-XA 4-bit ADPCM v1 (mono/interleave)"},
@@ -471,6 +504,7 @@ static const coding_info coding_info_list[] = {
{coding_3DS_IMA, "3DS IMA 4-bit ADPCM"},
{coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"},
{coding_XBOX_IMA, "XBOX 4-bit IMA ADPCM"},
+ {coding_XBOX_IMA_mch, "XBOX 4-bit IMA ADPCM (multichannel)"},
{coding_XBOX_IMA_int, "XBOX 4-bit IMA ADPCM (mono/interleave)"},
{coding_NDS_IMA, "NDS-style 4-bit IMA ADPCM"},
{coding_DAT4_IMA, "Eurocom DAT4 4-bit IMA ADPCM"},
@@ -488,6 +522,9 @@ static const coding_info coding_info_list[] = {
{coding_MSADPCM, "Microsoft 4-bit ADPCM"},
{coding_WS, "Westwood Studios VBR ADPCM"},
{coding_AICA, "Yamaha AICA 4-bit ADPCM"},
+ {coding_AICA_int, "Yamaha AICA 4-bit ADPCM (mono/interleave)"},
+ {coding_YAMAHA, "Yamaha 4-bit ADPCM"},
+ {coding_YAMAHA_NXAP, "Yamaha NXAP 4-bit ADPCM"},
{coding_NDS_PROCYON, "Procyon Studio Digital Sound Elements NDS 4-bit APDCM"},
{coding_L5_555, "Level-5 0x555 4-bit ADPCM"},
{coding_SASSC, "Activision / EXAKT SASSC 8-bit DPCM"},
@@ -495,25 +532,21 @@ static const coding_info coding_info_list[] = {
{coding_MTAF, "Konami MTAF 4-bit ADPCM"},
{coding_MTA2, "Konami MTA2 4-bit ADPCM"},
{coding_MC3, "Paradigm MC3 3-bit ADPCM"},
+ {coding_FADPCM, "FMOD FADPCM 4-bit ADPCM"},
{coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"},
{coding_SDX2_int, "Squareroot-delta-exact (SDX2) 8-bit DPCM with 1 byte interleave"},
{coding_CBD2, "Cuberoot-delta-exact (CBD2) 8-bit DPCM"},
{coding_CBD2_int, "Cuberoot-delta-exact (CBD2) 8-bit DPCM with 1 byte interleave"},
{coding_ACM, "InterPlay ACM"},
- {coding_NWA0, "NWA DPCM Level 0"},
- {coding_NWA1, "NWA DPCM Level 1"},
- {coding_NWA2, "NWA DPCM Level 2"},
- {coding_NWA3, "NWA DPCM Level 3"},
- {coding_NWA4, "NWA DPCM Level 4"},
- {coding_NWA5, "NWA DPCM Level 5"},
+ {coding_NWA, "VisualArt's NWA DPCM"},
{coding_EA_MT, "Electronic Arts MicroTalk"},
{coding_CRI_HCA, "CRI HCA"},
#ifdef VGM_USE_VORBIS
- {coding_ogg_vorbis, "Ogg Vorbis"},
+ {coding_OGG_VORBIS, "Ogg Vorbis"},
{coding_VORBIS_custom, "Custom Vorbis"},
#endif
#ifdef VGM_USE_MPEG
@@ -544,48 +577,47 @@ static const coding_info coding_info_list[] = {
static const layout_info layout_info_list[] = {
{layout_none, "flat (no layout)"},
{layout_interleave, "interleave"},
- {layout_interleave_shortblock, "interleave with short last block"},
- {layout_mxch_blocked, "MxCh blocked"},
- {layout_ast_blocked, "AST blocked"},
- {layout_halpst_blocked, "HALPST blocked"},
- {layout_xa_blocked, "CD-ROM XA"},
+
+ {layout_segmented, "segmented"},
+ {layout_layered, "layered"},
+ {layout_aix, "AIX"},
+
+ {layout_blocked_mxch, "blocked (MxCh)"},
+ {layout_blocked_ast, "blocked (AST)"},
+ {layout_blocked_halpst, "blocked (HALPST)"},
+ {layout_blocked_xa, "blocked (XA)"},
{layout_blocked_ea_schl, "blocked (EA SCHl)"},
{layout_blocked_ea_1snh, "blocked (EA 1SNh)"},
- {layout_caf_blocked, "CAF blocked"},
- {layout_wsi_blocked, ".wsi blocked"},
- {layout_xvas_blocked, ".xvas blocked"},
- {layout_str_snds_blocked, ".str SNDS blocked"},
- {layout_ws_aud_blocked, "Westwood Studios .aud blocked"},
- {layout_matx_blocked, "Matrix .matx blocked"},
+ {layout_blocked_caf, "blocked (CAF)"},
+ {layout_blocked_wsi, "blocked (WSI)"},
+ {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_vs_blocked, "vs blocked"},
- {layout_emff_ps2_blocked, "EMFF (PS2) blocked"},
- {layout_emff_ngc_blocked, "EMFF (NGC/WII) blocked"},
- {layout_gsb_blocked, "GSB blocked"},
- {layout_thp_blocked, "THP Movie Audio blocked"},
- {layout_filp_blocked, "FILp blocked"},
+ {layout_blocked_vs, "blocked (vs)"},
+ {layout_blocked_emff_ps2, "blocked (EMFF PS2)"},
+ {layout_blocked_emff_ngc, "blocked (EMFF NGC)"},
+ {layout_blocked_gsb, "blocked (GSB)"},
+ {layout_blocked_thp, "blocked (THP Movie Audio)"},
+ {layout_blocked_filp, "blocked (FILP)"},
{layout_blocked_ea_swvr, "blocked (EA SWVR)"},
- {layout_ps2_adm_blocked, "ADM blocked"},
- {layout_dsp_bdsp_blocked, "DSP blocked"},
+ {layout_blocked_adm, "blocked (ADM)"},
+ {layout_blocked_bdsp, "blocked (BDSP)"},
{layout_blocked_ivaud, "blocked (IVAUD)"},
- {layout_ps2_iab_blocked, "IAB blocked"},
- {layout_ps2_strlr_blocked, "The Bouncer STR blocked"},
- {layout_rws_blocked, "RWS blocked"},
- {layout_hwas_blocked, "HWAS blocked"},
- {layout_tra_blocked, "TRA blocked"},
- {layout_acm, "ACM blocked"},
- {layout_mus_acm, "multiple ACM files, ACM blocked"},
- {layout_aix, "AIX interleave, internally 18-byte interleaved"},
- {layout_aax, "AAX blocked, 18-byte interleaved"},
- {layout_scd_int, "SCD multistream interleave"},
+ {layout_blocked_ps2_iab, "blocked (IAB)"},
+ {layout_blocked_ps2_strlr, "blocked (The Bouncer STR)"},
+ {layout_blocked_rws, "blocked (RWS)"},
+ {layout_blocked_hwas, "blocked (HWAS)"},
+ {layout_blocked_tra, "blocked (TRA)"},
{layout_blocked_ea_sns, "blocked (EA SNS)"},
{layout_blocked_awc, "blocked (AWC)"},
{layout_blocked_vgs, "blocked (VGS)"},
{layout_blocked_vawx, "blocked (VAWX)"},
{layout_blocked_xvag_subsong, "blocked (XVAG subsong)"},
-#ifdef VGM_USE_VORBIS
- {layout_ogg_vorbis, "Ogg"},
-#endif
+ {layout_blocked_ea_wve_au00, "blocked (EA WVE au00)"},
+ {layout_blocked_ea_wve_ad10, "blocked (EA WVE Ad10)"},
+ {layout_blocked_sthd, "blocked (STHD)"},
};
static const meta_info meta_info_list[] = {
@@ -642,17 +674,16 @@ static const meta_info meta_info_list[] = {
{meta_PS2_ILD, "ILD header"},
{meta_PS2_PNB, "assumed PNB (PsychoNauts Bgm File) by .pnb extension"},
{meta_XBOX_WAVM, "Xbox WAVM raw header"},
- {meta_XBOX_RIFF, "Microsoft XWAV RIFF header"},
{meta_DSP_STR, "assumed Conan Gamecube STR File by .str extension"},
{meta_EA_SCHL, "Electronic Arts SCHl header (variable)"},
{meta_EA_SCHL_fixed, "Electronic Arts SCHl header (fixed)"},
- {meta_CFN, "tri-Crescendo CAF Header"},
+ {meta_CAF, "tri-Crescendo CAF Header"},
{meta_PS2_VPK, "VPK Header"},
- {meta_GENH, "GENH Generic Header"},
- {meta_DSP_SADB, "sadb header"},
- {meta_SADL, "sadl header"},
+ {meta_GENH, "GENH generic header"},
+ {meta_DSP_SADB, "Procyon Studio SADB header"},
+ {meta_SADL, "Procyon Studio SADL header"},
{meta_PS2_BMDX, "Beatmania .bmdx header"},
- {meta_DSP_WSI, ".wsi header"},
+ {meta_DSP_WSI, "Alone in the Dark .WSI header"},
{meta_AIFC, "Audio Interchange File Format AIFF-C"},
{meta_AIFF, "Audio Interchange File Format"},
{meta_STR_SNDS, ".str SNDS SHDR chunk"},
@@ -662,15 +693,15 @@ static const meta_info meta_info_list[] = {
{meta_PS2_SVS, "Square SVS header"},
{meta_RIFF_WAVE, "RIFF WAVE header"},
{meta_RIFF_WAVE_POS, "RIFF WAVE header and .pos for looping"},
- {meta_NWA, "Visual Art's NWA header"},
- {meta_NWA_NWAINFOINI, "Visual Art's NWA header and NWAINFO.INI for looping"},
- {meta_NWA_GAMEEXEINI, "Visual Art's NWA header and Gameexe.ini for 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_AUS, "Capcom AUS Header"},
{meta_RWS, "RenderWare RWS header"},
{meta_EA_1SNH, "Electronic Arts 1SNh/EACS header"},
- {meta_SL3, "SL3 Header"},
+ {meta_SL3, "Atari Melbourne House SL3 header"},
{meta_FSB1, "FMOD Sample Bank (FSB1) Header"},
{meta_FSB2, "FMOD Sample Bank (FSB2) Header"},
{meta_FSB3, "FMOD Sample Bank (FSB3) Header"},
@@ -694,19 +725,19 @@ static const meta_info meta_info_list[] = {
{meta_BG00, "Falcom BG00 Header"},
{meta_PS2_RSTM, "Rockstar Games RSTM Header"},
{meta_ACM, "InterPlay ACM Header"},
- {meta_MUS_ACM, "MUS playlist and multiple InterPlay ACM Headered files"},
+ {meta_MUS_ACM, "InterPlay MUS ACM header"},
{meta_PS2_KCES, "Konami KCES Header"},
{meta_PS2_DXH, "Tokobot Plus DXH Header"},
- {meta_PS2_PSH, "Dawn of Mana - Seiken Densetsu 4 PSH Header"},
+ {meta_PS2_PSH, "Square Enix PSH/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_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_SCD_PCM, "Lunar: Eternal Blue .PCM header"},
{meta_PS2_PCM, "Konami KCEJ East .PCM header"},
- {meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV Header"},
- {meta_PS2_PSW, "Rayman Raving Rabbids Riff Container File"},
+ {meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV PS2 header"},
{meta_PS2_VAS, "Pro Baseball Spirits 5 VAS Header"},
{meta_PS2_TEC, "assumed TECMO badflagged stream by .tec extension"},
{meta_XBOX_WVS, "Metal Arms WVS Header (XBOX)"},
@@ -724,32 +755,34 @@ static const meta_info meta_info_list[] = {
{meta_NGC_YMF, "YMF DSP Header"},
{meta_PS2_CCC, "CCC Header"},
{meta_PSX_FAG, "FAG Header"},
- {meta_PS2_MIHB, "Merged MIH+MIB"},
+ {meta_PS2_MIHB, "MIH+MIB header"},
{meta_DSP_WII_MUS, "mus header"},
{meta_WII_SNG, "SNG DSP Header"},
- {meta_RSD2VAG, "RSD2/VAG Header"},
- {meta_RSD2PCMB, "RSD2/PCMB Header"},
- {meta_RSD2XADP, "RSD2/XADP Header"},
- {meta_RSD3VAG, "RSD3/VAG Header"},
- {meta_RSD3GADP, "RSD3/GADP Header"},
- {meta_RSD3PCM, "RSD3/PCM Header"},
- {meta_RSD3PCMB, "RSD3/PCMB Header"},
- {meta_RSD4PCMB, "RSD4/PCMB Header"},
- {meta_RSD4PCM, "RSD4/PCM Header"},
- {meta_RSD4RADP, "RSD4/RADP Header"},
- {meta_RSD4VAG, "RSD4/VAG Header"},
- {meta_RSD6XADP, "RSD6/XADP Header"},
- {meta_RSD6VAG, "RSD6/VAG Header"},
- {meta_RSD6WADP, "RSD6/WADP Header"},
- {meta_RSD6RADP, "RSD6/RADP Header"},
- {meta_RSD6XMA, "RSD6/XMA Header"},
+ {meta_RSD2VAG, "Radical RSD2/VAG header"},
+ {meta_RSD2PCMB, "Radical RSD2/PCMB header"},
+ {meta_RSD2XADP, "Radical RSD2/XADP header"},
+ {meta_RSD3VAG, "Radical RSD3/VAG header"},
+ {meta_RSD3GADP, "Radical RSD3/GADP header"},
+ {meta_RSD3PCM, "Radical RSD3/PCM header"},
+ {meta_RSD3PCMB, "Radical RSD3/PCMB header"},
+ {meta_RSD4PCMB, "Radical RSD4/PCMB header"},
+ {meta_RSD4PCM, "Radical RSD4/PCM header"},
+ {meta_RSD4RADP, "Radical RSD4/RADP header"},
+ {meta_RSD4VAG, "Radical RSD4/VAG header"},
+ {meta_RSD6XADP, "Radical RSD6/XADP header"},
+ {meta_RSD6VAG, "Radical RSD6/VAG header"},
+ {meta_RSD6WADP, "Radical RSD6/WADP header"},
+ {meta_RSD6RADP, "Radical RSD6/RADP header"},
+ {meta_RSD6XMA, "Radical RSD6/XMA header"},
+ {meta_RSD6AT3P, "Radical RSD6/AT3+ header"},
+ {meta_RSD6WMA, "Radical RSD6/WMA header"},
{meta_DC_ASD, "ASD Header"},
- {meta_NAOMI_SPSD, "SPSD Header"},
+ {meta_NAOMI_SPSD, "Naomi SPSD header"},
{meta_FFXI_BGW, "BGW BGMStream header"},
{meta_FFXI_SPW, "SPW SeWave header"},
{meta_PS2_ASS, "ASS Header"},
{meta_IDSP, "IDSP Header"},
- {meta_WAA_WAC_WAD_WAM, "WAA/WAC/WAD/WAM RIFF Header"},
+ {meta_UBI_JADE, "Ubisoft Jade RIFF header"},
{meta_PS2_SEG, "SEG (PS2) Header"},
{meta_XBOX_SEG, "SEG (XBOX) Header"},
{meta_NDS_STRM_FFTA2, "Final Fantasy Tactics A2 RIFF Header"},
@@ -775,7 +808,6 @@ static const meta_info meta_info_list[] = {
{meta_NGC_DSP_IADP, "IADP Header"},
{meta_RSTM_shrunken, "Nintendo RSTM header, corrupted by Atlus"},
{meta_RIFF_WAVE_MWV, "RIFF WAVE header with .mwv flavoring"},
- {meta_RIFF_WAVE_SNS, "RIFF WAVE header with .sns flavoring"},
{meta_FFCC_STR, "Final Fantasy: Crystal Chronicles STR header"},
{meta_SAT_BAKA, "BAKA header from Crypt Killer"},
{meta_NDS_SWAV, "SWAV Header"},
@@ -790,8 +822,8 @@ static const meta_info meta_info_list[] = {
{meta_ZSD, "ZSD Header"},
{meta_RedSpark, "RedSpark Header"},
{meta_PC_IVAUD, "assumed GTA IV Audio file by .ivaud extension"},
- {meta_DSP_WII_WSD, "Standard Nintendo DSP headers in .wsd"},
- {meta_WII_NDP, "Vertigo NDP Header"},
+ {meta_DSP_WII_WSD, ".WSD header"},
+ {meta_WII_NDP, "Icon Games NDP header"},
{meta_PS2_SPS, "Ape Escape 2 SPS Header"},
{meta_PS2_XA2_RRP, "Acclaim XA2 Header"},
{meta_NDS_HWAS, "Vicarious Visions HWAS header"},
@@ -804,13 +836,13 @@ static const meta_info meta_info_list[] = {
{meta_NGC_GCUB, "GCub Header"},
{meta_NGC_SCK_DSP, "The Scorpion King SCK Header"},
{meta_NGC_SWD, "PSF + Standard DSP Headers"},
- {meta_CAFF, "Apple Core Audio Format Header"},
+ {meta_CAFF, "Apple Core Audio Format File header"},
{meta_PC_MXST, "Lego Island MxSt Header"},
{meta_SAB, "Team17 SAB header"},
{meta_MAXIS_XA, "Maxis XAI/XAJ Header"},
{meta_EXAKT_SC, "assumed Activision / EXAKT SC by extension"},
{meta_WII_BNS, "Nintendo BNS header"},
- {meta_WII_WAS, "WAS (iSWS) DSP header"},
+ {meta_WII_WAS, "Sumo Digital iSWS header"},
{meta_XBOX_HLWAV, "Half Life 2 bgm header"},
{meta_STX, "Nintendo .stx header"},
{meta_MYSPD, "U-Sing .MYSPD header"},
@@ -820,7 +852,7 @@ static const meta_info meta_info_list[] = {
{meta_DMSG, "RIFF/DMSGsegh header"},
{meta_PONA_3DO, "Policenauts BGM header"},
{meta_PONA_PSX, "Policenauts BGM header"},
- {meta_NGC_DSP_AAAP, "Double standard DSP header in 'AAAp'"},
+ {meta_NGC_DSP_AAAP, "Acclaim Austin AAAp header"},
{meta_NGC_DSP_KONAMI, "Konami DSP header"},
{meta_PS2_STER, "STER Header"},
{meta_BNSF, "Namco Bandai BNSF header"},
@@ -831,25 +863,27 @@ static const meta_info meta_info_list[] = {
{meta_PS2_SMPL, "Homura SMPL header"},
{meta_PS2_MSA, "Psyvariar -Complete Edition- MSA header"},
{meta_PC_SMP, "Ghostbusters .smp Header"},
- {meta_NGC_PDT, "PDT DSP header"},
- {meta_NGC_BO2, "Blood Omen 2 DSP header"},
+ {meta_NGC_PDT, "Hudson .PDT header"},
+ {meta_NGC_RKV, "Legacy of Kain - Blood Omen 2 RKV GC header"},
+ {meta_DSP_DDSP, ".DDSP header"},
{meta_P3D, "Radical P3D header"},
{meta_PS2_TK1, "Tekken TK5STRM1 Header"},
{meta_PS2_ADSC, "ADSC Header"},
{meta_NGC_DSP_MPDS, "MPDS DSP header"},
- {meta_DSP_STR_IG, "Infogrames dual dsp header"},
- {meta_EA_SWVR, "Electronic Arts SWVR header"},
+ {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_NGC_DSP_STH_STR, "STH dsp header"},
{meta_DSP_CABELAS, "Cabelas games dsp header"},
+ {meta_PS2_ADM, "Dragon Quest V .ADM raw header"},
{meta_PS2_LPCM, "LPCM header"},
{meta_PS2_VMS, "VMS Header"},
{meta_XAU, "XPEC XAU header"},
{meta_GH3_BAR, "Guitar Hero III Mobile .bar"},
{meta_FFW, "Freedom Fighters BGM header"},
- {meta_DSP_DSPW, "DSPW dsp header"},
+ {meta_DSP_DSPW, "Capcom DSPW header"},
{meta_PS2_JSTM, "JSTM Header"},
{meta_XVAG, "Sony XVAG header"},
{meta_PS3_CPS, "tri-Crescendo CPS Header"},
@@ -865,7 +899,7 @@ static const meta_info meta_info_list[] = {
{meta_PS2_SPM, "SPM header"},
{meta_X360_TRA, "Terminal Reality .TRA raw header"},
{meta_PS2_VGS, "Princess Soft VGS header"},
- {meta_PS2_IAB, "IAB header"},
+ {meta_PS2_IAB, "Runtime .IAB header"},
{meta_PS2_STRLR, "STR L/R header"},
{meta_LSF_N1NJ4N, ".lsf !n1nj4n header"},
{meta_VAWX, "feelplus VAWX header"},
@@ -895,14 +929,14 @@ static const meta_info meta_info_list[] = {
{meta_CSTM, "Nintendo 3DS CSTM Header"},
{meta_FSTM, "Nintendo Wii U FSTM Header"},
{meta_KT_WIIBGM, "Koei Tecmo WiiBGM Header"},
- {meta_KTSS, "Koei Tecmo Switch Sound Header"},
+ {meta_KTSS, "Koei Tecmo Nintendo Stream KTSS Header"},
{meta_3DS_IDSP, "Nintendo IDSP Header"},
{meta_WIIU_BTSND, "Nintendo Wii U Menu Boot Sound"},
{meta_MCA, "Capcom MCA header"},
{meta_XB3D_ADX, "Xenoblade 3D ADX header"},
{meta_HCA, "CRI MiddleWare HCA Header"},
{meta_PS2_SVAG_SNK, "SNK SVAG header"},
- {meta_PS2_VDS_VDM, "Graffiti Kingdom VDS/VDM header"},
+ {meta_PS2_VDS_VDM, "Procyon Studio VDS/VDM header"},
{meta_X360_CXS, "tri-Crescendo CXS header"},
{meta_AKB, "Square-Enix AKB header"},
{meta_NUB_XMA, "Namco NUB XMA header"},
@@ -917,12 +951,12 @@ static const meta_info meta_info_list[] = {
{meta_GTD, "GTD/GHS header"},
{meta_TA_AAC_X360, "tri-Ace AAC (X360) header"},
{meta_TA_AAC_PS3, "tri-Ace AAC (PS3) header"},
- {meta_TA_AAC_VORBIS, "tri-Ace AAC (Mobile Vorbis) header"},
+ {meta_TA_AAC_MOBILE, "tri-Ace AAC (Mobile) header"},
{meta_PS3_MTA2, "Konami MTA2 header"},
{meta_NGC_ULW, "Criterion ULW raw header"},
{meta_PC_XA30, "Reflections XA30 PC header"},
{meta_WII_04SW, "Reflections 04SW header"},
- {meta_TXTH, "TXTH Generic Header"},
+ {meta_TXTH, "TXTH generic header"},
{meta_EA_BNK, "Electronic Arts BNK header"},
{meta_SK_AUD, "Silicon Knights AUD header"},
{meta_AHX, "CRI AHX header"},
@@ -930,7 +964,7 @@ static const meta_info meta_info_list[] = {
{meta_BINK, "RAD Game Tools Bink header"},
{meta_EA_SNU, "Electronic Arts SNU header"},
{meta_AWC, "Rockstar AWC header"},
- {meta_NSW_OPUS, "Nintendo Switch OPUS header"},
+ {meta_OPUS, "Nintendo Switch OPUS header"},
{meta_PC_AL2, "Illwinter Game Design AL2 raw header"},
{meta_PC_AST, "Capcom AST (PC) header"},
{meta_UBI_SB, "Ubisoft SBx header"},
@@ -956,10 +990,29 @@ static const meta_info meta_info_list[] = {
{meta_SQEX_SAB, "Square-Enix SAB header"},
{meta_SQEX_MAB, "Square-Enix MAB header"},
{meta_OGG_L2SD, "Ogg Vorbis (L2SD)"},
+ {meta_WAF, "KID WAF header"},
+ {meta_WAVE, "EngineBlack .WAVE header"},
+ {meta_WAVE_segmented, "EngineBlack .WAVE header (segmented)"},
+ {meta_SMV, "Cho Aniki Zero .SMV header"},
+ {meta_NXAP, "Nex NXAP header"},
+ {meta_EA_WVE_AU00, "Electronic Arts WVE (au00) header"},
+ {meta_EA_WVE_AD10, "Electronic Arts WVE (Ad10) header"},
+ {meta_STHD, "Dream Factory STHD header"},
+ {meta_MP4, "MP4/AAC header"},
+ {meta_PCM_SRE, "Capcom .PCM+SRE header"},
+ {meta_DSP_MCADPCM, "Bethesda .mcadpcm header"},
+ {meta_UBI_LYN, "Ubisoft LyN RIFF header"},
+ {meta_MSB_MSH, "Sony MSB+MSH header"},
+ {meta_OGG_RPGMV, "Ogg Vorbis (RPGMV header)"},
+ {meta_OGG_ENO, "Ogg Vorbis (ENO header)"},
+ {meta_TXTP, "TXTP generic header"},
+ {meta_SMC_SMH, "Genki SMC+SMH header"},
+ {meta_OGG_YS8, "Ogg Vorbis (Ys VIII header)"},
+ {meta_PPST, "Parappa PPST header"},
+ {meta_OPUS_PPP, "AT9 OPUS header"},
+ {meta_UBI_BAO, "Ubisoft BAO header"},
+ {meta_DSP_SWITCH_AUDIO, "UE4 Switch Audio header"},
-#ifdef VGM_USE_MP4V2
- {meta_MP4, "AAC header"},
-#endif
#ifdef VGM_USE_FFMPEG
{meta_FFmpeg, "FFmpeg supported file format"},
#endif
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/aax_layout.c b/Frameworks/vgmstream/vgmstream/src/layout/aax_layout.c
deleted file mode 100644
index 2e0834ae9..000000000
--- a/Frameworks/vgmstream/vgmstream/src/layout/aax_layout.c
+++ /dev/null
@@ -1,67 +0,0 @@
-#include "layout.h"
-#include "../vgmstream.h"
-#include "../coding/coding.h"
-
-void render_vgmstream_aax(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
- int samples_written=0;
- aax_codec_data *data = vgmstream->codec_data;
-
- while (samples_writtensample_counts[data->current_segment];
-
- if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
- int i;
- data->current_segment = data->loop_segment;
-
- reset_vgmstream(data->adxs[data->current_segment]);
-
- /* carry over the history from the loop point */
- if (data->loop_segment > 0)
- {
- for (i=0;iadxs[0]->channels;i++)
- {
- data->adxs[data->loop_segment]->ch[i].adpcm_history1_32 =
- data->adxs[data->loop_segment-1]->ch[i].adpcm_history1_32;
- data->adxs[data->loop_segment]->ch[i].adpcm_history2_32 =
- data->adxs[data->loop_segment-1]->ch[i].adpcm_history2_32;
- }
- }
- vgmstream->samples_into_block = 0;
- continue;
- }
-
- samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream);
-
- /*printf("samples_to_do=%d,samples_this_block=%d,samples_written=%d,sample_count=%d\n",samples_to_do,samples_this_block,samples_written,sample_count);*/
-
- if (samples_written+samples_to_do > sample_count)
- samples_to_do=sample_count-samples_written;
-
- if (samples_to_do == 0)
- {
- int i;
- data->current_segment++;
- /*printf("advance to %d at %d samples\n",data->current_segment,vgmstream->current_sample);*/
- reset_vgmstream(data->adxs[data->current_segment]);
-
- /* carry over the history from the previous segment */
- for (i=0;iadxs[0]->channels;i++)
- {
- data->adxs[data->current_segment]->ch[i].adpcm_history1_32 =
- data->adxs[data->current_segment-1]->ch[i].adpcm_history1_32;
- data->adxs[data->current_segment]->ch[i].adpcm_history2_32 =
- data->adxs[data->current_segment-1]->ch[i].adpcm_history2_32;
- }
- vgmstream->samples_into_block = 0;
- continue;
- }
-
- render_vgmstream(&buffer[samples_written*data->adxs[data->current_segment]->channels],
- samples_to_do,data->adxs[data->current_segment]);
-
- samples_written += samples_to_do;
- vgmstream->current_sample += samples_to_do;
- vgmstream->samples_into_block+=samples_to_do;
- }
-}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked.c
index b6b1530f4..d59417d84 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked.c
@@ -1,6 +1,8 @@
#include "layout.h"
#include "../vgmstream.h"
+static void block_update(VGMSTREAM * vgmstream);
+
void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written=0;
@@ -34,12 +36,13 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
}
/* probably block bug or EOF, next calcs would give wrong values and buffer segfaults */
- if (samples_this_block <= 0) {
- VGM_LOG("layout_blocked: empty/wrong block\n");
+ if (samples_this_block < 0) {
+ VGM_LOG("layout_blocked: wrong block at 0x%lx\n", vgmstream->current_block_offset);
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample));
- break;
+ break; /* probable infinite loop otherwise */
}
+ /* samples_this_block = 0 is allowed (empty block), will do nothing then move to next block */
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
if (samples_written + samples_to_do > sample_count)
@@ -49,7 +52,7 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer);
}
else {
- /* block end signal (used below): partially 0-set buffer */
+ /* block end signal (used in halpst): partially 0-set buffer */
int i;
for (i = samples_written*vgmstream->channels; i < (samples_written+samples_to_do)*vgmstream->channels; i++) {
buffer[i]=0;
@@ -64,115 +67,10 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
/* move to next block when all samples are consumed */
if (vgmstream->samples_into_block==samples_this_block
/*&& vgmstream->current_sample < vgmstream->num_samples*/) { /* don't go past last block */
- switch (vgmstream->layout_type) {
- case layout_ast_blocked:
- ast_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_mxch_blocked:
- mxch_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_halpst_blocked:
- if (vgmstream->next_block_offset>=0)
- halpst_block_update(vgmstream->next_block_offset,vgmstream);
- else
- vgmstream->current_block_offset = -1;
- break;
- case layout_xa_blocked:
- xa_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_blocked_ea_schl:
- block_update_ea_schl(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_blocked_ea_1snh:
- block_update_ea_1snh(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_caf_blocked:
- caf_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_wsi_blocked:
- wsi_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_str_snds_blocked:
- str_snds_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_ws_aud_blocked:
- ws_aud_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_matx_blocked:
- matx_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_blocked_dec:
- block_update_dec(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_emff_ps2_blocked:
- emff_ps2_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_emff_ngc_blocked:
- emff_ngc_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_gsb_blocked:
- gsb_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_vs_blocked:
- vs_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_xvas_blocked:
- xvas_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_thp_blocked:
- thp_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_filp_blocked:
- filp_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_blocked_ivaud:
- block_update_ivaud(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_blocked_ea_swvr:
- block_update_ea_swvr(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_ps2_adm_blocked:
- ps2_adm_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_dsp_bdsp_blocked:
- dsp_bdsp_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_tra_blocked:
- tra_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_ps2_iab_blocked:
- ps2_iab_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_ps2_strlr_blocked:
- ps2_strlr_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_rws_blocked:
- rws_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_hwas_blocked:
- hwas_block_update(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_blocked_ea_sns:
- block_update_ea_sns(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_blocked_awc:
- block_update_awc(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_blocked_vgs:
- block_update_vgs(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_blocked_vawx:
- block_update_vawx(vgmstream->next_block_offset,vgmstream);
- break;
- case layout_blocked_xvag_subsong:
- block_update_xvag_subsong(vgmstream->next_block_offset,vgmstream);
- break;
- default:
- break;
- }
+ block_update(vgmstream);
/* for VBR these may change */
- frame_size = get_vgmstream_frame_size(vgmstream); /* for VBR these may change */
+ frame_size = get_vgmstream_frame_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
/* get samples in the current block */
@@ -189,3 +87,122 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
}
}
+
+
+static void block_update(VGMSTREAM * vgmstream) {
+ switch (vgmstream->layout_type) {
+ case layout_blocked_ast:
+ block_update_ast(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_mxch:
+ block_update_mxch(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_halpst:
+ if (vgmstream->next_block_offset>=0)
+ block_update_halpst(vgmstream->next_block_offset,vgmstream);
+ else
+ vgmstream->current_block_offset = -1;
+ break;
+ case layout_blocked_xa:
+ block_update_xa(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_ea_schl:
+ block_update_ea_schl(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_ea_1snh:
+ block_update_ea_1snh(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_caf:
+ block_update_caf(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_wsi:
+ block_update_wsi(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_str_snds:
+ block_update_str_snds(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_ws_aud:
+ block_update_ws_aud(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_matx:
+ block_update_matx(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_dec:
+ block_update_dec(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_emff_ps2:
+ block_update_emff_ps2(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_emff_ngc:
+ block_update_emff_ngc(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_gsb:
+ block_update_gsb(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_vs:
+ block_update_vs(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_xvas:
+ block_update_xvas(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_thp:
+ block_update_thp(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_filp:
+ block_update_filp(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_ivaud:
+ block_update_ivaud(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_ea_swvr:
+ block_update_ea_swvr(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_adm:
+ block_update_adm(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_bdsp:
+ block_update_bdsp(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_tra:
+ block_update_tra(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_ps2_iab:
+ block_update_ps2_iab(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_ps2_strlr:
+ block_update_ps2_strlr(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_rws:
+ block_update_rws(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_hwas:
+ block_update_hwas(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_ea_sns:
+ block_update_ea_sns(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_awc:
+ block_update_awc(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_vgs:
+ block_update_vgs(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_vawx:
+ block_update_vawx(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_xvag_subsong:
+ block_update_xvag_subsong(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_ea_wve_au00:
+ block_update_ea_wve_au00(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_ea_wve_ad10:
+ block_update_ea_wve_ad10(vgmstream->next_block_offset,vgmstream);
+ break;
+ case layout_blocked_sthd:
+ block_update_sthd(vgmstream->next_block_offset,vgmstream);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_adm.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_adm.c
new file mode 100644
index 000000000..31d0fcc45
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_adm.c
@@ -0,0 +1,47 @@
+#include "layout.h"
+#include "../vgmstream.h"
+
+/* blocks of 0x1000 with interleave 0x400 but also smaller last interleave */
+void block_update_adm(off_t block_offset, VGMSTREAM * vgmstream) {
+ STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
+ int i, new_full_block;
+ size_t block_size, interleave_size, interleave_data;
+
+ /* no header */
+ interleave_size = 0x400;
+ interleave_data = 0x400;
+ block_size = interleave_size * vgmstream->channels;
+
+ /* every 0x1000 is a full block, signaled by PS-ADPCM flags */
+ new_full_block = (read_8bit(block_offset+0x01, streamFile) == 0x06);
+
+ /* try to autodetect usable interleave data size as can be smaller when a discrete block ends (ex. 0x10~0x50, varies with file) */
+ if (!new_full_block) {
+ off_t next_block_offset = block_offset + block_size;
+
+ while (next_block_offset > block_offset) {
+ next_block_offset -= 0x10;
+
+ /* check if unused line (all blocks should only use flags 0x06/0x03/0x02) */
+ if (read_32bitLE(next_block_offset, streamFile) == 0x00000000) {
+ interleave_data -= 0x10;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ vgmstream->current_block_offset = block_offset;
+ vgmstream->next_block_offset = block_offset + block_size;
+ vgmstream->current_block_size = interleave_data;
+
+ for (i = 0; i < vgmstream->channels; i++) {
+ vgmstream->ch[i].offset = block_offset + interleave_size*i;
+
+ //if (new_full_block) { /* blocks are not discrete */
+ // vgmstream->ch[i].adpcm_history1_32 = 0;
+ // vgmstream->ch[i].adpcm_step_index = 0;
+ //}
+ }
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/ast_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ast.c
similarity index 90%
rename from Frameworks/vgmstream/vgmstream/src/layout/ast_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_ast.c
index d882a0de1..8ff32ba08 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/ast_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ast.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset */
-void ast_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_ast(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = read_32bitBE(
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/bdsp_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_bdsp.c
similarity index 88%
rename from Frameworks/vgmstream/vgmstream/src/layout/bdsp_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_bdsp.c
index 88f640b66..f5e763abd 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/bdsp_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_bdsp.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset */
-void dsp_bdsp_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_bdsp(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_caf.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_caf.c
new file mode 100644
index 000000000..988e77147
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_caf.c
@@ -0,0 +1,21 @@
+#include "layout.h"
+#include "../vgmstream.h"
+
+/* each block is a new CAF header */
+void block_update_caf(off_t block_offset, VGMSTREAM * vgmstream) {
+ STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
+ int i,ch;
+
+ vgmstream->current_block_offset = block_offset;
+ vgmstream->next_block_offset = block_offset + read_32bitBE(block_offset+0x04, streamFile);
+ vgmstream->current_block_size = read_32bitBE(block_offset+0x14, streamFile);
+
+ for (ch = 0; ch < vgmstream->channels; ch++) {
+ vgmstream->ch[ch].offset = block_offset + read_32bitBE(block_offset+0x10+(0x08*ch), streamFile);
+
+ /* re-read coeffs (though blocks seem to repeat them) */
+ for (i = 0; i < 16; i++) {
+ vgmstream->ch[ch].adpcm_coef[i] = read_16bitBE(block_offset+0x34 + 0x2c*ch + 0x02*i, streamFile);
+ }
+ }
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c
index eea96ffd5..169bbaec1 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c
@@ -21,7 +21,7 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
block_samples = 0;
- if (id == 0x5343446C || id == 0x5344454E) { /* "SCDl" "SDEN" audio data */
+ if (id == 0x5343446C || id == 0x5344454E || id == 0x53444652) { /* "SCDl" "SDEN" "SDFR" audio data */
switch(vgmstream->coding_type) {
case coding_PSX:
block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels);
@@ -37,7 +37,7 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
block_size = 0x04;
}
- if (id == 0x5343486C || id == 0x5348454E) { /* "SCHl" "SHEN" end block */
+ if (id == 0x5343486C || id == 0x5348454E || id == 0x53484652) { /* "SCHl" "SHEN" "SHFR" end block */
new_schl = 1;
}
}
@@ -53,8 +53,8 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
break;
block_offset += block_size;
- /* "SCEl" are aligned to 0x80 usually, but causes problems if not 32b-aligned (ex. Need for Speed 2 PC) */
- if ((id == 0x5343456C || id == 0x5345454E) && block_offset % 0x04) {
+ /* "SCEl" "SEEN" "SEFR" are aligned to 0x80 usually, but causes problems if not 32b-aligned (ex. Need for Speed 2 PC) */
+ if ((id == 0x5343456C || id == 0x5345454E || id == 0x53454652) && block_offset % 0x04) {
block_offset += 0x04 - (block_offset % 0x04);
}
}
@@ -93,6 +93,14 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
break;
+ /* id, size, samples */
+ case coding_PCM16_int:
+ for (i = 0; i < vgmstream->channels; i++) {
+ vgmstream->ch[i].offset = block_offset + 0x0c + (i*0x02);
+ }
+
+ break;
+
/* id, size, samples, hists-per-channel, stereo/interleaved data */
case coding_EA_XA:
//case coding_EA_XA_V2: /* handled in default */
@@ -126,14 +134,22 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
break;
#ifdef VGM_USE_MPEG
- /* id, size, samples, offset?, unknown (null for MP2, some constant for all blocks for EALayer3) */
+ /* id, size, samples, offsets, unknown (null for MP2, some size/config for EALayer3; only if not >2ch) */
case coding_MPEG_custom:
case coding_MPEG_layer1:
case coding_MPEG_layer2:
case coding_MPEG_layer3:
case coding_MPEG_ealayer3:
for (i = 0; i < vgmstream->channels; i++) {
- off_t channel_start = read_32bit(block_offset + 0x0C,streamFile);
+ off_t channel_start;
+
+ /* EALayer3 6ch uses 1ch*6 with offsets, no flag in header [Medal of Honor 2010 (PC) movies] */
+ if (vgmstream->channels > 2) {
+ channel_start = read_32bit(block_offset + 0x0C + 0x04*i,streamFile);
+ } else {
+ channel_start = read_32bit(block_offset + 0x0C,streamFile);
+ }
+
vgmstream->ch[i].offset = block_offset + 0x0C + (0x04*vgmstream->channels) + channel_start;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_swvr.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_swvr.c
index d4206b5c5..080443ad2 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_swvr.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_swvr.c
@@ -1,18 +1,97 @@
#include "layout.h"
-#include "../vgmstream.h"
+#include "../coding/coding.h"
-/* set up for the block at the given offset */
+/* EA-style blocks */
void block_update_ea_swvr(off_t block_offset, VGMSTREAM * vgmstream) {
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
int i;
+ size_t block_size, header_size = 0, channel_size = 0, interleave = 0;
+ uint32_t block_id;
int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE;
+ int16_t (*read_16bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_16bitBE : read_16bitLE;
+ block_id = read_32bit(block_offset+0x00, streamFile);
+ block_size = read_32bit(block_offset+0x04, streamFile);
+
+ /* parse blocks (Freekstyle uses multiblocks) */
+ switch(block_id) {
+ case 0x5641474D: /* "VAGM" */
+ if (read_16bit(block_offset+0x1a, streamFile) == 0x0024) {
+ header_size = 0x40;
+ channel_size = (block_size - header_size) / vgmstream->channels;
+
+ /* ignore blocks of other subsongs */
+ {
+ int target_subsong = vgmstream->stream_index ? vgmstream->stream_index : 1;
+ if (read_32bit(block_offset+0x0c, streamFile)+1 != target_subsong) {
+ channel_size = 0;
+ }
+ }
+ } else {
+ header_size = 0x1c;
+ channel_size = (block_size - header_size) / vgmstream->channels;
+ }
+ break;
+ case 0x56414742: /* "VAGB" */
+ if (read_16bit(block_offset+0x1a, streamFile) == 0x6400) {
+ header_size = 0x40;
+ } else {
+ header_size = 0x18;
+ }
+ channel_size = (block_size - header_size) / vgmstream->channels;
+ break;
+
+ case 0x4453504D: /* "DSPM" */
+ header_size = 0x60;
+ channel_size = (block_size - header_size) / vgmstream->channels;
+
+ /* ignore blocks of other subsongs */
+ {
+ int target_subsong = vgmstream->stream_index ? vgmstream->stream_index : 1;
+ if (read_32bit(block_offset+0x0c, streamFile)+1 != target_subsong) {
+ channel_size = 0;
+ }
+ }
+ dsp_read_coefs_be(vgmstream, streamFile, block_offset+0x1a, 0x22);
+ //todo adpcm history?
+ break;
+ case 0x44535042: /* "DSPB" */
+ header_size = 0x40;
+ channel_size = (block_size - header_size) / vgmstream->channels;
+ dsp_read_coefs_be(vgmstream, streamFile, block_offset+0x18, 0x00);
+ //todo adpcm history?
+ break;
+
+ case 0x4D534943: /* "MSIC" */
+ header_size = 0x1c;
+ channel_size = (block_size - header_size) / vgmstream->channels;
+ break;
+ case 0x53484F43: /* "SHOC" (a generic block but hopefully has PC sounds) */
+ header_size = 0x14; //todo the first block is 0x18
+ channel_size = (block_size - header_size) / vgmstream->channels;
+ break;
+
+ case 0x46494C4C: /* "FILL" (FILLs do that up to 0x6000, but at 0x5FFC don't actually have size) */
+ if ((block_offset + 0x04) % 0x6000 == 0)
+ block_size = 0x04;
+ header_size = 0x08;
+ break;
+
+ case 0xFFFFFFFF:
+ channel_size = -1; /* signal bad block */
+ break;
+
+ default: /* ignore, 0 samples */
+ VGM_LOG("EA SWVR: ignored 0x%08x at 0x%lx\n", block_id, block_offset);
+ break;
+ }
+
+ vgmstream->current_block_size = channel_size;
vgmstream->current_block_offset = block_offset;
- vgmstream->current_block_size = read_32bit(vgmstream->current_block_offset+0x04,streamFile)-0x1C;
- vgmstream->next_block_offset = vgmstream->current_block_offset+vgmstream->current_block_size+0x1C;
- vgmstream->current_block_size/=vgmstream->channels;
+ vgmstream->next_block_offset = block_offset + block_size;
- for (i=0;ichannels;i++) {
- vgmstream->ch[i].offset = vgmstream->current_block_offset+0x1C+(vgmstream->current_block_size*i);
+ interleave = vgmstream->coding_type == coding_PCM8_U_int ? 0x1 : channel_size;
+ for (i = 0; i < vgmstream->channels; i++) {
+ vgmstream->ch[i].offset = block_offset + header_size + interleave*i;
}
}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_wve_ad10.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_wve_ad10.c
new file mode 100644
index 000000000..705fd49f3
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_wve_ad10.c
@@ -0,0 +1,30 @@
+#include "layout.h"
+#include "../coding/coding.h"
+
+
+/* EA style blocks, one block per channel when stereo */
+void block_update_ea_wve_ad10(off_t block_offset, VGMSTREAM * vgmstream) {
+ STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
+ int i;
+ size_t block_size, channel_size = 0, interleave = 0;
+ uint32_t block_id;
+
+ block_id = read_32bitBE(block_offset+0x00, streamFile);
+ block_size = read_32bitBE(block_offset+0x04, streamFile);
+
+ /* accept "Ad10/Ad11" audio block/footer */
+ if (block_id == 0x41643130 || block_id == 0x41643131) {
+ channel_size = block_size - 0x08; /* one block per channel */
+ interleave = block_size;
+ block_size = block_size*vgmstream->channels;
+ }
+ /* rest could be "MDEC" video blocks with 0 size/samples */
+
+ vgmstream->current_block_size = channel_size;
+ vgmstream->current_block_offset = block_offset;
+ vgmstream->next_block_offset = block_offset + block_size;
+
+ for (i = 0; i < vgmstream->channels; i++) {
+ vgmstream->ch[i].offset = (block_offset + 0x08) + interleave*i;
+ }
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_wve_au00.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_wve_au00.c
new file mode 100644
index 000000000..038cf5cc8
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_wve_au00.c
@@ -0,0 +1,29 @@
+#include "layout.h"
+#include "../coding/coding.h"
+
+
+/* EA style blocks */
+void block_update_ea_wve_au00(off_t block_offset, VGMSTREAM * vgmstream) {
+ STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
+ int i;
+ size_t block_size, channel_size = 0;
+ uint32_t block_id;
+
+ block_id = read_32bitBE(block_offset+0x00, streamFile);
+ block_size = read_32bitBE(block_offset+0x04, streamFile);
+
+ /* accept "au00/au01" audio block/footer */
+ if (block_id == 0x61753030 || block_id == 0x61753031) {
+ /* adjusted to frame boundaries as blocks have padding */
+ channel_size = ((block_size - 0x10) / vgmstream->interleave_block_size * vgmstream->interleave_block_size) / vgmstream->channels;
+ }
+ /* rest could be "MDEC" video blocks with 0 size/samples */
+
+ vgmstream->current_block_size = channel_size;
+ vgmstream->current_block_offset = block_offset;
+ vgmstream->next_block_offset = block_offset + block_size;
+
+ for (i = 0; i < vgmstream->channels; i++) {
+ vgmstream->ch[i].offset = (block_offset + 0x10) + channel_size*i;
+ }
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/emff_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_emff.c
similarity index 89%
rename from Frameworks/vgmstream/vgmstream/src/layout/emff_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_emff.c
index b3ed7f5f2..41ad197f0 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/emff_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_emff.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset */
-void emff_ps2_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_emff_ps2(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
@@ -17,7 +17,7 @@ void emff_ps2_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
}
}
-void emff_ngc_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_emff_ngc(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/filp_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_filp.c
similarity index 90%
rename from Frameworks/vgmstream/vgmstream/src/layout/filp_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_filp.c
index 550c6e738..6baea3627 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/filp_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_filp.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset */
-void filp_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_filp(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/gsb_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_gsb.c
similarity index 93%
rename from Frameworks/vgmstream/vgmstream/src/layout/gsb_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_gsb.c
index eccd40d8d..29a417711 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/gsb_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_gsb.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset */
-void gsb_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_gsb(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
int block_header_size = 0x20; /*from header*/
int block_channel_size = 0x8000; /*from header, per channel*/
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/halpst_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_halpst.c
similarity index 92%
rename from Frameworks/vgmstream/vgmstream/src/layout/halpst_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_halpst.c
index 7c36c1bf8..d9ec3763e 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/halpst_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_halpst.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset */
-void halpst_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_halpst(off_t block_offset, VGMSTREAM * vgmstream) {
int i, header_length;
/* header length must be a multiple of 0x20 */
header_length = (4+8*vgmstream->channels+0x1f)/0x20*0x20;
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/hwas_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_hwas.c
similarity index 90%
rename from Frameworks/vgmstream/vgmstream/src/layout/hwas_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_hwas.c
index f55a40fc5..dbd4fd700 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/hwas_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_hwas.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* a simple headerless block with special adpcm history handling */
-void hwas_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_hwas(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
size_t block_size;
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/ims_block.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_matx.c
similarity index 90%
rename from Frameworks/vgmstream/vgmstream/src/layout/ims_block.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_matx.c
index c5df59480..e69a05038 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/ims_block.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_matx.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset */
-void matx_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_matx(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/mxch_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_mxch.c
similarity index 91%
rename from Frameworks/vgmstream/vgmstream/src/layout/mxch_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_mxch.c
index 8e49a4a95..f15afbcbb 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/mxch_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_mxch.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
//MxCh blocked layout as used by Lego Island
-void mxch_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_mxch(off_t block_offset, VGMSTREAM * vgmstream) {
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset +
read_32bitLE(vgmstream->current_block_offset+4,vgmstream->ch[0].streamfile)+8;
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ps2_iab.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ps2_iab.c
new file mode 100644
index 000000000..5ec5a0613
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ps2_iab.c
@@ -0,0 +1,22 @@
+#include "layout.h"
+#include "../vgmstream.h"
+
+/* blocks with mini header (0x48124812 + unknown + block data + block size) */
+void block_update_ps2_iab(off_t block_offset, VGMSTREAM * vgmstream) {
+ STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
+ int i;
+ size_t block_size, channel_size;
+
+ channel_size = read_32bitLE(block_offset+0x08,streamFile) / vgmstream->channels;
+ block_size = read_32bitLE(block_offset+0x0c,streamFile);
+ if (!block_size)
+ block_size = 0x10; /* happens on last block */
+
+ vgmstream->current_block_size = channel_size;
+ vgmstream->current_block_offset = block_offset;
+ vgmstream->next_block_offset = block_offset + block_size;
+
+ for (i = 0; i < vgmstream->channels; i++) {
+ vgmstream->ch[i].offset = block_offset + 0x10 + channel_size*i;
+ }
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/ps2_strlr_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ps2_strlr.c
similarity index 89%
rename from Frameworks/vgmstream/vgmstream/src/layout/ps2_strlr_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_ps2_strlr.c
index 7bf23bda5..d2834db50 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/ps2_strlr_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ps2_strlr.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset */
-void ps2_strlr_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_ps2_strlr(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/rws_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_rws.c
similarity index 87%
rename from Frameworks/vgmstream/vgmstream/src/layout/rws_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_rws.c
index 23b90c535..7d3fee2a5 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/rws_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_rws.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* a simple headerless block with padding; configured in the main header */
-void rws_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_rws(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
size_t block_size;
size_t interleave;
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_sthd.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_sthd.c
new file mode 100644
index 000000000..2d9d9fbcf
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_sthd.c
@@ -0,0 +1,22 @@
+#include "layout.h"
+
+/* Dream Factory STHD blocks */
+void block_update_sthd(off_t block_offset, VGMSTREAM * vgmstream) {
+ STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
+ size_t block_size, channel_size;
+ off_t data_offset;
+ int i;
+
+ block_size = 0x800;
+ data_offset = read_16bitLE(block_offset + 0x04, streamFile);
+ channel_size = read_16bitLE(block_offset + 0x16, streamFile);
+ /* 0x06: num channels, 0x10: total blocks, 0x12: block count, 0x14(2): null, 0x18: block count + 1 */
+
+ vgmstream->current_block_offset = block_offset;
+ vgmstream->current_block_size = channel_size;
+ vgmstream->next_block_offset = block_offset + block_size;
+
+ for (i = 0; i < vgmstream->channels; i++) {
+ vgmstream->ch[i].offset = block_offset + data_offset + channel_size*i;
+ }
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/str_snds_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_str_snds.c
similarity index 96%
rename from Frameworks/vgmstream/vgmstream/src/layout/str_snds_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_str_snds.c
index 91b64d60e..7a7fca9ac 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/str_snds_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_str_snds.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset */
-void str_snds_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_str_snds(off_t block_offset, VGMSTREAM * vgmstream) {
off_t current_chunk;
size_t file_size;
int i;
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/thp_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_thp.c
similarity index 94%
rename from Frameworks/vgmstream/vgmstream/src/layout/thp_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_thp.c
index 828d6c8de..abea3e2c7 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/thp_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_thp.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset */
-void thp_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_thp(off_t block_offset, VGMSTREAM * vgmstream) {
int i,j;
STREAMFILE *streamFile=vgmstream->ch[0].streamfile;
off_t start_offset;
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/tra_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_tra.c
similarity index 89%
rename from Frameworks/vgmstream/vgmstream/src/layout/tra_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_tra.c
index cc235f723..db29fe8ed 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/tra_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_tra.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset (first 32bytes is useless for decoding) */
-void tra_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_tra(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/vs_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_vs.c
similarity index 89%
rename from Frameworks/vgmstream/vgmstream/src/layout/vs_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_vs.c
index 76e4cb277..4284642d5 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/vs_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_vs.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset */
-void vs_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_vs(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
for (i=0;ichannels;i++) {
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/ws_aud_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ws_aud.c
similarity index 92%
rename from Frameworks/vgmstream/vgmstream/src/layout/ws_aud_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_ws_aud.c
index dfc824a57..6912060e2 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/ws_aud_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ws_aud.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset */
-void ws_aud_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_ws_aud(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = read_16bitLE(
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_wsi.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_wsi.c
new file mode 100644
index 000000000..572c6cc12
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_wsi.c
@@ -0,0 +1,21 @@
+#include "layout.h"
+#include "../vgmstream.h"
+
+/* .wsi - headered blocks with a single channel */
+void block_update_wsi(off_t block_offset, VGMSTREAM * vgmstream) {
+ STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
+ int i;
+ off_t channel_block_size;
+
+
+ /* assume that all channels have the same size for this block */
+ channel_block_size = read_32bitBE(block_offset, streamFile);
+
+ vgmstream->current_block_offset = block_offset;
+ vgmstream->current_block_size = channel_block_size - 0x10; /* remove header */
+ vgmstream->next_block_offset = block_offset + channel_block_size*vgmstream->channels;
+
+ for (i = 0; i < vgmstream->channels; i++) {
+ vgmstream->ch[i].offset = block_offset + channel_block_size*i + 0x10;
+ }
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/xa_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_xa.c
similarity index 97%
rename from Frameworks/vgmstream/vgmstream/src/layout/xa_blocked.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_xa.c
index bd208fd28..e7829b68a 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/xa_blocked.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_xa.c
@@ -3,7 +3,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset */
-void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_xa(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
int8_t currentChannel=0;
int8_t subAudio=0;
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/xvas_block.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_xvas.c
similarity index 91%
rename from Frameworks/vgmstream/vgmstream/src/layout/xvas_block.c
rename to Frameworks/vgmstream/vgmstream/src/layout/blocked_xvas.c
index ee78c3ad1..a26ed0da3 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/xvas_block.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_xvas.c
@@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* set up for the block at the given offset */
-void xvas_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
+void block_update_xvas(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/caf_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/caf_blocked.c
deleted file mode 100644
index d944baa01..000000000
--- a/Frameworks/vgmstream/vgmstream/src/layout/caf_blocked.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include "layout.h"
-#include "../vgmstream.h"
-
-/* set up for the block at the given offset */
-void caf_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
- int i;
-
- vgmstream->current_block_offset = block_offset;
- vgmstream->current_block_size = read_32bitBE(
- vgmstream->current_block_offset+0x14,
- vgmstream->ch[0].streamfile);
- vgmstream->next_block_offset = vgmstream->current_block_offset +
- (off_t)read_32bitBE(vgmstream->current_block_offset+0x04,
- vgmstream->ch[0].streamfile);
-
- for (i=0;ichannels;i++) {
- vgmstream->ch[i].offset = vgmstream->current_block_offset +
- read_32bitBE(block_offset+0x10+(8*i),vgmstream->ch[0].streamfile);
- }
-
- /* coeffs */
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(block_offset+0x34+(2*i),vgmstream->ch[0].streamfile);
- vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(block_offset+0x60+(2*i),vgmstream->ch[0].streamfile);
- }
-}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/interleave.c b/Frameworks/vgmstream/vgmstream/src/layout/interleave.c
index f10ee574e..6090d197d 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/interleave.c
+++ b/Frameworks/vgmstream/vgmstream/src/layout/interleave.c
@@ -10,12 +10,12 @@ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREA
samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame;
- if (vgmstream->layout_type == layout_interleave_shortblock &&
+ if (vgmstream->interleave_last_block_size && vgmstream->channels > 1 &&
vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block> vgmstream->num_samples) {
frame_size = get_vgmstream_shortframe_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream);
- samples_this_block = vgmstream->interleave_smallblock_size / frame_size * samples_per_frame;
+ samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame;
}
while (samples_writtenloop_flag && vgmstream_do_loop(vgmstream)) {
/* we assume that the loop is not back into a short block */
- if (vgmstream->layout_type == layout_interleave_shortblock) {
+ if (vgmstream->interleave_last_block_size && vgmstream->channels > 1) {
frame_size = get_vgmstream_frame_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame;
@@ -45,14 +45,14 @@ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREA
if (vgmstream->samples_into_block==samples_this_block) {
int chan;
- if (vgmstream->layout_type == layout_interleave_shortblock &&
+ if (vgmstream->interleave_last_block_size && vgmstream->channels > 1 &&
vgmstream->current_sample + samples_this_block > vgmstream->num_samples) {
frame_size = get_vgmstream_shortframe_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream);
- samples_this_block = vgmstream->interleave_smallblock_size / frame_size * samples_per_frame;
+ samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame;
for (chan=0;chanchannels;chan++)
- vgmstream->ch[chan].offset+=vgmstream->interleave_block_size*(vgmstream->channels-chan)+vgmstream->interleave_smallblock_size*chan;
+ vgmstream->ch[chan].offset+=vgmstream->interleave_block_size*(vgmstream->channels-chan)+vgmstream->interleave_last_block_size*chan;
} else {
for (chan=0;chanchannels;chan++)
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/layered.c b/Frameworks/vgmstream/vgmstream/src/layout/layered.c
new file mode 100644
index 000000000..bfaaec4b8
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/layout/layered.c
@@ -0,0 +1,129 @@
+#include "layout.h"
+#include "../vgmstream.h"
+
+/* TODO: there must be a reasonable way to respect the loop settings, as
+ the substreams are in their own little world.
+ Currently the VGMSTREAMs layers loop internally and the external/base VGMSTREAM
+ doesn't actually loop, and would ignore any altered values/loop_flag. */
+
+#define LAYER_BUF_SIZE 512
+#define LAYER_MAX_CHANNELS 6 /* at least 2, but let's be generous */
+
+
+void render_vgmstream_layered(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
+ sample interleave_buf[LAYER_BUF_SIZE*LAYER_MAX_CHANNELS];
+ int32_t samples_done = 0;
+ layered_layout_data *data = vgmstream->layout_data;
+
+ while (samples_done < sample_count) {
+ int32_t samples_to_do = LAYER_BUF_SIZE;
+ int layer;
+
+ if (samples_to_do > sample_count - samples_done)
+ samples_to_do = sample_count - samples_done;
+
+ for (layer = 0; layer < data->layer_count; layer++) {
+ int s,l_ch;
+ int layer_channels = data->layers[layer]->channels;
+
+ render_vgmstream(interleave_buf, samples_to_do, data->layers[layer]);
+
+ for (l_ch = 0; l_ch < layer_channels; l_ch++) {
+ for (s = 0; s < samples_to_do; s++) {
+ size_t layer_sample = s*layer_channels + l_ch;
+ size_t buffer_sample = (samples_done+s)*vgmstream->channels + (layer*layer_channels+l_ch);
+
+ buffer[buffer_sample] = interleave_buf[layer_sample];
+ }
+ }
+
+ }
+
+ samples_done += samples_to_do;
+ }
+}
+
+
+layered_layout_data* init_layout_layered(int layer_count) {
+ layered_layout_data *data = NULL;
+
+ if (layer_count <= 0 || layer_count > 255)
+ goto fail;
+
+ data = calloc(1, sizeof(layered_layout_data));
+ if (!data) goto fail;
+
+ data->layer_count = layer_count;
+
+ data->layers = calloc(layer_count, sizeof(VGMSTREAM*));
+ if (!data->layers) goto fail;
+
+ return data;
+fail:
+ free_layout_layered(data);
+ return NULL;
+}
+
+int setup_layout_layered(layered_layout_data* data) {
+ int i;
+
+ /* setup each VGMSTREAM (roughly equivalent to vgmstream.c's init_vgmstream_internal stuff) */
+ for (i = 0; i < data->layer_count; i++) {
+ if (!data->layers[i])
+ goto fail;
+
+ if (data->layers[i]->num_samples <= 0)
+ goto fail;
+
+ if (data->layers[i]->channels > LAYER_MAX_CHANNELS)
+ goto fail;
+
+ if (i > 0) {
+ /* a bit weird, but no matter */
+ if (data->layers[i]->sample_rate != data->layers[i-1]->sample_rate) {
+ VGM_LOG("layered layout: layer %i has different sample rate\n", i);
+ }
+
+ /* also weird */
+ if (data->layers[i]->coding_type != data->layers[i-1]->coding_type) {
+ VGM_LOG("layered layout: layer %i has different coding type\n", i);
+ }
+ }
+
+ //todo could check if layers'd loop match vs main, etc
+
+ /* save start things so we can restart for seeking/looping */
+ memcpy(data->layers[i]->start_ch,data->layers[i]->ch,sizeof(VGMSTREAMCHANNEL)*data->layers[i]->channels);
+ memcpy(data->layers[i]->start_vgmstream,data->layers[i],sizeof(VGMSTREAM));
+ }
+
+ return 1;
+fail:
+ return 0; /* caller is expected to free */
+}
+
+void free_layout_layered(layered_layout_data *data) {
+ int i;
+
+ if (!data)
+ return;
+
+ if (data->layers) {
+ for (i = 0; i < data->layer_count; i++) {
+ close_vgmstream(data->layers[i]);
+ }
+ free(data->layers);
+ }
+ free(data);
+}
+
+void reset_layout_layered(layered_layout_data *data) {
+ int i;
+
+ if (!data)
+ return;
+
+ for (i = 0; i < data->layer_count; i++) {
+ reset_vgmstream(data->layers[i]);
+ }
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/layout.h b/Frameworks/vgmstream/vgmstream/src/layout/layout.h
index 466281eff..a8fc78343 100644
--- a/Frameworks/vgmstream/vgmstream/src/layout/layout.h
+++ b/Frameworks/vgmstream/vgmstream/src/layout/layout.h
@@ -7,78 +7,60 @@
/* blocked layouts */
void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
-void ast_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
-
-void mxch_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
-
-void halpst_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
-
-void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
+void block_update_ast(off_t block_ofset, VGMSTREAM * vgmstream);
+void block_update_mxch(off_t block_ofset, VGMSTREAM * vgmstream);
+void block_update_halpst(off_t block_ofset, VGMSTREAM * vgmstream);
+void block_update_xa(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_ea_1snh(off_t block_offset, VGMSTREAM * vgmstream);
-
-void caf_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void wsi_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void str_snds_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void ws_aud_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void matx_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
+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 vs_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void emff_ps2_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void emff_ngc_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void gsb_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void xvas_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void thp_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void filp_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
+void block_update_vs(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_emff_ps2(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_emff_ngc(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_gsb(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_xvas(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_thp(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_filp(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_ivaud(off_t block_offset, VGMSTREAM * vgmstream);
-
void block_update_ea_swvr(off_t block_offset, VGMSTREAM * vgmstream);
-
-void ps2_adm_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void dsp_bdsp_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void tra_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void ps2_iab_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void ps2_strlr_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void rws_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
-void hwas_block_update(off_t block_offset, VGMSTREAM * vgmstream);
-
+void block_update_adm(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_bdsp(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_tra(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_ps2_iab(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_ps2_strlr(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_rws(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_hwas(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_vgs(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_vawx(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_xvag_subsong(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_ea_wve_au00(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_ea_wve_ad10(off_t block_offset, VGMSTREAM * vgmstream);
+void block_update_sthd(off_t block_offset, VGMSTREAM * vgmstream);
/* other layouts */
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void render_vgmstream_nolayout(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
-void render_vgmstream_mus_acm(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
-
void render_vgmstream_aix(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
-void render_vgmstream_aax(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
+void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
+segmented_layout_data* init_layout_segmented(int segment_count);
+int setup_layout_segmented(segmented_layout_data* data);
+void free_layout_segmented(segmented_layout_data *data);
+void reset_layout_segmented(segmented_layout_data *data);
-void render_vgmstream_scd_int(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
+void render_vgmstream_layered(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
+layered_layout_data* init_layout_layered(int layer_count);
+int setup_layout_layered(layered_layout_data* data);
+void free_layout_layered(layered_layout_data *data);
+void reset_layout_layered(layered_layout_data *data);
#endif
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/mus_acm_layout.c b/Frameworks/vgmstream/vgmstream/src/layout/mus_acm_layout.c
deleted file mode 100644
index bda82b501..000000000
--- a/Frameworks/vgmstream/vgmstream/src/layout/mus_acm_layout.c
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "layout.h"
-#include "../vgmstream.h"
-#include "../coding/acm_decoder.h"
-#include "../coding/coding.h"
-
-void render_vgmstream_mus_acm(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
- int samples_written=0;
- mus_acm_codec_data *data = vgmstream->codec_data;
-
- while (samples_writtenfiles[data->current_file];
- int samples_to_do;
- int samples_this_block = acm->total_values / acm->info.channels;
-
- if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
- data->current_file = data->loop_start_file;
- acm_reset(data->files[data->current_file]);
- vgmstream->samples_into_block = 0;
- continue;
- }
-
- samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream);
-
- /*printf("samples_to_do=%d,samples_this_block=%d,samples_written=%d,sample_count=%d\n",samples_to_do,samples_this_block,samples_written,sample_count);*/
-
- if (samples_written+samples_to_do > sample_count)
- samples_to_do=sample_count-samples_written;
-
- if (samples_to_do == 0)
- {
- data->current_file++;
- /*printf("next %d, %d samples\n",data->current_file,data->files[data->current_file]->total_values/data->files[data->current_file]->info.channels);*/
- /* force loop back to first file in case we're still playing for some
- * reason, prevent out of bounds stuff */
- if (data->current_file >= data->file_count) data->current_file = 0;
- acm_reset(data->files[data->current_file]);
- vgmstream->samples_into_block = 0;
- continue;
- }
-
- /*printf("decode %d samples file %d\n",samples_to_do,data->current_file);*/
- decode_acm(acm,
- buffer+samples_written*vgmstream->channels,
- samples_to_do, vgmstream->channels);
-
- samples_written += samples_to_do;
- vgmstream->current_sample += samples_to_do;
- vgmstream->samples_into_block+=samples_to_do;
- }
-}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/ps2_adm_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/ps2_adm_blocked.c
deleted file mode 100644
index 87c7c606e..000000000
--- a/Frameworks/vgmstream/vgmstream/src/layout/ps2_adm_blocked.c
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "layout.h"
-#include "../vgmstream.h"
-
-/* set up for the block at the given offset */
-void ps2_adm_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
- int i;
-
- vgmstream->current_block_offset = block_offset;
- vgmstream->current_block_size = 0x1000; /*read_32bitLE(
- vgmstream->current_block_offset+0x10,
- vgmstream->ch[0].streamfile); */
- vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size;
- //vgmstream->current_block_size/=vgmstream->channels;
-
- for (i=0;ichannels;i++) {
- vgmstream->ch[i].offset = vgmstream->current_block_offset+(0x400*i);
- }
-}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/ps2_iab_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/ps2_iab_blocked.c
deleted file mode 100644
index 0b375b1ea..000000000
--- a/Frameworks/vgmstream/vgmstream/src/layout/ps2_iab_blocked.c
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "layout.h"
-#include "../vgmstream.h"
-
-/* set up for the block at the given offset */
-void ps2_iab_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
- int i;
-
- vgmstream->current_block_offset = block_offset;
- vgmstream->current_block_size = read_32bitLE(vgmstream->current_block_offset+0x08,vgmstream->ch[0].streamfile);
- vgmstream->next_block_offset = vgmstream->current_block_offset+vgmstream->current_block_size+0x10;
- vgmstream->current_block_size/=vgmstream->channels;
-
- for (i=0;ichannels;i++) {
- vgmstream->ch[i].offset = vgmstream->current_block_offset+0x10+(vgmstream->current_block_size*i);
-
- }
-}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/scd_int_layout.c b/Frameworks/vgmstream/vgmstream/src/layout/scd_int_layout.c
deleted file mode 100644
index 1a2c5e8a9..000000000
--- a/Frameworks/vgmstream/vgmstream/src/layout/scd_int_layout.c
+++ /dev/null
@@ -1,38 +0,0 @@
-#include "layout.h"
-#include "../vgmstream.h"
-
-/* TODO: currently only properly handles mono substreams */
-/* TODO: there must be a reasonable way to respect the loop settings, as is
- the substreams are in their own little world */
-
-#define INTERLEAVE_BUF_SIZE 512
-void render_vgmstream_scd_int(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
- sample interleave_buf[INTERLEAVE_BUF_SIZE];
- int32_t samples_done = 0;
- scd_int_codec_data *data = vgmstream->codec_data;
-
- while (samples_done < sample_count)
- {
- int32_t samples_to_do = INTERLEAVE_BUF_SIZE;
- int c;
- if (samples_to_do > sample_count - samples_done)
- samples_to_do = sample_count - samples_done;
-
- for (c=0; c < data->substream_count; c++)
- {
- int32_t i;
-
- render_vgmstream(interleave_buf,
- samples_to_do, data->substreams[c]);
-
- for (i=0; i < samples_to_do; i++)
- {
- buffer[(samples_done+i)*data->substream_count + c] = interleave_buf[i];
- }
- }
-
- samples_done += samples_to_do;
-
- }
-}
-
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/segmented.c b/Frameworks/vgmstream/vgmstream/src/layout/segmented.c
new file mode 100644
index 000000000..4f2b70737
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/layout/segmented.c
@@ -0,0 +1,136 @@
+#include "layout.h"
+#include "../vgmstream.h"
+
+
+void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
+ int samples_written=0;
+ segmented_layout_data *data = vgmstream->layout_data;
+ //int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
+
+ while (samples_writtensegments[data->current_segment]->num_samples;
+
+ if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
+ //todo can only loop in a segment start
+ // (for arbitrary values find loop segment from loop_start_sample, and skip N samples until loop start)
+ data->current_segment = data->loop_segment;
+
+ reset_vgmstream(data->segments[data->current_segment]);
+
+ vgmstream->samples_into_block = 0;
+ continue;
+ }
+
+ samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream);
+
+ if (samples_written+samples_to_do > sample_count)
+ samples_to_do=sample_count-samples_written;
+
+ if (samples_to_do == 0) {
+ data->current_segment++;
+ reset_vgmstream(data->segments[data->current_segment]);
+
+ vgmstream->samples_into_block = 0;
+ continue;
+ }
+
+ render_vgmstream(&buffer[samples_written*data->segments[data->current_segment]->channels],
+ samples_to_do,data->segments[data->current_segment]);
+
+ samples_written += samples_to_do;
+ vgmstream->current_sample += samples_to_do;
+ vgmstream->samples_into_block+=samples_to_do;
+ }
+}
+
+
+segmented_layout_data* init_layout_segmented(int segment_count) {
+ segmented_layout_data *data = NULL;
+
+ if (segment_count <= 0 || segment_count > 255)
+ goto fail;
+
+ data = calloc(1, sizeof(segmented_layout_data));
+ if (!data) goto fail;
+
+ data->segment_count = segment_count;
+ data->current_segment = 0;
+
+ data->segments = calloc(segment_count, sizeof(VGMSTREAM*));
+ if (!data->segments) goto fail;
+
+ return data;
+fail:
+ free_layout_segmented(data);
+ return NULL;
+}
+
+int setup_layout_segmented(segmented_layout_data* data) {
+ int i;
+
+ /* setup each VGMSTREAM (roughly equivalent to vgmstream.c's init_vgmstream_internal stuff) */
+ for (i = 0; i < data->segment_count; i++) {
+ if (!data->segments[i])
+ goto fail;
+
+ if (data->segments[i]->num_samples <= 0)
+ goto fail;
+
+ /* shouldn't happen */
+ if (data->segments[i]->loop_flag != 0) {
+ VGM_LOG("segmented layout: segment %i is looped\n", i);
+ data->segments[i]->loop_flag = 0;
+ }
+
+ if (i > 0) {
+ if (data->segments[i]->channels != data->segments[i-1]->channels)
+ goto fail;
+
+ /* a bit weird, but no matter */
+ if (data->segments[i]->sample_rate != data->segments[i-1]->sample_rate) {
+ VGM_LOG("segmented layout: segment %i has different sample rate\n", i);
+ }
+
+ //if (data->segments[i]->coding_type != data->segments[i-1]->coding_type)
+ // goto fail; /* perfectly acceptable */
+ }
+
+
+ /* save start things so we can restart for seeking/looping */
+ memcpy(data->segments[i]->start_ch,data->segments[i]->ch,sizeof(VGMSTREAMCHANNEL)*data->segments[i]->channels);
+ memcpy(data->segments[i]->start_vgmstream,data->segments[i],sizeof(VGMSTREAM));
+ }
+
+
+ return 1;
+fail:
+ return 0; /* caller is expected to free */
+}
+
+void free_layout_segmented(segmented_layout_data *data) {
+ int i;
+
+ if (!data)
+ return;
+
+ if (data->segments) {
+ for (i = 0; i < data->segment_count; i++) {
+ close_vgmstream(data->segments[i]);
+ }
+ free(data->segments);
+ }
+ free(data);
+}
+
+void reset_layout_segmented(segmented_layout_data *data) {
+ int i;
+
+ if (!data)
+ return;
+
+ data->current_segment = 0;
+ for (i = 0; i < data->segment_count; i++) {
+ reset_vgmstream(data->segments[i]);
+ }
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/layout/wsi_blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/wsi_blocked.c
deleted file mode 100644
index 6dcd79a52..000000000
--- a/Frameworks/vgmstream/vgmstream/src/layout/wsi_blocked.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "layout.h"
-#include "../vgmstream.h"
-
-/* set up for the block at the given offset */
-void wsi_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
- int i;
-
- /* assume that all channels have the same size for this block */
-
- vgmstream->current_block_offset = block_offset;
- /* current_block_size is the data size in this block, so subtract header */
- vgmstream->current_block_size = read_32bitBE(
- vgmstream->current_block_offset,
- vgmstream->ch[0].streamfile) - 0x10;
- vgmstream->next_block_offset =
- vgmstream->current_block_offset +
- (vgmstream->current_block_size + 0x10) * vgmstream->channels;
-
- for (i=0;ichannels;i++) {
- vgmstream->ch[i].offset = vgmstream->current_block_offset +
- 0x10 + (vgmstream->current_block_size+0x10)*i;
- }
-}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/aax.c b/Frameworks/vgmstream/vgmstream/src/meta/aax.c
index b37c70f84..15df8edec 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/aax.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/aax.c
@@ -1,673 +1,193 @@
#include "meta.h"
-#include "aax_streamfile.h"
+#include "../layout/layout.h"
+#include "../coding/coding.h"
+#include "aax_utf.h"
-struct utf_query
-{
- /* if 0 */
- const char *name;
- int index;
-};
-
-struct offset_size_pair
-{
- uint32_t offset;
- uint32_t size;
-};
-
-struct utf_query_result
-{
- int valid; /* table is valid */
- int found;
- int type; /* one of COLUMN_TYPE_* */
- union
- {
- uint64_t value_u64;
- uint32_t value_u32;
- uint16_t value_u16;
- uint8_t value_u8;
- float value_float;
- struct offset_size_pair value_data;
- uint32_t value_string;
- } value;
-
- /* info for the queried table */
- uint32_t rows;
- uint32_t name_offset;
- uint32_t string_table_offset;
- uint32_t data_offset;
-};
-
-static struct utf_query_result analyze_utf(STREAMFILE *infile, long offset,
- const struct utf_query *query);
-
-static struct utf_query_result query_utf(STREAMFILE *infile, long offset,
- const struct utf_query *query);
-
-static struct utf_query_result query_utf_nofail(STREAMFILE *infile, const long offset,
- const struct utf_query *query, int *error);
-
-static struct utf_query_result query_utf_key(STREAMFILE *infile, const long offset,
- int index, const char *name, int *error);
-
-static uint8_t query_utf_1byte(STREAMFILE *infile, const long offset,
- int index, const char *name, int *error);
-
-static struct offset_size_pair query_utf_data(STREAMFILE *infile, const long offset,
- int index, const char *name, int *error);
-
-#define COLUMN_STORAGE_MASK 0xf0
-#define COLUMN_STORAGE_PERROW 0x50
-#define COLUMN_STORAGE_CONSTANT 0x30
-#define COLUMN_STORAGE_ZERO 0x10
-
-#define COLUMN_TYPE_MASK 0x0f
-#define COLUMN_TYPE_DATA 0x0b
-#define COLUMN_TYPE_STRING 0x0a
-#define COLUMN_TYPE_FLOAT 0x08
-#define COLUMN_TYPE_8BYTE 0x06
-#define COLUMN_TYPE_4BYTE 0x04
-#define COLUMN_TYPE_2BYTE2 0x03
-#define COLUMN_TYPE_2BYTE 0x02
-#define COLUMN_TYPE_1BYTE2 0x01
-#define COLUMN_TYPE_1BYTE 0x00
-
-struct utf_column_info
-{
- uint8_t type;
- const char *column_name;
- long constant_offset;
-};
-
-struct utf_table_info
-{
- long table_offset;
- uint32_t table_size;
- uint32_t schema_offset;
- uint32_t rows_offset;
- uint32_t string_table_offset;
- uint32_t data_offset;
- const char *string_table;
- const char *table_name;
- uint16_t columns;
- uint16_t row_width;
- uint32_t rows;
-
- const struct utf_column_info *schema;
-};
+static STREAMFILE* setup_aax_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext);
-/* AAX - segmented ADX [Padora's Tower (Wii)] */
+#define MAX_SEGMENTS 2 /* usually segment0=intro, segment1=loop/main */
+
+/* AAX - segmented ADX [Bayonetta (PS3), Pandora's Tower (Wii), Catherine (X360), Binary Domain (PS3)] */
VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- STREAMFILE * streamFileAAX = NULL;
- STREAMFILE * streamFileADX = NULL;
- char filename[PATH_LIMIT];
- off_t *segment_offset = NULL;
- off_t *segment_size = NULL;
- int32_t sample_count;
+ int is_hca;
+
+ int loop_flag = 0, channel_count = 0;
+ int32_t sample_count, loop_start_sample = 0, loop_end_sample = 0;
+ int segment_count, loop_segment = 0;
+
+ segmented_layout_data *data = NULL;
int table_error = 0;
-
- int loop_flag = 0;
- int32_t loop_start_sample=0;
- int32_t loop_end_sample=0;
- int loop_segment = 0;
-
- aax_codec_data *data = NULL;
-
- const long AAX_offset = 0;
-
- int channel_count = 0, segment_count;
- int sample_rate = 0;
-
+ const long top_offset = 0x00;
+ off_t segment_offset[MAX_SEGMENTS];
+ size_t segment_size[MAX_SEGMENTS];
int i;
- long aax_data_offset;
+ /* checks */
+ if (!check_extensions(streamFile, "aax"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x40555446) /* "@UTF" */
+ goto fail;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("aax",filename_extension(filename))) goto fail;
-
- /* get AAX entry count, data offset */
+
+ /* get segment count, offsets and sizes */
{
struct utf_query_result result;
long aax_string_table_offset;
long aax_string_table_size;
-
- result = query_utf_nofail(streamFile, AAX_offset, NULL, &table_error);
+ long aax_data_offset;
+
+ result = query_utf_nofail(streamFile, top_offset, NULL, &table_error);
if (table_error) goto fail;
+
segment_count = result.rows;
- aax_string_table_offset = AAX_offset + 8 + result.string_table_offset;
- aax_data_offset = AAX_offset + 8 + result.data_offset;
+ if (segment_count > MAX_SEGMENTS) goto fail;
+
+ aax_string_table_offset = top_offset+0x08 + result.string_table_offset;
+ aax_data_offset = top_offset+0x08 + result.data_offset;
aax_string_table_size = aax_data_offset - aax_string_table_offset;
- if (result.name_offset+4 > aax_string_table_size) goto fail;
- if (read_32bitBE(aax_string_table_offset + result.name_offset,
- streamFile) != 0x41415800) /* "AAX\0" */
+ if (result.name_offset+0x04 > aax_string_table_size)
goto fail;
- }
- segment_offset = calloc(segment_count,sizeof(off_t));
- if (!segment_offset)
- goto fail;
- segment_size = calloc(segment_count,sizeof(off_t));
- if (!segment_size)
- goto fail;
-
- /* get offsets of constituent ADXs */
- for (i = 0; i < segment_count; i++)
- {
- struct offset_size_pair offset_size;
- offset_size = query_utf_data(streamFile, AAX_offset, i, "data", &table_error);
- if (table_error) goto fail;
- segment_offset[i] = aax_data_offset + offset_size.offset;
- segment_size[i] = offset_size.size;
- }
-
- streamFileAAX = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!streamFileAAX) goto fail;
-
- data = malloc(sizeof(aax_codec_data));
- if (!data) goto fail;
- data->segment_count = segment_count;
- data->adxs = malloc(sizeof(STREAMFILE *)*segment_count);
- if (!data->adxs) goto fail;
- for (i=0;iadxs[i] = NULL;
- }
- data->sample_counts = calloc(segment_count,sizeof(int32_t));
- if (!data->sample_counts) goto fail;
-
- /* for each segment */
- for (i = 0; i < segment_count; i++)
- {
- VGMSTREAM *adx;
- /*printf("try opening segment %d/%d %x\n",i,segment_count,segment_offset[i]);*/
- streamFileADX = open_aax_with_STREAMFILE(streamFileAAX,segment_offset[i],segment_size[i]);
- if (!streamFileADX) goto fail;
- adx = data->adxs[i] = init_vgmstream_adx(streamFileADX);
- if (!adx)
- goto fail;
- data->sample_counts[i] = adx->num_samples;
- close_streamfile(streamFileADX); streamFileADX = NULL;
-
- if (i == 0)
- {
- channel_count = adx->channels;
- sample_rate = adx->sample_rate;
- }
+ if (read_32bitBE(aax_string_table_offset + result.name_offset, streamFile) == 0x41415800) /* "AAX\0" */
+ is_hca = 0;
+ else if (read_32bitBE(aax_string_table_offset + result.name_offset, streamFile) == 0x48434100) /* "HCA\0" */
+ is_hca = 1;
else
- {
- if (channel_count != adx->channels)
- goto fail;
- if (sample_rate != adx->sample_rate)
- goto fail;
- }
-
- if (adx->loop_flag != 0)
goto fail;
- /* save start things so we can restart for seeking/looping */
- /* copy the channels */
- memcpy(adx->start_ch,adx->ch,sizeof(VGMSTREAMCHANNEL)*adx->channels);
- /* copy the whole VGMSTREAM */
- memcpy(adx->start_vgmstream,adx,sizeof(VGMSTREAM));
+ /* get offsets of constituent segments */
+ for (i = 0; i < segment_count; i++) {
+ struct offset_size_pair offset_size;
+ offset_size = query_utf_data(streamFile, top_offset, i, "data", &table_error);
+ if (table_error) goto fail;
+
+ segment_offset[i] = aax_data_offset + offset_size.offset;
+ segment_size[i] = offset_size.size;
+ }
}
+ /* init layout */
+ data = init_layout_segmented(segment_count);
+ if (!data) goto fail;
+
+ /* open each segment subfile */
+ for (i = 0; i < segment_count; i++) {
+ STREAMFILE* temp_streamFile = setup_aax_streamfile(streamFile, segment_offset[i],segment_size[i], (is_hca ? "hca" : "adx"));
+ if (!temp_streamFile) goto fail;
+
+ data->segments[i] = is_hca ?
+ init_vgmstream_hca(temp_streamFile) :
+ init_vgmstream_adx(temp_streamFile);
+
+ close_streamfile(temp_streamFile);
+
+ if (!data->segments[i]) goto fail;
+ }
+
+ /* setup segmented VGMSTREAMs */
+ if (!setup_layout_segmented(data))
+ goto fail;
+
+ /* get looping and samples */
sample_count = 0;
loop_flag = 0;
- for (i = 0; i < segment_count; i++)
- {
- int segment_loop_flag = query_utf_1byte(streamFile, AAX_offset, i,
- "lpflg", &table_error);
+ for (i = 0; i < segment_count; i++) {
+ int segment_loop_flag = query_utf_1byte(streamFile, top_offset, i, "lpflg", &table_error);
if (table_error) segment_loop_flag = 0;
- if (!loop_flag && segment_loop_flag)
- {
+ if (!loop_flag && segment_loop_flag) {
loop_start_sample = sample_count;
loop_segment = i;
}
- sample_count += data->sample_counts[i];
+ sample_count += data->segments[i]->num_samples;
- if (!loop_flag && segment_loop_flag)
- {
+ if (!loop_flag && segment_loop_flag) {
loop_end_sample = sample_count;
loop_flag = 1;
}
}
+
+ channel_count = data->segments[0]->channels;
+
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+ vgmstream->sample_rate = data->segments[0]->sample_rate;
vgmstream->num_samples = sample_count;
- vgmstream->sample_rate = sample_rate;
-
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
- vgmstream->coding_type = data->adxs[0]->coding_type;
- vgmstream->layout_type = layout_aax;
vgmstream->meta_type = meta_AAX;
+ vgmstream->coding_type = data->segments[0]->coding_type;
+ vgmstream->layout_type = layout_segmented;
- vgmstream->ch[0].streamfile = streamFileAAX;
- data->current_segment = 0;
+ vgmstream->layout_data = data;
data->loop_segment = loop_segment;
- vgmstream->codec_data = data;
- free(segment_offset);
- free(segment_size);
-
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (streamFileAAX) close_streamfile(streamFileAAX);
- if (streamFileADX) close_streamfile(streamFileADX);
- if (vgmstream) close_vgmstream(vgmstream);
- if (segment_offset) free(segment_offset);
- if (segment_size) free(segment_size);
- if (data) {
- if (data->adxs)
- {
- int i;
- for (i=0;isegment_count;i++)
- if (data->adxs)
- close_vgmstream(data->adxs[i]);
- free(data->adxs);
- }
- if (data->sample_counts)
- {
- free(data->sample_counts);
- }
- free(data);
- }
+ close_vgmstream(vgmstream);
+ free_layout_segmented(data);
return NULL;
}
-/* @UTF table reading, abridged */
-static struct utf_query_result analyze_utf(STREAMFILE *infile, const long offset, const struct utf_query *query)
-{
- unsigned char buf[4];
- struct utf_table_info table_info;
- char *string_table = NULL;
- struct utf_column_info * schema = NULL;
- struct utf_query_result result;
- uint32_t table_name_string;
- int string_table_size;
-
- result.valid = 0;
+static STREAMFILE* setup_aax_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext) {
+ STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
- table_info.table_offset = offset;
+ /* setup subfile */
+ new_streamFile = open_wrap_streamfile(streamFile);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
- /* check header */
- {
- static const char UTF_signature[4] = "@UTF"; /* intentionally unterminated */
- if (4 != read_streamfile(buf, offset, 4, infile)) goto cleanup_error;
- if (memcmp(buf, UTF_signature, sizeof(UTF_signature)))
- {
- goto cleanup_error;
- }
- }
+ new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
- /* get table size */
- table_info.table_size = read_32bitBE(offset+4, infile);
+ new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,fake_ext);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
- table_info.schema_offset = 0x20;
- table_info.rows_offset = read_32bitBE(offset+8, infile);
- table_info.string_table_offset = read_32bitBE(offset+0xc,infile);
- table_info.data_offset = read_32bitBE(offset+0x10,infile);
- table_name_string = read_32bitBE(offset+0x14,infile);
- table_info.columns = read_16bitBE(offset+0x18,infile);
- table_info.row_width = read_16bitBE(offset+0x1a,infile);
- table_info.rows = read_32bitBE(offset+0x1c,infile);
+ return temp_streamFile;
- /* allocate for string table */
- string_table_size = table_info.data_offset-table_info.string_table_offset;
- string_table = malloc(string_table_size+1);
- if (!string_table) goto cleanup_error;
- table_info.string_table = string_table;
- memset(string_table, 0, string_table_size+1);
-
- /* load schema */
- schema = malloc(sizeof(struct utf_column_info) * table_info.columns);
- if (!schema) goto cleanup_error;
-
- {
- int i;
- long schema_current_offset = table_info.schema_offset;
- for (i = 0; i < table_info.columns; i++)
- {
- schema[i].type = read_8bit(schema_current_offset,infile);
- schema_current_offset ++;
- schema[i].column_name = string_table + read_32bitBE(schema_current_offset,infile);
- schema_current_offset += 4;
-
- if ((schema[i].type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_CONSTANT)
- {
- schema[i].constant_offset = schema_current_offset;
- switch (schema[i].type & COLUMN_TYPE_MASK)
- {
- case COLUMN_TYPE_8BYTE:
- case COLUMN_TYPE_DATA:
- schema_current_offset+=8;
- break;
- case COLUMN_TYPE_STRING:
- case COLUMN_TYPE_FLOAT:
- case COLUMN_TYPE_4BYTE:
- schema_current_offset+=4;
- break;
- case COLUMN_TYPE_2BYTE2:
- case COLUMN_TYPE_2BYTE:
- schema_current_offset+=2;
- break;
- case COLUMN_TYPE_1BYTE2:
- case COLUMN_TYPE_1BYTE:
- schema_current_offset++;
- break;
- default:
- goto cleanup_error;
- }
- }
- }
- }
-
- table_info.schema = schema;
-
- /* read string table */
- read_streamfile((unsigned char *)string_table,
- table_info.string_table_offset+8+offset,
- string_table_size, infile);
- table_info.table_name = table_info.string_table+table_name_string;
-
- /* fill in the default stuff */
- result.found = 0;
- result.rows = table_info.rows;
- result.name_offset = table_name_string;
- result.string_table_offset = table_info.string_table_offset;
- result.data_offset = table_info.data_offset;
-
- /* explore the values */
- if (query) {
- int i, j;
-
- for (i = 0; i < table_info.rows; i++)
- {
- uint32_t row_offset =
- table_info.table_offset + 8 + table_info.rows_offset +
- i * table_info.row_width;
- const uint32_t row_start_offset = row_offset;
-
- if (query && i != query->index) continue;
-
- for (j = 0; j < table_info.columns; j++)
- {
- uint8_t type = table_info.schema[j].type;
- long constant_offset = table_info.schema[j].constant_offset;
- int constant = 0;
-
- int qthis = (query && i == query->index &&
- !strcmp(table_info.schema[j].column_name, query->name));
-
- if (qthis)
- {
- result.found = 1;
- result.type = schema[j].type & COLUMN_TYPE_MASK;
- }
-
- switch (schema[j].type & COLUMN_STORAGE_MASK)
- {
- case COLUMN_STORAGE_PERROW:
- break;
- case COLUMN_STORAGE_CONSTANT:
- constant = 1;
- break;
- case COLUMN_STORAGE_ZERO:
- if (qthis)
- {
- memset(&result.value, 0,
- sizeof(result.value));
- }
- continue;
- default:
- goto cleanup_error;
- }
-
- if (1)
- {
- long data_offset;
- int bytes_read;
-
- if (constant)
- {
- data_offset = constant_offset;
- }
- else
- {
- data_offset = row_offset;
- }
-
- switch (type & COLUMN_TYPE_MASK)
- {
- case COLUMN_TYPE_STRING:
- {
- uint32_t string_offset;
- string_offset = read_32bitBE(data_offset, infile);
- bytes_read = 4;
- if (qthis)
- {
- result.value.value_string = string_offset;
- }
- }
- break;
- case COLUMN_TYPE_DATA:
- {
- uint32_t vardata_offset, vardata_size;
-
- vardata_offset = read_32bitBE(data_offset, infile);
- vardata_size = read_32bitBE(data_offset+4, infile);
- bytes_read = 8;
- if (qthis)
- {
- result.value.value_data.offset = vardata_offset;
- result.value.value_data.size = vardata_size;
- }
- }
- break;
-
- case COLUMN_TYPE_8BYTE:
- {
- uint64_t value =
- read_32bitBE(data_offset, infile);
- value <<= 32;
- value |=
- read_32bitBE(data_offset+4, infile);
- if (qthis)
- {
- result.value.value_u64 = value;
- }
- bytes_read = 8;
- break;
- }
- case COLUMN_TYPE_4BYTE:
- {
- uint32_t value =
- read_32bitBE(data_offset, infile);
- if (qthis)
- {
- result.value.value_u32 = value;
- }
- bytes_read = 4;
- }
- break;
- case COLUMN_TYPE_2BYTE2:
- case COLUMN_TYPE_2BYTE:
- {
- uint16_t value =
- read_16bitBE(data_offset, infile);
- if (qthis)
- {
- result.value.value_u16 = value;
- }
- bytes_read = 2;
- }
- break;
- case COLUMN_TYPE_FLOAT:
- if (sizeof(float) == 4)
- {
- union {
- float float_value;
- uint32_t int_value;
- } int_float;
-
- int_float.int_value = read_32bitBE(data_offset, infile);
- if (qthis)
- {
- result.value.value_float = int_float.float_value;
- }
- }
- else
- {
- read_32bitBE(data_offset, infile);
- if (qthis)
- {
- goto cleanup_error;
- }
- }
- bytes_read = 4;
- break;
- case COLUMN_TYPE_1BYTE2:
- case COLUMN_TYPE_1BYTE:
- {
- uint8_t value =
- read_8bit(data_offset, infile);
- if (qthis)
- {
- result.value.value_u8 = value;
- }
- bytes_read = 1;
- }
- break;
- default:
- goto cleanup_error;
- }
-
- if (!constant)
- {
- row_offset += bytes_read;
- }
- } /* useless if end */
- } /* column for loop end */
-
- if (row_offset - row_start_offset != table_info.row_width)
- goto cleanup_error;
-
- if (query && i >= query->index) break;
- } /* row for loop end */
- } /* explore values block end */
-
-//cleanup:
-
- result.valid = 1;
-cleanup_error:
-
- if (string_table)
- {
- free(string_table);
- string_table = NULL;
- }
-
- if (schema)
- {
- free(schema);
- schema = NULL;
- }
-
- return result;
+fail:
+ close_streamfile(temp_streamFile);
+ return NULL;
}
-static struct utf_query_result query_utf(STREAMFILE *infile, const long offset, const struct utf_query *query)
-{
- return analyze_utf(infile, offset, query);
-}
-static struct utf_query_result query_utf_nofail(STREAMFILE *infile, const long offset, const struct utf_query *query, int *error)
-{
- const struct utf_query_result result = query_utf(infile, offset, query);
-
- if (error)
- {
- *error = 0;
- if (!result.valid) *error = 1;
- if (query && !result.found) *error = 1;
- }
-
- return result;
-}
-
-static struct utf_query_result query_utf_key(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
-{
- struct utf_query query;
- query.index = index;
- query.name = name;
-
- return query_utf_nofail(infile, offset, &query, error);
-}
-
-static uint8_t query_utf_1byte(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
-{
- struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
- if (error)
- {
- if (result.type != COLUMN_TYPE_1BYTE) *error = 1;
- }
- return result.value.value_u8;
-}
-
-static uint32_t query_utf_4byte(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
-{
- struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
- if (error)
- {
- if (result.type != COLUMN_TYPE_4BYTE) *error = 1;
- }
- return result.value.value_u32;
-}
-
-static struct offset_size_pair query_utf_data(STREAMFILE *infile, const long offset,
- int index, const char *name, int *error)
-{
- struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
- if (error)
- {
- if (result.type != COLUMN_TYPE_DATA) *error = 1;
- }
- return result.value.value_data;
-}
-
-/* CRI's UTF wrapper around DSP */
+/* CRI's UTF wrapper around DSP [Sonic Colors sfx (Wii), NiGHTS: Journey of Dreams sfx (Wii)] */
VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- int table_error = 0;
+ off_t start_offset;
+ size_t channel_size;
- int loop_flag = 0;
-
- const long top_offset = 0;
-
- int channel_count;
- int sample_rate;
+ int loop_flag = 0, channel_count, sample_rate;
long sample_count;
+ int table_error = 0;
+ const long top_offset = 0x00;
long top_data_offset, segment_count;
long body_offset, body_size;
long header_offset, header_size;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- //if (strcasecmp("aax",filename_extension(filename))) goto fail;
- /* get entry count, data offset */
+ /* checks */
+ /* files don't have extension, we accept "" for CLI and .aax for plugins (they aren't exactly .aax though) */
+ if (!check_extensions(streamFile, "aax,"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x40555446) /* "@UTF" */
+ goto fail;
+
+ /* get segment count, offsets and sizes*/
{
struct utf_query_result result;
long top_string_table_offset;
@@ -676,8 +196,10 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
result = query_utf_nofail(streamFile, top_offset, NULL, &table_error);
if (table_error) goto fail;
+
segment_count = result.rows;
- if (segment_count != 1) goto fail; // only simple stuff for now
+ if (segment_count != 1) goto fail; /* only simple stuff for now (multisegment not known) */
+
top_string_table_offset = top_offset + 8 + result.string_table_offset;
top_data_offset = top_offset + 8 + result.data_offset;
top_string_table_size = top_data_offset - top_string_table_offset;
@@ -685,12 +207,13 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
if (result.name_offset+10 > top_string_table_size) goto fail;
name_offset = top_string_table_offset + result.name_offset;
- if (read_32bitBE(name_offset, streamFile) != 0x41445043 ||// "ADPC"
- read_32bitBE(name_offset+4, streamFile) != 0x4D5F5749 ||// "M_WI"
- read_16bitBE(name_offset+8, streamFile) != 0x4900) // "I\0"
+ if (read_32bitBE(name_offset+0x00, streamFile) != 0x41445043 || /* "ADPC" */
+ read_32bitBE(name_offset+0x04, streamFile) != 0x4D5F5749 || /* "M_WI" */
+ read_16bitBE(name_offset+0x08, streamFile) != 0x4900) /* "I\0" */
goto fail;
}
+ /* get sizes */
{
struct offset_size_pair offset_size;
@@ -712,36 +235,29 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
if (channel_count != 1 && channel_count != 2) goto fail;
if (header_size != channel_count * 0x60) goto fail;
+ start_offset = body_offset;
+ channel_size = (body_size+7) / 8 * 8 / channel_count;
+
+
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
- vgmstream->num_samples = sample_count;
vgmstream->sample_rate = sample_rate;
+ vgmstream->num_samples = sample_count;
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_UTF_DSP;
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = channel_size;
- {
- int i,j;
- long channel_size = (body_size+7)/8*8/channel_count;
- for (i = 0; i < channel_count; i++)
- {
- vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[i].streamfile) goto fail;
- vgmstream->ch[i].channel_start_offset =
- vgmstream->ch[i].offset = body_offset + i * channel_size;
- for (j=0;j<16;j++)
- {
- vgmstream->ch[i].adpcm_coef[j] =
- read_16bitBE(header_offset + 0x60*i + 0x1c + j*2, streamFile);
- }
- }
- }
+ dsp_read_coefs_be(vgmstream, streamFile, header_offset+0x1c, 0x60);
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/aax_streamfile.h b/Frameworks/vgmstream/vgmstream/src/meta/aax_streamfile.h
deleted file mode 100644
index 1490e7c4a..000000000
--- a/Frameworks/vgmstream/vgmstream/src/meta/aax_streamfile.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef _AAX_STREAMFILE_H_
-#define _AAX_STREAMFILE_H_
-#include "../streamfile.h"
-
-/* a streamfile representing a subfile inside another */
-
-typedef struct _AAXSTREAMFILE {
- STREAMFILE sf;
- STREAMFILE *real_file;
- off_t start_physical_offset;
- size_t file_size;
-} AAXSTREAMFILE;
-
-static size_t read_aax(AAXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length) {
- /* truncate at end of logical file */
- if (offset+length > streamfile->file_size) {
- long signed_length = length;
- signed_length = streamfile->file_size - offset;
- if (signed_length < 0) signed_length = 0;
- length = signed_length;
- }
- return read_streamfile(dest, streamfile->start_physical_offset+offset, length,streamfile->real_file);
-}
-
-static void close_aax(AAXSTREAMFILE *streamfile) {
- free(streamfile);
- return;
-}
-
-static size_t get_size_aax(AAXSTREAMFILE *streamfile) {
- return 0;
-}
-
-static size_t get_offset_aax(AAXSTREAMFILE *streamfile) {
- long offset = streamfile->real_file->get_offset(streamfile->real_file);
- offset -= streamfile->start_physical_offset;
- if (offset < 0) offset = 0;
- if (offset > streamfile->file_size) offset = streamfile->file_size;
-
- return offset;
-}
-
-static void get_name_aax(AAXSTREAMFILE *streamfile,char *buffer,size_t length) {
- strncpy(buffer,"ARBITRARY.ADX",length);
- buffer[length-1]='\0';
-}
-
-static STREAMFILE *open_aax_impl(AAXSTREAMFILE *streamfile,const char * const filename,size_t buffersize) {
- AAXSTREAMFILE *newfile;
- if (strcmp(filename,"ARBITRARY.ADX"))
- return NULL;
-
- newfile = malloc(sizeof(AAXSTREAMFILE));
- if (!newfile)
- return NULL;
- memcpy(newfile,streamfile,sizeof(AAXSTREAMFILE));
- return &newfile->sf;
-}
-
-static STREAMFILE *open_aax_with_STREAMFILE(STREAMFILE *file,off_t start_offset,size_t file_size) {
- AAXSTREAMFILE *streamfile = malloc(sizeof(AAXSTREAMFILE));
-
- if (!streamfile)
- return NULL;
-
- /* success, set our pointers */
-
- streamfile->sf.read = (void*)read_aax;
- streamfile->sf.get_size = (void*)get_size_aax;
- streamfile->sf.get_offset = (void*)get_offset_aax;
- streamfile->sf.get_name = (void*)get_name_aax;
- streamfile->sf.get_realname = (void*)get_name_aax;
- streamfile->sf.open = (void*)open_aax_impl;
- streamfile->sf.close = (void*)close_aax;
-
- streamfile->real_file = file;
- streamfile->start_physical_offset = start_offset;
- streamfile->file_size = file_size;
-
- return &streamfile->sf;
-}
-
-#endif /* _AAX_STREAMFILE_H_ */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/aax_utf.h b/Frameworks/vgmstream/vgmstream/src/meta/aax_utf.h
new file mode 100644
index 000000000..24dc88dc3
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/aax_utf.h
@@ -0,0 +1,442 @@
+#ifndef _AAX_UTF_H_
+#define _AAX_UTF_H_
+
+struct utf_query
+{
+ /* if 0 */
+ const char *name;
+ int index;
+};
+
+struct offset_size_pair
+{
+ uint32_t offset;
+ uint32_t size;
+};
+
+struct utf_query_result
+{
+ int valid; /* table is valid */
+ int found;
+ int type; /* one of COLUMN_TYPE_* */
+ union
+ {
+ uint64_t value_u64;
+ uint32_t value_u32;
+ uint16_t value_u16;
+ uint8_t value_u8;
+ float value_float;
+ struct offset_size_pair value_data;
+ uint32_t value_string;
+ } value;
+
+ /* info for the queried table */
+ uint32_t rows;
+ uint32_t name_offset;
+ uint32_t string_table_offset;
+ uint32_t data_offset;
+};
+
+
+#define COLUMN_STORAGE_MASK 0xf0
+#define COLUMN_STORAGE_PERROW 0x50
+#define COLUMN_STORAGE_CONSTANT 0x30
+#define COLUMN_STORAGE_ZERO 0x10
+
+#define COLUMN_TYPE_MASK 0x0f
+#define COLUMN_TYPE_DATA 0x0b
+#define COLUMN_TYPE_STRING 0x0a
+#define COLUMN_TYPE_FLOAT 0x08
+#define COLUMN_TYPE_8BYTE 0x06
+#define COLUMN_TYPE_4BYTE 0x04
+#define COLUMN_TYPE_2BYTE2 0x03
+#define COLUMN_TYPE_2BYTE 0x02
+#define COLUMN_TYPE_1BYTE2 0x01
+#define COLUMN_TYPE_1BYTE 0x00
+
+struct utf_column_info
+{
+ uint8_t type;
+ const char *column_name;
+ long constant_offset;
+};
+
+struct utf_table_info
+{
+ long table_offset;
+ uint32_t table_size;
+ uint32_t schema_offset;
+ uint32_t rows_offset;
+ uint32_t string_table_offset;
+ uint32_t data_offset;
+ const char *string_table;
+ const char *table_name;
+ uint16_t columns;
+ uint16_t row_width;
+ uint32_t rows;
+
+ const struct utf_column_info *schema;
+};
+
+/* @UTF table reading, abridged */
+static struct utf_query_result analyze_utf(STREAMFILE *infile, const long offset, const struct utf_query *query)
+{
+ unsigned char buf[4];
+ struct utf_table_info table_info;
+ char *string_table = NULL;
+ struct utf_column_info * schema = NULL;
+ struct utf_query_result result;
+ uint32_t table_name_string;
+ int string_table_size;
+
+ result.valid = 0;
+
+ table_info.table_offset = offset;
+
+ /* check header */
+ {
+ static const char UTF_signature[4] = "@UTF"; /* intentionally unterminated */
+ if (4 != read_streamfile(buf, offset, 4, infile)) goto cleanup_error;
+ if (memcmp(buf, UTF_signature, sizeof(UTF_signature)))
+ {
+ goto cleanup_error;
+ }
+ }
+
+ /* get table size */
+ table_info.table_size = read_32bitBE(offset+4, infile);
+
+ table_info.schema_offset = 0x20;
+ table_info.rows_offset = read_32bitBE(offset+8, infile);
+ table_info.string_table_offset = read_32bitBE(offset+0xc,infile);
+ table_info.data_offset = read_32bitBE(offset+0x10,infile);
+ table_name_string = read_32bitBE(offset+0x14,infile);
+ table_info.columns = read_16bitBE(offset+0x18,infile);
+ table_info.row_width = read_16bitBE(offset+0x1a,infile);
+ table_info.rows = read_32bitBE(offset+0x1c,infile);
+
+ /* allocate for string table */
+ string_table_size = table_info.data_offset-table_info.string_table_offset;
+ string_table = malloc(string_table_size+1);
+ if (!string_table) goto cleanup_error;
+ table_info.string_table = string_table;
+ memset(string_table, 0, string_table_size+1);
+
+ /* load schema */
+ schema = malloc(sizeof(struct utf_column_info) * table_info.columns);
+ if (!schema) goto cleanup_error;
+
+ {
+ int i;
+ long schema_current_offset = table_info.schema_offset;
+ for (i = 0; i < table_info.columns; i++)
+ {
+ schema[i].type = read_8bit(schema_current_offset,infile);
+ schema_current_offset ++;
+ schema[i].column_name = string_table + read_32bitBE(schema_current_offset,infile);
+ schema_current_offset += 4;
+
+ if ((schema[i].type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_CONSTANT)
+ {
+ schema[i].constant_offset = schema_current_offset;
+ switch (schema[i].type & COLUMN_TYPE_MASK)
+ {
+ case COLUMN_TYPE_8BYTE:
+ case COLUMN_TYPE_DATA:
+ schema_current_offset+=8;
+ break;
+ case COLUMN_TYPE_STRING:
+ case COLUMN_TYPE_FLOAT:
+ case COLUMN_TYPE_4BYTE:
+ schema_current_offset+=4;
+ break;
+ case COLUMN_TYPE_2BYTE2:
+ case COLUMN_TYPE_2BYTE:
+ schema_current_offset+=2;
+ break;
+ case COLUMN_TYPE_1BYTE2:
+ case COLUMN_TYPE_1BYTE:
+ schema_current_offset++;
+ break;
+ default:
+ goto cleanup_error;
+ }
+ }
+ }
+ }
+
+ table_info.schema = schema;
+
+ /* read string table */
+ read_streamfile((unsigned char *)string_table,
+ table_info.string_table_offset+8+offset,
+ string_table_size, infile);
+ table_info.table_name = table_info.string_table+table_name_string;
+
+ /* fill in the default stuff */
+ result.found = 0;
+ result.rows = table_info.rows;
+ result.name_offset = table_name_string;
+ result.string_table_offset = table_info.string_table_offset;
+ result.data_offset = table_info.data_offset;
+
+ /* explore the values */
+ if (query) {
+ int i, j;
+
+ for (i = 0; i < table_info.rows; i++)
+ {
+ uint32_t row_offset =
+ table_info.table_offset + 8 + table_info.rows_offset +
+ i * table_info.row_width;
+ const uint32_t row_start_offset = row_offset;
+
+ if (query && i != query->index) continue;
+
+ for (j = 0; j < table_info.columns; j++)
+ {
+ uint8_t type = table_info.schema[j].type;
+ long constant_offset = table_info.schema[j].constant_offset;
+ int constant = 0;
+
+ int qthis = (query && i == query->index &&
+ !strcmp(table_info.schema[j].column_name, query->name));
+
+ if (qthis)
+ {
+ result.found = 1;
+ result.type = schema[j].type & COLUMN_TYPE_MASK;
+ }
+
+ switch (schema[j].type & COLUMN_STORAGE_MASK)
+ {
+ case COLUMN_STORAGE_PERROW:
+ break;
+ case COLUMN_STORAGE_CONSTANT:
+ constant = 1;
+ break;
+ case COLUMN_STORAGE_ZERO:
+ if (qthis)
+ {
+ memset(&result.value, 0,
+ sizeof(result.value));
+ }
+ continue;
+ default:
+ goto cleanup_error;
+ }
+
+ if (1)
+ {
+ long data_offset;
+ int bytes_read;
+
+ if (constant)
+ {
+ data_offset = constant_offset;
+ }
+ else
+ {
+ data_offset = row_offset;
+ }
+
+ switch (type & COLUMN_TYPE_MASK)
+ {
+ case COLUMN_TYPE_STRING:
+ {
+ uint32_t string_offset;
+ string_offset = read_32bitBE(data_offset, infile);
+ bytes_read = 4;
+ if (qthis)
+ {
+ result.value.value_string = string_offset;
+ }
+ }
+ break;
+ case COLUMN_TYPE_DATA:
+ {
+ uint32_t vardata_offset, vardata_size;
+
+ vardata_offset = read_32bitBE(data_offset, infile);
+ vardata_size = read_32bitBE(data_offset+4, infile);
+ bytes_read = 8;
+ if (qthis)
+ {
+ result.value.value_data.offset = vardata_offset;
+ result.value.value_data.size = vardata_size;
+ }
+ }
+ break;
+
+ case COLUMN_TYPE_8BYTE:
+ {
+ uint64_t value =
+ read_32bitBE(data_offset, infile);
+ value <<= 32;
+ value |=
+ read_32bitBE(data_offset+4, infile);
+ if (qthis)
+ {
+ result.value.value_u64 = value;
+ }
+ bytes_read = 8;
+ break;
+ }
+ case COLUMN_TYPE_4BYTE:
+ {
+ uint32_t value =
+ read_32bitBE(data_offset, infile);
+ if (qthis)
+ {
+ result.value.value_u32 = value;
+ }
+ bytes_read = 4;
+ }
+ break;
+ case COLUMN_TYPE_2BYTE2:
+ case COLUMN_TYPE_2BYTE:
+ {
+ uint16_t value =
+ read_16bitBE(data_offset, infile);
+ if (qthis)
+ {
+ result.value.value_u16 = value;
+ }
+ bytes_read = 2;
+ }
+ break;
+ case COLUMN_TYPE_FLOAT:
+ if (sizeof(float) == 4)
+ {
+ union {
+ float float_value;
+ uint32_t int_value;
+ } int_float;
+
+ int_float.int_value = read_32bitBE(data_offset, infile);
+ if (qthis)
+ {
+ result.value.value_float = int_float.float_value;
+ }
+ }
+ else
+ {
+ read_32bitBE(data_offset, infile);
+ if (qthis)
+ {
+ goto cleanup_error;
+ }
+ }
+ bytes_read = 4;
+ break;
+ case COLUMN_TYPE_1BYTE2:
+ case COLUMN_TYPE_1BYTE:
+ {
+ uint8_t value =
+ read_8bit(data_offset, infile);
+ if (qthis)
+ {
+ result.value.value_u8 = value;
+ }
+ bytes_read = 1;
+ }
+ break;
+ default:
+ goto cleanup_error;
+ }
+
+ if (!constant)
+ {
+ row_offset += bytes_read;
+ }
+ } /* useless if end */
+ } /* column for loop end */
+
+ if (row_offset - row_start_offset != table_info.row_width)
+ goto cleanup_error;
+
+ if (query && i >= query->index) break;
+ } /* row for loop end */
+ } /* explore values block end */
+
+//cleanup:
+
+ result.valid = 1;
+cleanup_error:
+
+ if (string_table)
+ {
+ free(string_table);
+ string_table = NULL;
+ }
+
+ if (schema)
+ {
+ free(schema);
+ schema = NULL;
+ }
+
+ return result;
+}
+
+static struct utf_query_result query_utf(STREAMFILE *infile, const long offset, const struct utf_query *query)
+{
+ return analyze_utf(infile, offset, query);
+}
+
+/*static*/ struct utf_query_result query_utf_nofail(STREAMFILE *infile, const long offset, const struct utf_query *query, int *error)
+{
+ const struct utf_query_result result = query_utf(infile, offset, query);
+
+ if (error)
+ {
+ *error = 0;
+ if (!result.valid) *error = 1;
+ if (query && !result.found) *error = 1;
+ }
+
+ return result;
+}
+
+static struct utf_query_result query_utf_key(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
+{
+ struct utf_query query;
+ query.index = index;
+ query.name = name;
+
+ return query_utf_nofail(infile, offset, &query, error);
+}
+
+/*static*/ uint8_t query_utf_1byte(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
+{
+ struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
+ if (error)
+ {
+ if (result.type != COLUMN_TYPE_1BYTE) *error = 1;
+ }
+ return result.value.value_u8;
+}
+
+/*static*/ uint32_t query_utf_4byte(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
+{
+ struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
+ if (error)
+ {
+ if (result.type != COLUMN_TYPE_4BYTE) *error = 1;
+ }
+ return result.value.value_u32;
+}
+
+/*static*/ struct offset_size_pair query_utf_data(STREAMFILE *infile, const long offset,
+ int index, const char *name, int *error)
+{
+ struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
+ if (error)
+ {
+ if (result.type != COLUMN_TYPE_DATA) *error = 1;
+ }
+ return result.value.value_data;
+}
+
+
+#endif /* SRC_META_AAX_UTF_H_ */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/acm.c b/Frameworks/vgmstream/vgmstream/src/meta/acm.c
index e91a9cb7f..4f1cf6fa7 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/acm.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/acm.c
@@ -1,66 +1,49 @@
-#include "../vgmstream.h"
#include "meta.h"
-#include "../util.h"
+#include "../coding/coding.h"
#include "../coding/acm_decoder.h"
-/* InterPlay ACM */
-/* The real work is done by libacm */
+/* ACM - InterPlay infinity engine games [Planescape: Torment (PC), Baldur's Gate (PC)] */
VGMSTREAM * init_vgmstream_acm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- ACMStream *acm_stream = NULL;
- mus_acm_codec_data *data;
+ int loop_flag = 0, channel_count, sample_rate, num_samples;
+ acm_codec_data *data = NULL;
- char filename[PATH_LIMIT];
- int loop_flag = 0;
- int channel_count;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("acm",filename_extension(filename))) goto fail;
-
- /* check header */
- if (read_32bitBE(0x0,streamFile) != 0x97280301)
- goto fail;
-
- data = calloc(1,sizeof(mus_acm_codec_data));
- if (!data) goto fail;
-
- data->files = calloc(1,sizeof(ACMStream *));
- if (!data->files) {
- free(data); data = NULL;
+ /* checks */
+ if (!check_extensions(streamFile, "acm"))
goto fail;
+ if (read_32bitBE(0x0,streamFile) != 0x97280301) /* header id */
+ goto fail;
+
+
+ /* init decoder */
+ {
+ data = init_acm(streamFile);
+ if (!data) goto fail;
+
+ channel_count = data->file->info.channels;
+ sample_rate = data->file->info.rate;
+ num_samples = data->file->total_values / data->file->info.channels;
}
- /* gonna do this a little backwards, open and parse the file
- before creating the vgmstream */
- if (acm_open_decoder(&acm_stream,streamFile,filename) != ACM_OK) {
- goto fail;
- }
-
- channel_count = acm_stream->info.channels;
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- vgmstream->channels = channel_count;
- vgmstream->sample_rate = acm_stream->info.rate;
- vgmstream->coding_type = coding_ACM;
- vgmstream->num_samples = acm_stream->total_values / acm_stream->info.channels;
- vgmstream->layout_type = layout_acm;
- vgmstream->meta_type = meta_ACM;
+ vgmstream->sample_rate = sample_rate;
+ vgmstream->num_samples = num_samples;
- data->file_count = 1;
- data->current_file = 0;
- data->files[0] = acm_stream;
- /*data->end_file = -1;*/
+ vgmstream->meta_type = meta_ACM;
+ vgmstream->coding_type = coding_ACM;
+ vgmstream->layout_type = layout_none;
vgmstream->codec_data = data;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ free_acm(data);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/adx.c b/Frameworks/vgmstream/vgmstream/src/meta/adx.c
index 5e6a875c2..0dc09918c 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/adx.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/adx.c
@@ -28,8 +28,10 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
uint16_t xor_start=0,xor_mult=0,xor_add=0;
- /* check extension, case insensitive */
- if (!check_extensions(streamFile,"adx")) goto fail;
+ /* checks*/
+ /* .adx: standard, .adp: Headhunter (DC) */
+ if (!check_extensions(streamFile,"adx,adp"))
+ goto fail;
/* check first 2 bytes */
if ((uint16_t)read_16bitBE(0x00,streamFile)!=0x8000) goto fail;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/adx_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/adx_keys.h
index 9d5b750e8..d35564864 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/adx_keys.h
+++ b/Frameworks/vgmstream/vgmstream/src/meta/adx_keys.h
@@ -26,7 +26,7 @@ static const adxkey_info adxkey8_list[] = {
{0x49e1,0x4a57,0x553d, "karaage",0},
/* Grasshopper Manufacture 0 (Blood+) */
- {0x5f5d,0x58bd,0x55ed, NULL,0}, // estimated
+ {0x5f5d,0x58bd,0x55ed, NULL,0}, // estimated (keystring not in ELF?)
/* Grasshopper Manufacture 1 (Killer7) */
{0x50fb,0x5803,0x5701, "GHM",0},
@@ -132,7 +132,7 @@ static const adxkey_info adxkey8_list[] = {
{0x6731,0x645d,0x566b, NULL,0}, // confirmed unique with guessadx
/* Shakugan no Shana (2006)(Vridge)(Media Works)[PS2] */
- {0x5fc5,0x63d9,0x599f, NULL,0}, // confirmed unique with guessadx
+ {0x5fc5,0x63d9,0x599f, "FUZETSU",0},
/* Uragiri wa Boku no Namae o Shitteiru (2010)(Kadokawa Shoten)[PS2] */
{0x4c73,0x4d8d,0x5827, NULL,0}, // confirmed unique with guessadx
@@ -207,6 +207,9 @@ static const adxkey_info adxkey9_list[] = {
// Super Robot Wars X-Omega (voices) [iOS/Android]
{0x5152,0x7979,0x152b, NULL,165521992944278}, // 0000968A97978A96
+ // AKA to BLUE (Android)
+ {0x03fc,0x0749,0x12EF, NULL,0}, // guessed with VGAudio (possible key: 1FE0748978 / 136909719928)
+ //{0x0c03,0x0749,0x1459, NULL,0}, // 2nd guess (possible key: 6018748A2D / 412727151149)
};
static const int adxkey8_list_count = sizeof(adxkey8_list) / sizeof(adxkey8_list[0]);
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/aix_streamfile.h b/Frameworks/vgmstream/vgmstream/src/meta/aix_streamfile.h
index 7fd36fd83..ae2be5984 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/aix_streamfile.h
+++ b/Frameworks/vgmstream/vgmstream/src/meta/aix_streamfile.h
@@ -148,7 +148,6 @@ static STREAMFILE *open_aix_impl(AIXSTREAMFILE *streamfile,const char * const fi
streamfile->sf.get_size = (void*)get_size_aix;
streamfile->sf.get_offset = (void*)get_offset_aix;
streamfile->sf.get_name = (void*)get_name_aix;
- streamfile->sf.get_realname = (void*)get_name_aix;
streamfile->sf.open = (void*)open_aix_impl;
streamfile->sf.close = (void*)close_aix;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/akb.c b/Frameworks/vgmstream/vgmstream/src/meta/akb.c
index 8a22de08a..0f65d66a8 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/akb.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/akb.c
@@ -3,7 +3,7 @@
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
/* AKB (AAC only) - found in SQEX iOS games */
-VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
+VGMSTREAM * init_vgmstream_akb_mp4(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
size_t filesize;
@@ -34,74 +34,99 @@ fail:
/* AKB - found in SQEX iOS games */
-VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile) {
+VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- off_t start_offset, extra_data_offset = 0;
- size_t file_size, header_size, extra_header_size = 0, extra_data_size = 0;
- int loop_flag = 0, channel_count, codec;
+ off_t start_offset, extradata_offset = 0;
+ size_t stream_size, header_size, subheader_size = 0, extradata_size = 0;
+ int loop_flag = 0, channel_count, codec, sample_rate;
+ int num_samples, loop_start, loop_end;
- /* check extensions */
+
+ /* checks */
/* .akb.bytes is the usual extension in later games */
- if ( !check_extensions(streamFile, "akb") )
+ if ( !check_extensions(streamFile, "akb,bytes") )
goto fail;
-
- /* check header */
if (read_32bitBE(0x00,streamFile) != 0x414B4220) /* "AKB " */
goto fail;
+ if (read_32bitLE(0x08,streamFile) != get_streamfile_size(streamFile))
+ goto fail;
- channel_count = read_8bit(0x0d,streamFile);
- loop_flag = read_32bitLE(0x18,streamFile) > 0; /* loop end */
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(channel_count,loop_flag);
- if (!vgmstream) goto fail;
-
- /* 0x04 (2): version (iPad/IPhone?) */
+ /* 0x04(2): version? (iPad/IPhone?) */
header_size = read_16bitLE(0x06,streamFile);
- file_size = read_32bitLE(0x08,streamFile);
- codec = read_8bit(0x0c,streamFile);
- vgmstream->sample_rate = (uint16_t)read_16bitLE(0x0e,streamFile);
- vgmstream->num_samples = read_32bitLE(0x10,streamFile);
- vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile);
- vgmstream->loop_end_sample = read_32bitLE(0x18,streamFile);
- vgmstream->meta_type = meta_AKB;
- /* should be ok but not exact (probably more complex, see AKB2) */
- if ( header_size >= 0x44) { /* v2 */
- /* 0x10+: config? (pan, volume), 0x24: file_id? */
- extra_data_size = read_16bitLE(0x1c,streamFile);
- extra_header_size = read_16bitLE(0x28,streamFile);
- extra_data_offset = header_size + extra_header_size;
- start_offset = extra_data_offset + extra_data_size;
- /* ~num_samples at extra_data_offset + 0x04/0x0c? */
+ codec = read_8bit(0x0c,streamFile);
+ channel_count = read_8bit(0x0d,streamFile);
+ sample_rate = (uint16_t)read_16bitLE(0x0e,streamFile);
+ num_samples = read_32bitLE(0x10,streamFile);
+ loop_start = read_32bitLE(0x14,streamFile);
+ loop_end = read_32bitLE(0x18,streamFile);
+
+ /* possibly more complex, see AKB2 */
+ if (header_size >= 0x44) { /* v2 */
+ extradata_size = read_16bitLE(0x1c,streamFile);
+ subheader_size = read_16bitLE(0x28,streamFile);
+ /* 0x20+: config? (pan, volume), 0x24: file_id? */
+ extradata_offset = header_size + subheader_size;
+ start_offset = extradata_offset + extradata_size;
}
else { /* v0 */
start_offset = header_size;
}
+ stream_size = get_streamfile_size(streamFile) - start_offset;
+ loop_flag = read_32bitLE(0x18,streamFile) > 0; /* loop end */
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = sample_rate;
+ vgmstream->meta_type = meta_AKB;
+
switch (codec) {
- case 0x02: { /* MSAPDCM [various SFX] */
+ case 0x02: { /* MSAPDCM [Dragon Quest II (iOS) sfx] */
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
- vgmstream->interleave_block_size = read_16bitLE(extra_data_offset + 0x02,streamFile);
+ vgmstream->interleave_block_size = read_16bitLE(extradata_offset + 0x02,streamFile);
/* adjusted samples; bigger or smaller than base samples, but seems more accurate
* (base samples may have more than possible and read over file size otherwise, very strange)
* loop_end seems to exist even with loop disabled */
- vgmstream->num_samples = read_32bitLE(extra_data_offset + 0x04, streamFile);
- vgmstream->loop_start_sample = read_32bitLE(extra_data_offset + 0x08, streamFile);
- vgmstream->loop_end_sample = read_32bitLE(extra_data_offset + 0x0c, streamFile);
+ vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, streamFile);
+ vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, streamFile);
+ vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, streamFile);
break;
}
-#ifdef VGM_USE_FFMPEG
- case 0x05: { /* Ogg Vorbis [Final Fantasy VI, Dragon Quest II-VI] */
- /* Starting from an offset in the current libvorbis code is a bit hard so just use FFmpeg.
- * Decoding seems to produce the same output with (inaudible) +-1 lower byte differences due to rounding. */
+#ifdef VGM_USE_VORBIS
+ case 0x05: { /* Ogg Vorbis [Final Fantasy VI (iOS), Dragon Quest II-VI (iOS)] */
+ VGMSTREAM *ogg_vgmstream = NULL;
+ ogg_vorbis_meta_info_t ovmi = {0};
+
+ ovmi.meta_type = vgmstream->meta_type;
+ ovmi.stream_size = stream_size;
+
+ ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
+ if (ogg_vgmstream) {
+ close_vgmstream(vgmstream);
+ return ogg_vgmstream;
+ }
+ else {
+ goto fail;
+ }
+
+ break;
+ }
+
+#elif defined(VGM_USE_FFMPEG)
+ /* Alt decoding without libvorbis (minor number of beginning samples difference).
+ * Otherwise same output with (inaudible) +-1 lower byte differences due to rounding. */
+ case 0x05: { /* Ogg Vorbis [Final Fantasy VI (iOS), Dragon Quest II-VI (iOS)] */
ffmpeg_codec_data *ffmpeg_data;
- ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,file_size-start_offset);
+ ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
@@ -109,20 +134,30 @@ VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile) {
vgmstream->layout_type = layout_none;
/* These oggs have loop info in the comments, too */
+ vgmstream->num_samples = num_samples;
+ vgmstream->loop_start_sample = loop_start;
+ vgmstream->loop_end_sample = loop_end;
+
break;
}
+#endif
+#ifdef VGM_USE_FFMPEG
case 0x06: { /* aac [The World Ends with You (iPad)] */
- /* init_vgmstream_akb above has priority, but this works fine too */
+ /* init_vgmstream_akb_mp4 above has priority, but this works fine too */
ffmpeg_codec_data *ffmpeg_data;
- ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,file_size-start_offset);
+ ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size-start_offset);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
+ vgmstream->num_samples = num_samples;
+ vgmstream->loop_start_sample = loop_start;
+ vgmstream->loop_end_sample = loop_end;
+
/* remove encoder delay from the "global" sample values */
vgmstream->num_samples -= ffmpeg_data->skipSamples;
vgmstream->loop_start_sample -= ffmpeg_data->skipSamples;
@@ -149,80 +184,134 @@ fail:
/* AKB2 - found in later SQEX iOS games */
-VGMSTREAM * init_vgmstream_akb2_multi(STREAMFILE *streamFile) {
+VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- off_t start_offset, header_offset;
- size_t datasize;
- int loop_flag = 0, channel_count, codec;
- int akb_header_size, sound_index = 0, sound_offset_data, sound, sound_header_size, material_offset_data, material_index = 0, material, extradata, encryption_flag;
+ off_t start_offset, material_offset, extradata_offset;
+ size_t material_size, extradata_size, stream_size;
+ int loop_flag = 0, channel_count, encryption_flag, codec, sample_rate, num_samples, loop_start, loop_end;
+ int total_subsongs, target_subsong = streamFile->stream_index;
/* check extensions */
/* .akb.bytes is the usual extension in later games */
- if ( !check_extensions(streamFile, "akb") )
+ if ( !check_extensions(streamFile, "akb,bytes") )
goto fail;
- /* check header */
+ /* checks */
if (read_32bitBE(0x00,streamFile) != 0x414B4232) /* "AKB2" */
goto fail;
+ if (read_32bitLE(0x08,streamFile) != get_streamfile_size(streamFile))
+ goto fail;
- akb_header_size = read_16bitLE(0x06, streamFile);
- sound_offset_data = akb_header_size + sound_index * 0x10;
- sound = read_32bitLE(sound_offset_data + 0x04, streamFile);
- sound_header_size = read_16bitLE(sound + 0x02, streamFile);
- material_offset_data = sound + sound_header_size + material_index * 0x10;
- material = sound + read_32bitLE(material_offset_data + 0x04, streamFile);
- encryption_flag = read_8bit(material + 0x03, streamFile) & 0x08;
- extradata = material + read_16bitLE(material + 0x04, streamFile);
+ /* parse tables */
+ {
+ off_t table_offset;
+ size_t table_size, entry_size;
+ off_t akb_header_size = read_16bitLE(0x06, streamFile);
+ int table_count = read_8bit(0x0c, streamFile);
- start_offset = material + read_16bitLE(material + 0x04, streamFile) + read_32bitLE(material + 0x18, streamFile);
- header_offset = material;
+ /* probably each table has its type somewhere, but only seen last table = sound table */
+ if (table_count > 2) /* 2 only seen in some Mobius FF sound banks */
+ goto fail;
+ entry_size = 0x10; /* technically every entry/table has its own size but to simplify... */
+
+ table_offset = read_32bitLE(akb_header_size + (table_count-1)*entry_size + 0x04, streamFile);
+ table_size = read_16bitLE(table_offset + 0x02, streamFile);
+
+ total_subsongs = read_8bit(table_offset + 0x0f, streamFile); /* can contain 0 entries too */
+ if (target_subsong == 0) target_subsong = 1;
+ if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
+
+ material_offset = table_offset + read_32bitLE(table_offset + table_size + (target_subsong-1)*entry_size + 0x04, streamFile);
+ }
+
+ /** stream header **/
+ /* 0x00: 0? */
+ codec = read_8bit(material_offset+0x01,streamFile);
+ channel_count = read_8bit(material_offset+0x02,streamFile);
+ encryption_flag = read_8bit(material_offset+0x03,streamFile);
+ material_size = read_16bitLE(material_offset+0x04,streamFile);
+ sample_rate = (uint16_t)read_16bitLE(material_offset+0x06,streamFile);
+ stream_size = read_32bitLE(material_offset+0x08,streamFile);
+ num_samples = read_32bitLE(material_offset+0x0c,streamFile);
+
+ loop_start = read_32bitLE(material_offset+0x10,streamFile);
+ loop_end = read_32bitLE(material_offset+0x14,streamFile);
+ extradata_size = read_32bitLE(material_offset+0x18,streamFile);
+ /* rest: ? (empty or 0x3f80) */
+
+ loop_flag = (loop_end > 0);
+ extradata_offset = material_offset + material_size;
+ start_offset = material_offset + material_size + extradata_size;
- channel_count = read_8bit(header_offset+0x02,streamFile);
- loop_flag = read_32bitLE(header_offset+0x14,streamFile) > 0; /* loop end */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- /* 0x04: version? 0x08: filesize, 0x28: file_id?, others: no idea */
- codec = read_8bit(header_offset+0x01,streamFile);
- datasize = read_32bitLE(header_offset+0x08,streamFile);
- vgmstream->sample_rate = (uint16_t)read_16bitLE(header_offset+0x06,streamFile);
- /* When loop_flag num_samples may be much larger than real num_samples (it's fine when looping is off)
- * Actual num_samples would be loop_end_sample+1, but more testing is needed */
- vgmstream->num_samples = read_32bitLE(header_offset+0x0c,streamFile);
- vgmstream->loop_start_sample = read_32bitLE(header_offset+0x10,streamFile);
- vgmstream->loop_end_sample = read_32bitLE(header_offset+0x14,streamFile);
+ vgmstream->sample_rate = sample_rate;
+ vgmstream->num_streams = total_subsongs;
+ vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_AKB;
switch (codec) {
- case 0x02: { /* MSAPDCM [The Irregular at Magic High School Lost Zero (Android)] */
- if (encryption_flag) goto fail;
+ case 0x02: { /* MSADPCM [The Irregular at Magic High School Lost Zero (Android)] */
+ if (encryption_flag & 0x08) goto fail;
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
- vgmstream->interleave_block_size = read_16bitLE(extradata + 0x02, streamFile);
+ vgmstream->interleave_block_size = read_16bitLE(extradata_offset + 0x02, streamFile);
/* adjusted samples; bigger or smaller than base samples, but seems more accurate
* (base samples may have more than possible and read over file size otherwise, very strange)
* loop_end seems to exist even with loop disabled */
- vgmstream->num_samples = read_32bitLE(extradata + 0x04, streamFile);
- vgmstream->loop_start_sample = read_32bitLE(extradata + 0x08, streamFile);
- vgmstream->loop_end_sample = read_32bitLE(extradata + 0x0c, streamFile);
+ vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, streamFile);
+ vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, streamFile);
+ vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, streamFile);
break;
}
-#ifdef VGM_USE_FFMPEG
- case 0x05: { /* ogg vorbis [The World Ends with You (iPhone / latest update)] */
+#ifdef VGM_USE_VORBIS
+ case 0x05: { /* Ogg Vorbis [The World Ends with You (iOS / latest update)] */
+ VGMSTREAM *ogg_vgmstream = NULL;
+ ogg_vorbis_meta_info_t ovmi = {0};
+
+ ovmi.meta_type = vgmstream->meta_type;
+ ovmi.total_subsongs = total_subsongs;
+ ovmi.stream_size = stream_size;
+
+ ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
+ if (ogg_vgmstream) {
+ ogg_vgmstream->num_streams = vgmstream->num_streams;
+ ogg_vgmstream->stream_size = vgmstream->stream_size;
+
+ close_vgmstream(vgmstream);
+ return ogg_vgmstream;
+ }
+ else {
+ goto fail;
+ }
+
+ break;
+ }
+
+#elif defined(VGM_USE_FFMPEG)
+ /* Alt decoding without libvorbis (minor number of beginning samples difference).
+ * Otherwise same output with (inaudible) +-1 lower byte differences due to rounding. */
+ case 0x05: { /* Ogg Vorbis [The World Ends with You (iOS / latest update)] */
ffmpeg_codec_data *ffmpeg_data;
- ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,datasize);
+ ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
+ /* When loop_flag num_samples may be much larger than real num_samples (it's fine when looping is off)
+ * Actual num_samples would be loop_end_sample+1, but more testing is needed */
+ vgmstream->num_samples = num_samples;
+ vgmstream->loop_start_sample = loop_start;
+ vgmstream->loop_end_sample = loop_end;
break;
}
#endif
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/apple_caff.c b/Frameworks/vgmstream/vgmstream/src/meta/apple_caff.c
index f2ab60d53..8e7750886 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/apple_caff.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/apple_caff.c
@@ -1,170 +1,160 @@
#include "meta.h"
-#include "../util.h"
-
-/* Apple Core Audio Format */
+#include "../coding/coding.h"
+/* Apple Core Audio Format File - from iOS games [Vectros (iOS), Ridge Racer Accelerated (iOS)] */
VGMSTREAM * init_vgmstream_apple_caff(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
+ off_t start_offset = 0, chunk_offset;
+ size_t file_size, data_size = 0;
+ int loop_flag, channel_count = 0, sample_rate = 0;
- off_t start_offset = 0;
- off_t data_size = 0;
- off_t sample_count = 0;
- off_t interleave = 0;
- int sample_rate = -1, unused_frames = 0;
- int channel_count = 0;
-
- off_t file_length;
- off_t chunk_offset = 8;
- int found_desc = 0, found_pakt = 0, found_data = 0;
+ int found_desc = 0 /*, found_pakt = 0*/, found_data = 0;
+ uint32_t codec = 0 /*, codec_flags = 0*/;
+ uint32_t bytes_per_packet = 0, samples_per_packet = 0, channels_per_packet = 0, bits_per_sample = 0;
+ int valid_samples = 0 /*, priming_samples = 0, unused_samples = 0*/;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("caf",filename_extension(filename))) goto fail;
- /* check "caff" id */
- if (read_32bitBE(0,streamFile)!=0x63616666) goto fail;
- /* check version, flags */
- if (read_32bitBE(4,streamFile)!=0x00010000) goto fail;
+ /* checks */
+ if (!check_extensions(streamFile, "caf"))
+ goto fail;
- file_length = (off_t)get_streamfile_size(streamFile);
+ if (read_32bitBE(0x00,streamFile) != 0x63616666) /* "caff" */
+ goto fail;
+ if (read_32bitBE(0x04,streamFile) != 0x00010000) /* version/flags */
+ goto fail;
- while (chunk_offset < file_length)
- {
- /* high half of size (expect 0s) */
- if (read_32bitBE(chunk_offset+4,streamFile) != 0) goto fail;
+ file_size = get_streamfile_size(streamFile);
+ chunk_offset = 0x08;
- /* handle chunk type */
- switch (read_32bitBE(chunk_offset,streamFile))
- {
- case 0x64657363: /* desc */
+ while (chunk_offset < file_size) {
+ uint32_t chunk_type = read_32bitBE(chunk_offset+0x00,streamFile);
+ uint32_t chunk_size = (uint32_t)read_64bitBE(chunk_offset+0x04,streamFile);
+ chunk_offset += 0x0c;
+
+ switch (chunk_type) {
+
+ case 0x64657363: /* "desc" */
found_desc = 1;
- {
- /* rather than put a convoluted conversion here for
- portability, just look it up */
- uint32_t sratefloat = read_32bitBE(chunk_offset+0x0c, streamFile);
- if (read_32bitBE(chunk_offset+0x10, streamFile) != 0) goto fail;
- switch (sratefloat)
- {
- case 0x40D19400:
- sample_rate = 18000;
- break;
- case 0x40D58880:
- sample_rate = 22050;
- break;
- case 0x40DF4000:
- sample_rate = 32000;
- break;
- case 0x40E58880:
- sample_rate = 44100;
- break;
- case 0x40E77000:
- sample_rate = 48000;
- break;
- default:
- goto fail;
- }
- }
{
- uint32_t bytes_per_packet, frames_per_packet, channels_per_frame, bits_per_channel;
- uint32_t codec_4cc = read_32bitBE(chunk_offset+0x14, streamFile);
- /* only supporting ima4 for now */
- if (codec_4cc != 0x696d6134) goto fail;
+ uint64_t sample_long = (uint64_t)read_64bitBE(chunk_offset+0x00, streamFile);
+ double* sample_double; /* double sample rate, double the fun */
- /* format flags */
- if (read_32bitBE(chunk_offset+0x18, streamFile) != 0) goto fail;
- bytes_per_packet = read_32bitBE(chunk_offset+0x1c, streamFile);
- frames_per_packet = read_32bitBE(chunk_offset+0x20, streamFile);
- channels_per_frame = read_32bitBE(chunk_offset+0x24, streamFile);
- bits_per_channel = read_32bitBE(chunk_offset+0x28, streamFile);
-
- interleave = bytes_per_packet / channels_per_frame;
- channel_count = channels_per_frame;
- if (channels_per_frame != 1 && channels_per_frame != 2)
- goto fail;
- /* ima4-specific */
- if (frames_per_packet != 64) goto fail;
- if ((frames_per_packet / 2 + 2) * channels_per_frame !=
- bytes_per_packet) goto fail;
- if (bits_per_channel != 0) goto fail;
+ sample_double = (double*)&sample_long;
+ sample_rate = (int)(*sample_double);
}
+
+ codec = read_32bitBE(chunk_offset+0x08, streamFile);
+ //codec_flags = read_32bitBE(chunk_offset+0x0c, streamFile);
+ bytes_per_packet = read_32bitBE(chunk_offset+0x10, streamFile);
+ samples_per_packet = read_32bitBE(chunk_offset+0x14, streamFile);
+ channels_per_packet = read_32bitBE(chunk_offset+0x18, streamFile);
+ bits_per_sample = read_32bitBE(chunk_offset+0x1C, streamFile);
break;
- case 0x70616b74: /* pakt */
- found_pakt = 1;
- /* 64-bit packet table size, 0 for constant bitrate */
- if (
- read_32bitBE(chunk_offset+0x0c,streamFile) != 0 ||
- read_32bitBE(chunk_offset+0x10,streamFile) != 0) goto fail;
- /* high half of valid frames count */
- if (read_32bitBE(chunk_offset+0x14,streamFile) != 0) goto fail;
- /* frame count */
- sample_count = read_32bitBE(chunk_offset+0x18,streamFile);
- /* priming frames */
- if (read_32bitBE(chunk_offset+0x1c,streamFile) != 0) goto fail;
- /* remainder (unused) frames */
- unused_frames = read_32bitBE(chunk_offset+0x20,streamFile);
+
+ case 0x70616b74: /* "pakt" */
+ //found_pakt = 1;
+
+ //packets_table_size = (uint32_t)read_64bitBE(chunk_offset+0x00,streamFile); /* 0 for constant bitrate */
+ valid_samples = (uint32_t)read_64bitBE(chunk_offset+0x08,streamFile);
+ //priming_samples = read_32bitBE(chunk_offset+0x10,streamFile); /* encoder delay samples */
+ //unused_samples = read_32bitBE(chunk_offset+0x14,streamFile); /* footer samples */
break;
- case 0x66726565: /* free */
- /* padding, ignore */
- break;
- case 0x64617461: /* data */
- if (read_32bitBE(chunk_offset+12,streamFile) != 1) goto fail;
+
+ case 0x64617461: /* "data" */
found_data = 1;
- start_offset = chunk_offset + 16;
- data_size = read_32bitBE(chunk_offset+8,streamFile) - 4;
+
+ /* 0x00: version? 0x00/0x01 */
+ start_offset = chunk_offset + 0x04;
+ data_size = chunk_size - 0x4;
+ break;
+
+ default: /* "free" "kuki" "info" "chan" etc: ignore */
break;
- default:
- goto fail;
}
/* done with chunk */
- chunk_offset += 12 + read_32bitBE(chunk_offset+8,streamFile);
+ chunk_offset += chunk_size;
}
- if (!found_pakt || !found_desc || !found_data) goto fail;
- if (start_offset == 0 || data_size == 0 || sample_count == 0 ||
- sample_rate == -1 || channel_count == 0) goto fail;
+ if (!found_desc || !found_data)
+ goto fail;
+ if (start_offset == 0 || data_size == 0)
+ goto fail;
- /* ima4-specific */
- /* check for full packets */
- if (data_size % (interleave*channel_count) != 0) goto fail;
- if ((sample_count+unused_frames)%((interleave-2)*2) != 0) goto fail;
- /* check that all packets are accounted for */
- if (data_size/interleave/channel_count !=
- (sample_count+unused_frames)/((interleave-2)*2)) goto fail;
- vgmstream = allocate_vgmstream(channel_count,0);
+ loop_flag = 0;
+ channel_count = channels_per_packet;
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- vgmstream->channels = channel_count;
vgmstream->sample_rate = sample_rate;
- vgmstream->num_samples = sample_count;
- /* ima4-specific */
- vgmstream->coding_type = coding_APPLE_IMA4;
- if (channel_count == 2)
- vgmstream->layout_type = layout_interleave;
- else
- vgmstream->layout_type = layout_none;
- vgmstream->interleave_block_size = interleave;
vgmstream->meta_type = meta_CAFF;
- /* open the file for reading by each channel */
- {
- int i;
- for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[i].streamfile) goto fail;
+ switch(codec) {
+ case 0x6C70636D: /* "lpcm" */
+ vgmstream->num_samples = valid_samples;
+ if (!vgmstream->num_samples)
+ vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, bits_per_sample);
- vgmstream->ch[i].offset =
- vgmstream->ch[i].channel_start_offset =
- start_offset + interleave * i;
- }
+ //todo check codec_flags for BE/LE, signed/etc
+ if (bits_per_sample == 8) {
+ vgmstream->coding_type = coding_PCM8;
+ }
+ else {
+ goto fail;
+ }
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = bytes_per_packet / channels_per_packet;
+
+ break;
+
+ case 0x696D6134: /* "ima4" [Vectros (iOS), Dragon Quest (iOS)] */
+ vgmstream->num_samples = valid_samples;
+ if (!vgmstream->num_samples) /* rare [Endless Fables 2 (iOS) */
+ vgmstream->num_samples = apple_ima4_bytes_to_samples(data_size, channel_count);
+
+ vgmstream->coding_type = coding_APPLE_IMA4;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = bytes_per_packet / channels_per_packet;
+
+ /* ima4 defaults */
+ //if (channels_per_packet != 1 && channels_per_packet != 2)
+ // goto fail;
+ if (samples_per_packet != 64)
+ goto fail;
+ if ((samples_per_packet / 2 + 2) * channels_per_packet != bytes_per_packet)
+ goto fail;
+ if (bits_per_sample != 0 && bits_per_sample != 4) /* 4 is rare too [Endless Fables 2 (iOS) */
+ goto fail;
+
+ /* check for full packets and that all packets are accounted for */
+ //if (found_pakt) {
+ // if (data_size % (vgmstream->interleave_block_size*channel_count) != 0)
+ // goto fail;
+ // if ((valid_samples+unused_samples)%((vgmstream->interleave_block_size-2)*2) != 0)
+ // goto fail;
+ // if (data_size/vgmstream->interleave_block_size/channel_count !=
+ // (valid_samples+unused_samples)/((vgmstream->interleave_block_size-2)*2))
+ // goto fail;
+ //}
+
+ break;
+
+ case 0x61616320: /* "aac " [Ridge Racer Accelerated (iOS)] */
+ case 0x616C6163: /* "alac" [Chrono Trigger v1 (iOS)] */
+ default: /* should be parsed by FFMpeg in its meta (involves parsing complex chunks) */
+ goto fail;
}
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
+
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ast.c b/Frameworks/vgmstream/vgmstream/src/meta/ast.c
index fde881724..4ed5162c2 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ast.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ast.c
@@ -59,7 +59,7 @@ VGMSTREAM * init_vgmstream_ast(STREAMFILE *streamFile) {
vgmstream->loop_end_sample = read_32bitBE(0x1c,streamFile);
vgmstream->coding_type = coding_type;
- vgmstream->layout_type = layout_ast_blocked;
+ vgmstream->layout_type = layout_blocked_ast;
vgmstream->meta_type = meta_AST;
/* open the file for reading by each channel */
@@ -80,7 +80,7 @@ VGMSTREAM * init_vgmstream_ast(STREAMFILE *streamFile) {
}
/* start me up */
- ast_block_update(0x40,vgmstream);
+ block_update_ast(0x40,vgmstream);
return vgmstream;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/atsl.c b/Frameworks/vgmstream/vgmstream/src/meta/atsl.c
new file mode 100644
index 000000000..bb19f62ff
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/atsl.c
@@ -0,0 +1,168 @@
+#include "meta.h"
+#include "../coding/coding.h"
+
+static STREAMFILE* setup_atsl_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext);
+typedef enum { ATRAC3, ATRAC9, KOVS, KTSS } atsl_codec;
+
+/* .ATSL - Koei Tecmo audio container [One Piece Pirate Warriors (PS3), Warriors All-Stars (PC)] */
+VGMSTREAM * init_vgmstream_atsl(STREAMFILE *streamFile) {
+ VGMSTREAM *vgmstream = NULL;
+ STREAMFILE *temp_streamFile = NULL;
+ int total_subsongs, target_subsong = streamFile->stream_index;
+ int type, big_endian = 0, entries;
+ atsl_codec codec;
+ const char* fake_ext;
+ off_t subfile_offset = 0;
+ size_t subfile_size = 0, header_size;
+ int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
+
+
+ /* checks */
+ /* .atsl: header id (for G1L extractions), .atsl3: PS3 games, .atsl4: PS4 games */
+ if ( !check_extensions(streamFile,"atsl,atsl3,atsl4"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x4154534C) /* "ATSL" */
+ goto fail;
+
+ /* main header (LE) */
+ header_size = read_32bitLE(0x04,streamFile);
+ /* 0x08/0c: flags?, 0x10: fixed? (0x03E8) */
+ entries = read_32bitLE(0x14,streamFile);
+ /* 0x18: 0x28, or 0x30 (rarer) */
+ /* 0x1c: null, 0x20: subheader size, 0x24/28: null */
+
+ /* Type byte may be wrong (could need header id tests instead). Example flags at 0x08/0x0c:
+ * - 00010101 00020001 .atsl3 from One Piece Pirate Warriors (PS3)[ATRAC3]
+ * - 00000201 00020001 .atsl3 from Fist of North Star: Ken's Rage 2 (PS3)[ATRAC3]
+ * 00000301 00020101 (same)
+ * - 01040301 00060301 .atsl4 from Nobunaga's Ambition: Sphere of Influence (PS4)[ATRAC9]
+ * - 00060301 00040301 atsl in G1L from One Piece Pirate Warriors 3 (Vita)[ATRAC9]
+ * - 00060301 00010301 atsl in G1L from One Piece Pirate Warriors 3 (PC)[KOVS]
+ * - 000A0301 00010501 atsl in G1L from Warriors All-Stars (PC)[KOVS]
+ * - 000B0301 00080601 atsl in G1l from Sengoku Musou Sanada Maru (Switch)[KTSS]
+ */
+ type = read_8bit(0x0d, streamFile);
+ switch(type) {
+ case 0x01:
+ codec = KOVS;
+ fake_ext = "kvs";
+ break;
+ case 0x02:
+ codec = ATRAC3;
+ fake_ext = "at3";
+ big_endian = 1;
+ break;
+ case 0x04:
+ case 0x06:
+ codec = ATRAC9;
+ fake_ext = "at9";
+ break;
+ case 0x08:
+ codec = KTSS;
+ fake_ext = "ktss";
+ break;
+ default:
+ VGM_LOG("ATSL: unknown type %x\n", type);
+ goto fail;
+ }
+ read_32bit = big_endian ? read_32bitBE : read_32bitLE;
+
+
+ /* entries can point to the same file, count unique only */
+ {
+ int i,j;
+
+ total_subsongs = 0;
+ if (target_subsong == 0) target_subsong = 1;
+
+ /* parse entry header (in machine endianness) */
+ for (i = 0; i < entries; i++) {
+ int is_unique = 1;
+
+ off_t entry_offset = read_32bit(header_size + i*0x28 + 0x04,streamFile);
+ size_t entry_size = read_32bit(header_size + i*0x28 + 0x08,streamFile);
+ /* 0x00: id?, 0x08+: sample rate/num_samples/loop_start/etc, matching subfile header */
+
+ /* check if current entry was repeated in a prev entry */
+ for (j = 0; j < i; j++) {
+ off_t prev_offset = read_32bit(header_size + j*0x28 + 0x04,streamFile);
+ if (prev_offset == entry_offset) {
+ is_unique = 0;
+ break;
+ }
+ }
+ if (!is_unique)
+ continue;
+
+ total_subsongs++;
+
+ /* target GET, but keep going to count subsongs */
+ if (!subfile_offset && target_subsong == total_subsongs) {
+ subfile_offset = entry_offset;
+ subfile_size = entry_size;
+ }
+ }
+ }
+ if (target_subsong > total_subsongs || total_subsongs <= 0) goto fail;
+ if (!subfile_offset || !subfile_size) goto fail;
+
+
+ /* some kind of seek/switch table may follow (optional, found in .atsl3) */
+
+
+ temp_streamFile = setup_atsl_streamfile(streamFile, subfile_offset,subfile_size, fake_ext);
+ if (!temp_streamFile) goto fail;
+
+ /* init the VGMSTREAM */
+ switch(codec) {
+ case ATRAC3:
+ case ATRAC9:
+ vgmstream = init_vgmstream_riff(temp_streamFile);
+ if (!vgmstream) goto fail;
+ break;
+ case KOVS:
+ vgmstream = init_vgmstream_ogg_vorbis(temp_streamFile);
+ if (!vgmstream) goto fail;
+ break;
+ case KTSS:
+ vgmstream = init_vgmstream_ktss(temp_streamFile);
+ if (!vgmstream) goto fail;
+ break;
+ default:
+ goto fail;
+ }
+
+ vgmstream->num_streams = total_subsongs;
+
+ close_streamfile(temp_streamFile);
+ return vgmstream;
+
+fail:
+ close_streamfile(temp_streamFile);
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+
+static STREAMFILE* setup_atsl_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext) {
+ STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
+
+ /* setup subfile */
+ new_streamFile = open_wrap_streamfile(streamFile);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,fake_ext);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ return temp_streamFile;
+
+fail:
+ close_streamfile(temp_streamFile);
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/atsl3.c b/Frameworks/vgmstream/vgmstream/src/meta/atsl3.c
deleted file mode 100644
index 722c3f77f..000000000
--- a/Frameworks/vgmstream/vgmstream/src/meta/atsl3.c
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "meta.h"
-#include "../coding/coding.h"
-
-static STREAMFILE* setup_atsl3_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size);
-
-/* .ATSL3 - Koei Tecmo container of multiple .AT3 [One Piece Pirate Warriors (PS3)] */
-VGMSTREAM * init_vgmstream_atsl3(STREAMFILE *streamFile) {
- VGMSTREAM *vgmstream = NULL;
- STREAMFILE *temp_streamFile = NULL;
- int total_subsongs, target_subsong = streamFile->stream_index;
- off_t subfile_offset;
- size_t subfile_size, header_size, entry_size;
-
- /* check extensions */
- if ( !check_extensions(streamFile,"atsl3"))
- goto fail;
- if (read_32bitBE(0x00,streamFile) != 0x4154534C) /* "ATSL" */
- goto fail;
-
- /* main header (LE) */
- header_size = read_32bitLE(0x04,streamFile);
- /* 0x08/0c: flags?, 0x10: some size? */
- total_subsongs = read_32bitLE(0x14,streamFile);
- entry_size = read_32bitLE(0x18,streamFile);
- /* 0x1c: null, 0x20: subheader size, 0x24/28: null */
-
- if (target_subsong == 0) target_subsong = 1;
- if (target_subsong > total_subsongs || total_subsongs <= 0) goto fail;
-
- /* entry header (BE) */
- /* 0x00: id */
- subfile_offset = read_32bitBE(header_size + (target_subsong-1)*entry_size + 0x04,streamFile);
- subfile_size = read_32bitBE(header_size + (target_subsong-1)*entry_size + 0x08,streamFile);
- /* 0x08+: sample rate/num_samples/loop_start/etc, matching subfile header */
- /* some kind of seek/switch table follows */
-
- temp_streamFile = setup_atsl3_streamfile(streamFile, subfile_offset,subfile_size);
- if (!temp_streamFile) goto fail;
-
- /* init the VGMSTREAM */
- vgmstream = init_vgmstream_riff(temp_streamFile);
- if (!vgmstream) goto fail;
- vgmstream->num_streams = total_subsongs;
-
- close_streamfile(temp_streamFile);
- return vgmstream;
-
-fail:
- close_streamfile(temp_streamFile);
- close_vgmstream(vgmstream);
- return NULL;
-}
-
-
-static STREAMFILE* setup_atsl3_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size) {
- STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
-
- /* setup subfile */
- new_streamFile = open_wrap_streamfile(streamFile);
- if (!new_streamFile) goto fail;
- temp_streamFile = new_streamFile;
-
- new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
- if (!new_streamFile) goto fail;
- temp_streamFile = new_streamFile;
-
- new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"at3");
- if (!new_streamFile) goto fail;
- temp_streamFile = new_streamFile;
-
- return temp_streamFile;
-
-fail:
- close_streamfile(temp_streamFile);
- return NULL;
-}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/atx.c b/Frameworks/vgmstream/vgmstream/src/meta/atx.c
index e540baa36..bace1a298 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/atx.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/atx.c
@@ -49,7 +49,7 @@ static STREAMFILE* setup_atx_streamfile(STREAMFILE *streamFile) {
num_segments = read_16bitLE(0x1e,streamFile);
/* expected segment name: X_XXX_XXX_0n.ATX, starting from n=1 */
- get_streamfile_name(streamFile, filename,PATH_LIMIT);
+ get_streamfile_filename(streamFile, filename,PATH_LIMIT);
filename_len = strlen(filename);
if (filename_len < 7 || filename[filename_len - 5] != '1') goto fail;
@@ -59,7 +59,7 @@ static STREAMFILE* setup_atx_streamfile(STREAMFILE *streamFile) {
size_t subfile_size;
filename[filename_len - 5] = ('0'+i+1); /* ghetto digit conversion */
- new_streamFile = open_stream_name(streamFile, filename);
+ new_streamFile = open_streamfile_by_filename(streamFile, filename);
if (!new_streamFile) goto fail;
segment_streamFiles[i] = new_streamFile;
@@ -96,12 +96,16 @@ static STREAMFILE* setup_atx_streamfile(STREAMFILE *streamFile) {
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
+ /* if all this worked we'll have this frankenstein streamfile:
+ * fakename( clamp( multifile( segment0=clamp(standard(FILE)), segment1=clamp(standard(FILE)) ) ) ) */
+
return temp_streamFile;
fail:
if (!temp_streamFile) {
- for (i = 0; i < num_segments; i++)
+ for (i = 0; i < num_segments; i++) {
close_streamfile(segment_streamFiles[i]);
+ }
} else {
close_streamfile(temp_streamFile); /* closes all segments */
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/awc.c b/Frameworks/vgmstream/vgmstream/src/meta/awc.c
index ab73b6cdd..1994613a6 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/awc.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/awc.c
@@ -1,6 +1,7 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
+#include "awc_xma_streamfile.h"
typedef struct {
int big_endian;
@@ -17,7 +18,7 @@ typedef struct {
int block_chunk;
off_t stream_offset;
- off_t stream_size;
+ size_t stream_size;
} awc_header;
@@ -64,6 +65,76 @@ VGMSTREAM * init_vgmstream_awc(STREAMFILE *streamFile) {
vgmstream->codec_endian = awc.big_endian;
break;
+#ifdef VGM_USE_FFMPEG
+ case 0x05: { /* XMA2 (X360) */
+ uint8_t buf[0x100];
+ size_t bytes, block_size, block_count, substream_size;
+ off_t substream_offset;
+
+ if (awc.is_music) {
+ /* 1ch XMAs in blocks, we'll use layered layout + custom IO to get multi-FFmpegs working */
+ int i;
+ layered_layout_data * data = NULL;
+
+ /* init layout */
+ data = init_layout_layered(awc.channel_count);
+ if (!data) goto fail;
+ vgmstream->layout_data = data;
+ vgmstream->layout_type = layout_layered;
+ vgmstream->coding_type = coding_FFmpeg;
+
+ /* open each layer subfile */
+ for (i = 0; i < awc.channel_count; i++) {
+ STREAMFILE* temp_streamFile;
+ int layer_channels = 1;
+
+ /* build the layer VGMSTREAM */
+ data->layers[i] = allocate_vgmstream(layer_channels, 0);
+ if (!data->layers[i]) goto fail;
+
+ data->layers[i]->sample_rate = awc.sample_rate;
+ data->layers[i]->meta_type = meta_AWC;
+ data->layers[i]->coding_type = coding_FFmpeg;
+ data->layers[i]->layout_type = layout_none;
+ data->layers[i]->num_samples = awc.num_samples;
+
+ /* setup custom IO streamfile, pass to FFmpeg and hope it's fooled */
+ temp_streamFile = setup_awc_xma_streamfile(streamFile, awc.stream_offset, awc.stream_size, awc.block_chunk, awc.channel_count, i);
+ if (!temp_streamFile) goto fail;
+
+ substream_offset = 0; /* where FFmpeg thinks data starts, which our custom streamFile will clamp */
+ substream_size = get_streamfile_size(temp_streamFile); /* data of one XMA substream without blocks */
+ block_size = 0x8000; /* no idea */
+ block_count = substream_size / block_size; /* not accurate but not needed */
+
+ bytes = ffmpeg_make_riff_xma2(buf, 0x100, awc.num_samples, substream_size, layer_channels, awc.sample_rate, block_count, block_size);
+ data->layers[i]->codec_data = init_ffmpeg_header_offset(temp_streamFile, buf,bytes, substream_offset,substream_size);
+
+ close_streamfile(temp_streamFile);
+ if (!data->layers[i]->codec_data) goto fail;
+ }
+
+ /* setup layered VGMSTREAMs */
+ if (!setup_layout_layered(data))
+ goto fail;
+ }
+ else {
+ /* regular XMA for sfx */
+ block_size = 0x8000; /* no idea */
+ block_count = awc.stream_size / block_size; /* not accurate but not needed */
+
+ bytes = ffmpeg_make_riff_xma2(buf, 0x100, awc.num_samples, awc.stream_size, awc.channel_count, awc.sample_rate, block_count, block_size);
+ vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, awc.stream_offset,awc.stream_size);
+ if (!vgmstream->codec_data) goto fail;
+ vgmstream->coding_type = coding_FFmpeg;
+ vgmstream->layout_type = layout_none;
+ }
+
+ break;
+ }
+
+
+#endif
#ifdef VGM_USE_MPEG
case 0x07: { /* MPEG (PS3) */
mpeg_custom_config cfg;
@@ -80,7 +151,6 @@ VGMSTREAM * init_vgmstream_awc(STREAMFILE *streamFile) {
}
#endif
- case 0x05: /* XMA2 (X360) */
default:
VGM_LOG("AWC: unknown codec 0x%02x\n", awc.codec);
goto fail;
@@ -187,12 +257,15 @@ static int parse_awc_header(STREAMFILE* streamFile, awc_header* awc) {
/* get stream tags */
for (i = 0; i < tag_count; i++) {
- uint64_t tag_header, tag, size, offset;
+ uint64_t tag_header;
+ uint8_t tag;
+ size_t size;
+ off_t offset;
tag_header = (uint64_t)read_64bit(off + 0x08*i,streamFile);
- tag = (tag_header >> 56) & 0xFF; /* 8b */
- size = (tag_header >> 28) & 0x0FFFFFFF; /* 28b */
- offset = (tag_header >> 0) & 0x0FFFFFFF; /* 28b */
+ tag = (uint8_t)((tag_header >> 56) & 0xFF); /* 8b */
+ size = (size_t)((tag_header >> 28) & 0x0FFFFFFF); /* 28b */
+ offset = (off_t)((tag_header >> 0) & 0x0FFFFFFF); /* 28b */
/* Tags are apparently part of a hash derived from a word ("data", "format", etc).
* If music + 1ch, the header and data chunks can repeat for no reason (sometimes not even pointed). */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/awc_xma_streamfile.h b/Frameworks/vgmstream/vgmstream/src/meta/awc_xma_streamfile.h
new file mode 100644
index 000000000..f4c231c7a
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/awc_xma_streamfile.h
@@ -0,0 +1,257 @@
+#ifndef _AWC_XMA_STREAMFILE_H_
+#define _AWC_XMA_STREAMFILE_H_
+#include "../streamfile.h"
+
+
+typedef struct {
+ /* config */
+ off_t stream_offset;
+ size_t stream_size;
+ int channel_count;
+ int channel;
+ size_t chunk_size;
+
+ /* state */
+ off_t logical_offset; /* offset that corresponds to physical_offset */
+ off_t physical_offset; /* actual file offset */
+ off_t next_block_offset; /* physical offset of the next block start */
+ off_t last_offset; /* physical offset of where the last block ended */
+ size_t current_data_size;
+ size_t current_consumed_size;
+
+ size_t total_size; /* size of the resulting XMA data */
+} awc_xma_io_data;
+
+
+static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, awc_xma_io_data *data);
+static size_t get_repeated_data_size(STREAMFILE *streamFile, off_t new_offset, off_t last_offset);
+static size_t get_block_skip_count(STREAMFILE *streamFile, off_t offset, int channel);
+
+/* Reads plain XMA data of a single stream. Each block has a header and channels have different num_samples/frames.
+ * Channel data is separate within the block (first all frames of ch0, then ch1, etc), padded, and sometimes
+ * the last few frames of a channel are repeated in the new block (marked with the "discard samples" field). */
+static size_t awc_xma_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, awc_xma_io_data* data) {
+ size_t total_read = 0;
+ size_t frame_size = 0x800;
+
+ /* ignore bad reads */
+ if (offset < 0 || offset > data->total_size) {
+ return 0;
+ }
+
+ /* previous offset: re-start as we can't map logical<>physical offsets
+ * (kinda slow as it trashes buffers, but shouldn't happen often) */
+ if (offset < data->logical_offset) {
+ data->logical_offset = 0x00;
+ data->physical_offset = data->stream_offset;
+ data->next_block_offset = 0;
+ data->last_offset = 0;
+ data->current_data_size = 0;
+ data->current_consumed_size = 0;
+ }
+
+ /* read from block, moving to next when all data is consumed */
+ while (length > 0) {
+ size_t to_read, bytes_read;
+
+ /* new block */
+ if (data->current_data_size == 0) {
+ size_t header_size = get_block_header_size(streamfile, data->physical_offset, data);
+ /* header table entries = frames... I hope */
+ size_t skip_size = get_block_skip_count(streamfile, data->physical_offset, data->channel) * frame_size;
+ //size_t skip_size = read_32bitBE(data->physical_offset + 0x10*data->channel + 0x00, streamfile) * frame_size;
+ size_t data_size = read_32bitBE(data->physical_offset + 0x10*data->channel + 0x04, streamfile) * frame_size;
+ size_t repeat_samples = read_32bitBE(data->physical_offset + 0x10*data->channel + 0x08, streamfile);
+ size_t repeat_size = 0;
+
+ /* if there are repeat samples current block repeats some frames from last block, find out size */
+ if (repeat_samples && data->last_offset) {
+ off_t data_offset = data->physical_offset + header_size + skip_size;
+ repeat_size = get_repeated_data_size(streamfile, data_offset, data->last_offset);
+ }
+
+ data->next_block_offset = data->physical_offset + data->chunk_size;
+ data->physical_offset += header_size + skip_size + repeat_size; /* data start */
+ data->current_data_size = data_size - repeat_size; /* readable max in this block */
+ data->current_consumed_size = 0;
+ continue;
+ }
+
+ /* block end, go next */
+ if (data->current_consumed_size == data->current_data_size) {
+ data->last_offset = data->physical_offset; /* where last block ended */
+ data->physical_offset = data->next_block_offset;
+ data->current_data_size = 0;
+ continue;
+ }
+
+ /* requested offset is further along, pretend we consumed data and try again */
+ if (offset > data->logical_offset) {
+ size_t to_consume = offset - data->logical_offset;
+ if (to_consume > data->current_data_size - data->current_consumed_size)
+ to_consume = data->current_data_size - data->current_consumed_size;
+
+ data->physical_offset += to_consume;
+ data->logical_offset += to_consume;
+ data->current_consumed_size += to_consume;
+ continue;
+ }
+
+ /* clamp reads up to this block's end */
+ to_read = (data->current_data_size - data->current_consumed_size);
+ if (to_read > length)
+ to_read = length;
+ if (to_read == 0)
+ return total_read; /* should never happen... */
+
+ /* finally read and move buffer/offsets */
+ bytes_read = read_streamfile(dest, data->physical_offset, to_read, streamfile);
+ total_read += bytes_read;
+ if (bytes_read != to_read)
+ return total_read; /* couldn't read fully */
+
+ dest += bytes_read;
+ offset += bytes_read;
+ length -= bytes_read;
+
+ data->physical_offset += bytes_read;
+ data->logical_offset += bytes_read;
+ data->current_consumed_size += bytes_read;
+ }
+
+ return total_read;
+}
+
+static size_t awc_xma_io_size(STREAMFILE *streamfile, awc_xma_io_data* data) {
+ off_t physical_offset, max_physical_offset, last_offset;
+ size_t frame_size = 0x800;
+ size_t total_size = 0;
+
+ if (data->total_size)
+ return data->total_size;
+
+ physical_offset = data->stream_offset;
+ max_physical_offset = data->stream_offset + data->stream_size;
+ last_offset = 0;
+
+ /* read blocks and sum final size */
+ while (physical_offset < max_physical_offset) {
+ size_t header_size = get_block_header_size(streamfile, physical_offset, data);
+ /* header table entries = frames... I hope */
+ size_t skip_size = get_block_skip_count(streamfile, physical_offset, data->channel) * frame_size;
+ //size_t skip_size = read_32bitBE(physical_offset + 0x10*data->channel + 0x00, streamfile) * frame_size;
+ size_t data_size = read_32bitBE(physical_offset + 0x10*data->channel + 0x04, streamfile) * frame_size;
+ size_t repeat_samples = read_32bitBE(physical_offset + 0x10*data->channel + 0x08, streamfile);
+ size_t repeat_size = 0;
+
+ /* if there are repeat samples current block repeats some frames from last block, find out size */
+ if (repeat_samples && last_offset) {
+ off_t data_offset = physical_offset + header_size + skip_size;
+ repeat_size = get_repeated_data_size(streamfile, data_offset, last_offset);
+ }
+
+ last_offset = physical_offset + header_size + skip_size + data_size;
+ total_size += data_size - repeat_size;
+ physical_offset += data->chunk_size;
+ }
+
+ data->total_size = total_size;
+ return data->total_size;
+}
+
+
+/* Prepares custom IO for AWC XMA, which is interleaved XMA in AWC blocks */
+static STREAMFILE* setup_awc_xma_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t stream_size, size_t chunk_size, int channel_count, int channel) {
+ STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
+ awc_xma_io_data io_data = {0};
+ size_t io_data_size = sizeof(awc_xma_io_data);
+
+ io_data.stream_offset = stream_offset;
+ io_data.stream_size = stream_size;
+ io_data.chunk_size = chunk_size;
+ io_data.channel_count = channel_count;
+ io_data.channel = channel;
+ io_data.physical_offset = stream_offset;
+
+ /* setup subfile */
+ new_streamFile = open_wrap_streamfile(streamFile);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, awc_xma_io_read,awc_xma_io_size);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ //todo maybe should force to read filesize once
+ return temp_streamFile;
+
+fail:
+ close_streamfile(temp_streamFile);
+ return NULL;
+}
+
+/* block header size, aligned/padded to 0x800 */
+static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, awc_xma_io_data *data) {
+ size_t header_size = 0;
+ int i;
+ int entries = data->channel_count;
+
+ for (i = 0; i < entries; i++) {
+ header_size += 0x10;
+ header_size += read_32bitBE(offset + 0x10*i + 0x04, streamFile) * 0x04; /* entries in the table */
+ }
+
+ if (header_size % 0x800) /* padded */
+ header_size += 0x800 - (header_size % 0x800);
+
+ return header_size;
+}
+
+
+/* find data that repeats in the beginning of a new block at the end of last block */
+static size_t get_repeated_data_size(STREAMFILE *streamFile, off_t new_offset, off_t last_offset) {
+ uint8_t new_frame[0x800];/* buffer to avoid fseek back and forth */
+ size_t frame_size = 0x800;
+ off_t offset;
+ int i;
+
+ /* read block first frame */
+ if (read_streamfile(new_frame,new_offset, frame_size,streamFile) != frame_size)
+ goto fail;
+
+ /* find the frame in last bytes of prev block */
+ offset = last_offset - 0x4000; /* typical max is 1 frame of ~0x800, no way to know exact size */
+ while (offset < last_offset) {
+ /* compare frame vs prev block data */
+ for (i = 0; i < frame_size; i++) {
+ if ((uint8_t)read_8bit(offset+i,streamFile) != new_frame[i])
+ break;
+ }
+
+ /* frame fully compared? */
+ if (i == frame_size)
+ return last_offset - offset;
+ else
+ offset += i+1;
+ }
+
+fail:
+ VGM_LOG("AWC: can't find repeat size, new=0x%08lx, last=0x%08lx\n", new_offset, last_offset);
+ return 0; /* keep on truckin' */
+}
+
+/* header has a skip value, but somehow it's sometimes bigger than expected (WHY!?!?) so just sum all */
+static size_t get_block_skip_count(STREAMFILE *streamFile, off_t offset, int channel) {
+ size_t skip_count = 0;
+ int i;
+
+ //skip_size = read_32bitBE(offset + 0x10*channel + 0x00, streamFile); /* wrong! */
+ for (i = 0; i < channel; i++) {
+ skip_count += read_32bitBE(offset + 0x10*i + 0x04, streamFile); /* number of frames of this channel */
+ }
+
+ return skip_count;
+}
+
+
+#endif /* _AWC_XMA_STREAMFILE_H_ */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bar_streamfile.h b/Frameworks/vgmstream/vgmstream/src/meta/bar_streamfile.h
index 81d43befc..fbe455952 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/bar_streamfile.h
+++ b/Frameworks/vgmstream/vgmstream/src/meta/bar_streamfile.h
@@ -41,11 +41,7 @@ static size_t get_offset_bar(BARSTREAMFILE *streamFile) {
}
static void get_name_bar(BARSTREAMFILE *streamFile, char *name, size_t length) {
- return streamFile->real_file->get_name(streamFile->real_file, name, length);
-}
-
-static void get_realname_bar(BARSTREAMFILE *streamFile, char *name, size_t length) {
- return streamFile->real_file->get_realname(streamFile->real_file, name, length);
+ streamFile->real_file->get_name(streamFile->real_file, name, length);
}
STREAMFILE *open_bar(BARSTREAMFILE *streamFile, const char * const filename, size_t buffersize) {
@@ -75,7 +71,6 @@ static void close_bar(BARSTREAMFILE *streamFile) {
streamfile->sf.get_size = (void*)get_size_bar;
streamfile->sf.get_offset = (void*)get_offset_bar;
streamfile->sf.get_name = (void*)get_name_bar;
- streamfile->sf.get_realname = (void*)get_realname_bar;
streamfile->sf.open = (void*)open_bar;
streamfile->sf.close = (void*)close_bar;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bcstm.c b/Frameworks/vgmstream/vgmstream/src/meta/bcstm.c
index 2d8c83659..0b5d89ef4 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/bcstm.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/bcstm.c
@@ -112,22 +112,14 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) {
}
vgmstream->coding_type = coding_type;
- if (channel_count == 1)
- vgmstream->layout_type = layout_none;
- else
- {
- if (ima)
- vgmstream->layout_type = layout_interleave;
- else
- vgmstream->layout_type = layout_interleave_shortblock;
- }
+ vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
vgmstream->meta_type = meta_CSTM;
- if (ima)
+ if (ima) {
vgmstream->interleave_block_size = 0x200;
- else {
+ } else {
vgmstream->interleave_block_size = read_32bitLE(info_offset + 0x34, streamFile);
- vgmstream->interleave_smallblock_size = read_32bitLE(info_offset + 0x44, streamFile);
+ vgmstream->interleave_last_block_size = read_32bitLE(info_offset + 0x44, streamFile);
}
if (vgmstream->coding_type == coding_NGC_DSP) {
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bfstm.c b/Frameworks/vgmstream/vgmstream/src/meta/bfstm.c
index 6e86c22a6..19a2bb902 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/bfstm.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/bfstm.c
@@ -121,22 +121,14 @@ VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) {
}
vgmstream->coding_type = coding_type;
- if (channel_count == 1)
- vgmstream->layout_type = layout_none;
- else
- {
- if (ima)
- vgmstream->layout_type = layout_interleave;
- else
- vgmstream->layout_type = layout_interleave_shortblock;
- }
+ vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
vgmstream->meta_type = meta_FSTM;
if (ima)
vgmstream->interleave_block_size = 0x200;
else {
vgmstream->interleave_block_size = read_32bit(info_offset + 0x34, streamFile);
- vgmstream->interleave_smallblock_size = read_32bit(info_offset + 0x44, streamFile);
+ vgmstream->interleave_last_block_size = read_32bit(info_offset + 0x44, streamFile);
}
if (vgmstream->coding_type == coding_NGC_DSP) {
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bfwav.c b/Frameworks/vgmstream/vgmstream/src/meta/bfwav.c
index acf938599..734fdc0c3 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/bfwav.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/bfwav.c
@@ -1,150 +1,133 @@
#include "meta.h"
-#include "../util.h"
+#include "../coding/coding.h"
+/* FWAV - Nintendo streams */
VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
-
- coding_t coding_type;
- coding_t coding_PCM16;
- int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
- int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
-
- /*int ima = 0;*/
- int nsmbu_flag = 0;
-
- off_t data_offset;
- off_t head_offset;
- int codec_number;
- int channel_count;
- int loop_flag;
-
- off_t start_offset;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile, filename, sizeof(filename));
- if (strcasecmp("bfwav", filename_extension(filename)) && strcasecmp("fwav", filename_extension(filename))) {
- if (strcasecmp("bfwavnsmbu",filename_extension(filename))) goto fail;
- else nsmbu_flag = 1;
- }
- /* check header */
- if ((uint32_t)read_32bitBE(0, streamFile) != 0x46574156) /* "FWAV" */
- goto fail;
-
- if ((uint16_t)read_16bitBE(4, streamFile) == 0xFEFF) { /* endian marker (BE most common) */
- read_32bit = read_32bitBE;
- read_16bit = read_16bitBE;
- coding_PCM16 = coding_PCM16BE;
- } else if ((uint16_t)read_16bitBE(4, streamFile) == 0xFFFE) { /* LE endian marker */
- read_32bit = read_32bitLE;
- read_16bit = read_16bitLE;
- coding_PCM16 = coding_PCM16LE;
- } else {
- goto fail;
- }
-
- /* get head offset, check */
- head_offset = read_32bit(0x18, streamFile);
- data_offset = read_32bit(0x24, streamFile);
-
- if ((uint32_t)read_32bitBE(head_offset, streamFile) != 0x494E464F) /* "INFO" (FWAV)*/
- goto fail;
-
-
- /* check type details */
- codec_number = read_8bit(head_offset + 0x8, streamFile);
- loop_flag = read_8bit(head_offset + 0x9, streamFile);
- channel_count = read_32bit(head_offset + 0x1C, streamFile);
-
- switch (codec_number) {
- case 0:
- coding_type = coding_PCM8;
- break;
- case 1:
- coding_type = coding_PCM16;
- break;
- case 2:
- coding_type = coding_NGC_DSP;
- break;
- default:
- goto fail;
- }
-
- if (channel_count < 1) goto fail;
-
- /* build the VGMSTREAM */
-
- vgmstream = allocate_vgmstream(channel_count, loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = read_32bit(head_offset + 0x14, streamFile);
- if (nsmbu_flag)
- vgmstream->sample_rate = 16000;
- else
- vgmstream->sample_rate = (uint16_t)read_32bit(head_offset + 0xC, streamFile);
- /* channels and loop flag are set by allocate_vgmstream */
-
- vgmstream->loop_start_sample = read_32bit(head_offset + 0x10, streamFile);
- vgmstream->loop_end_sample = vgmstream->num_samples;
-
- vgmstream->coding_type = coding_type;
- if (channel_count == 1)
- vgmstream->layout_type = layout_none;
- else
- vgmstream->layout_type = layout_interleave;
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ off_t info_offset, data_offset;
+ int channel_count, loop_flag, codec;
+ int big_endian;
+ size_t interleave = 0;
+ int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
+ int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
+ int nsmbu_flag = 0;
- vgmstream->meta_type = meta_FWAV;
+ /* checks */
+ /* .bfwavnsmbu: fake extension to detect New Super Mario Bros U files with weird sample rate */
+ if (!check_extensions(streamFile, "bfwav,fwav,bfwavnsmbu"))
+ goto fail;
+ nsmbu_flag = check_extensions(streamFile, "bfwavnsmbu");
- vgmstream->interleave_block_size = read_32bit(read_32bit(0x6c, streamFile) + 0x60, streamFile) - 0x18;
-
+ /* FWAV header */
+ if (read_32bitBE(0x00, streamFile) != 0x46574156) /* "FWAV" */
+ goto fail;
+ /* 0x06(2): header size (0x40), 0x08: version (0x00010200), 0x0c: file size 0x10(2): sections (2) */
- start_offset = data_offset + 0x20;
+ if ((uint16_t)read_16bitBE(0x04, streamFile) == 0xFEFF) { /* BE BOM check */
+ read_32bit = read_32bitBE;
+ read_16bit = read_16bitBE;
+ big_endian = 1;
+ } else if ((uint16_t)read_16bitBE(0x04, streamFile) == 0xFFFE) { /* LE BOM check */
+ read_32bit = read_32bitLE;
+ read_16bit = read_16bitLE;
+ big_endian = 0;
+ } else {
+ goto fail;
+ }
- if (vgmstream->coding_type == coding_NGC_DSP) {
- int i, j;
+ info_offset = read_32bit(0x18, streamFile); /* 0x14(2): info mark (0x7000), 0x1c: info size */
+ data_offset = read_32bit(0x24, streamFile); /* 0x20(2): data mark (0x7001), 0x28: data size */
- for (j = 0; jchannels; j++) {
- for (i = 0; i<16; i++) {
- off_t coeffheader = head_offset + 0x1C + read_32bit(head_offset + 0x24 + (j*8), streamFile);
- off_t coef_offset;
- if ((uint32_t)read_16bit(coeffheader, streamFile) != 0x1F00) goto fail;
+ /* INFO section */
+ if (read_32bitBE(info_offset, streamFile) != 0x494E464F) /* "INFO" */
+ goto fail;
+ codec = read_8bit(info_offset + 0x08, streamFile);
+ loop_flag = read_8bit(info_offset + 0x09, streamFile);
+ channel_count = read_32bit(info_offset + 0x1C, streamFile);
- coef_offset = read_32bit(coeffheader + 0xC, streamFile) + coeffheader;
- vgmstream->ch[j].adpcm_coef[i] = read_16bit(coef_offset + i * 2, streamFile);
- }
- }
- }
+ /* parse channel table */
+ {
+ off_t channel1_info, data_start;
+ int i;
+
+ channel1_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*0+0x04, streamFile);
+ data_start = read_32bit(channel1_info+0x04, streamFile); /* within "DATA" after 0x08 */
+
+ /* channels use absolute offsets but should be ok as interleave */
+ interleave = 0;
+ if (channel_count > 1) {
+ off_t channel2_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*1+0x04, streamFile);
+ interleave = read_32bit(channel2_info+0x04, streamFile) - data_start;
+ }
+
+ start_offset = data_offset + 0x08 + data_start;
+
+ /* validate all channels just in case of multichannel with non-constant interleave */
+ for (i = 0; i < channel_count; i++) {
+ /* channel table, 0x00: flag (0x7100), 0x04: channel info offset */
+ off_t channel_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*i+0x04, streamFile);
+ /* channel info, 0x00(2): flag (0x1f00), 0x04: offset, 0x08(2): ADPCM flag (0x0300), 0x0c: ADPCM offset */
+ if ((uint16_t)read_16bit(channel_info+0x00, streamFile) != 0x1F00)
+ goto fail;
+ if (read_32bit(channel_info+0x04, streamFile) != data_start + interleave*i)
+ goto fail;
+ }
+ }
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count, loop_flag);
+ if (!vgmstream) goto fail;
- /* open the file for reading by each channel */
- {
- int i;
- for (i = 0; ilayout_type == layout_interleave_shortblock)
- vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
- vgmstream->interleave_block_size);
- else if (vgmstream->layout_type == layout_interleave)
- vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
- STREAMFILE_DEFAULT_BUFFER_SIZE);
- else
- vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
- 0x1000);
+ vgmstream->sample_rate = read_32bit(info_offset + 0x0C, streamFile);
+ if (nsmbu_flag)
+ vgmstream->sample_rate = 16000;
- if (!vgmstream->ch[i].streamfile) goto fail;
+ vgmstream->num_samples = read_32bit(info_offset + 0x14, streamFile);
+ vgmstream->loop_start_sample = read_32bit(info_offset + 0x10, streamFile);
+ vgmstream->loop_end_sample = vgmstream->num_samples;
- vgmstream->ch[i].channel_start_offset =
- vgmstream->ch[i].offset =
- start_offset + i*vgmstream->interleave_block_size;
- }
- }
+ vgmstream->meta_type = meta_FWAV;
+ vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
+ vgmstream->interleave_block_size = interleave;
- return vgmstream;
+ switch (codec) {
+ case 0x00:
+ vgmstream->coding_type = coding_PCM8;
+ break;
+
+ case 0x01:
+ vgmstream->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
+ break;
+
+ case 0x02:
+ vgmstream->coding_type = coding_NGC_DSP;
+ {
+ int i, c;
+ off_t coef_header, coef_offset;
+
+ for (i = 0; i < vgmstream->channels; i++) {
+ for (c = 0; c < 16; c++) {
+ coef_header = info_offset + 0x1C + read_32bit(info_offset + 0x24 + (i*0x08), streamFile);
+ coef_offset = read_32bit(coef_header + 0x0c, streamFile) + coef_header;
+ vgmstream->ch[i].adpcm_coef[c] = read_16bit(coef_offset + c*2, streamFile);
+ }
+ }
+ }
+ break;
+
+ default: /* 0x03: IMA? */
+ goto fail;
+ }
+
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
+ return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
- return NULL;
+ close_vgmstream(vgmstream);
+ return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bgw.c b/Frameworks/vgmstream/vgmstream/src/meta/bgw.c
index 0be6ebabc..601d7cbdd 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/bgw.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/bgw.c
@@ -244,7 +244,7 @@ static STREAMFILE* setup_bgw_atrac3_streamfile(STREAMFILE *streamFile, off_t sub
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
- new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, bgw_decryption_read);
+ new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, bgw_decryption_read,NULL);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/brstm.c b/Frameworks/vgmstream/vgmstream/src/meta/brstm.c
index 249999977..960c21b37 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/brstm.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/brstm.c
@@ -91,10 +91,7 @@ VGMSTREAM * init_vgmstream_brstm(STREAMFILE *streamFile) {
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->coding_type = coding_type;
- if (channel_count==1)
- vgmstream->layout_type = layout_none;
- else
- vgmstream->layout_type = layout_interleave_shortblock;
+ vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
vgmstream->meta_type = meta_RSTM;
if (atlus_shrunken_head)
vgmstream->meta_type = meta_RSTM_shrunken;
@@ -105,7 +102,7 @@ VGMSTREAM * init_vgmstream_brstm(STREAMFILE *streamFile) {
}
vgmstream->interleave_block_size = read_32bitBE(head_offset+0x38,streamFile);
- vgmstream->interleave_smallblock_size = read_32bitBE(head_offset+0x48,streamFile);
+ vgmstream->interleave_last_block_size = read_32bitBE(head_offset+0x48,streamFile);
if (vgmstream->coding_type == coding_NGC_DSP) {
off_t coef_offset;
@@ -139,12 +136,7 @@ VGMSTREAM * init_vgmstream_brstm(STREAMFILE *streamFile) {
{
int i;
for (i=0;ilayout_type==layout_interleave_shortblock)
- vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,
- vgmstream->interleave_block_size);
- else
- vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,
- 0x1000);
+ vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[i].streamfile) goto fail;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/caf.c b/Frameworks/vgmstream/vgmstream/src/meta/caf.c
new file mode 100644
index 000000000..8180fe8ea
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/caf.c
@@ -0,0 +1,65 @@
+#include "meta.h"
+#include "../layout/layout.h"
+#include "../util.h"
+
+/* CAF - from tri-Crescendo games [Baten Kaitos 1/2 (GC), Fragile (Wii)] */
+VGMSTREAM * init_vgmstream_caf(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset, offset;
+ size_t file_size;
+ int channel_count, loop_flag;
+ int32_t num_samples = 0;
+ uint32_t loop_start = -1;
+
+
+ /* checks */
+ /* .caf: header id, .cfn: fake extension? , "" is accepted as files don't have extensions in the disc */
+ if (!check_extensions(streamFile,"caf,cfn,"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x43414620) /* "CAF " */
+ goto fail;
+
+ /* get total samples */
+ offset = 0;
+ file_size = get_streamfile_size(streamFile);
+ while (offset < file_size) {
+ off_t next_block = read_32bitBE(offset+0x04,streamFile);
+ num_samples += read_32bitBE(offset+0x14,streamFile)/8*14;
+
+ if(read_32bitBE(offset+0x20,streamFile)==read_32bitBE(offset+0x08,streamFile)) {
+ loop_start = num_samples - read_32bitBE(offset+0x14,streamFile)/8*14;
+ }
+ offset += next_block;
+ }
+
+ start_offset = 0x00;
+ channel_count = 2; /* always stereo */
+ loop_flag = (loop_start!=-1);
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = 32000;
+ vgmstream->num_samples = num_samples;
+ if (loop_flag) {
+ vgmstream->loop_start_sample = loop_start;
+ vgmstream->loop_end_sample = num_samples;
+ }
+
+ vgmstream->meta_type = meta_CAF;
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = layout_blocked_caf;
+
+ if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
+ goto fail;
+
+ block_update_caf(start_offset,vgmstream);
+
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/dc_dcsw_dcs.c b/Frameworks/vgmstream/vgmstream/src/meta/dc_dcsw_dcs.c
index 23105fd07..d1710560a 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/dc_dcsw_dcs.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/dc_dcsw_dcs.c
@@ -92,7 +92,7 @@ VGMSTREAM * init_vgmstream_dc_dcsw_dcs(STREAMFILE *streamFile) {
vgmstream->interleave_block_size = 0x4000;
}
- vgmstream->coding_type = coding_AICA;
+ vgmstream->coding_type = coding_AICA_int;
vgmstream->meta_type = meta_DC_DCSW_DCS;
/* open the file for reading by each channel */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/dc_idvi.c b/Frameworks/vgmstream/vgmstream/src/meta/dc_idvi.c
index 0200f8cd3..4498204a8 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/dc_idvi.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/dc_idvi.c
@@ -5,9 +5,12 @@
VGMSTREAM * init_vgmstream_dc_idvi(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
+ size_t data_size;
int loop_flag, channel_count;
- /* check extension (.dvi: original, .idvi: renamed to header id) */
+
+ /* checks*/
+ /* .dvi: original, .idvi: renamed to header id */
if ( !check_extensions(streamFile,"dvi,idvi") )
goto fail;
@@ -18,28 +21,24 @@ VGMSTREAM * init_vgmstream_dc_idvi(STREAMFILE *streamFile) {
loop_flag = (read_32bitLE(0x0C,streamFile) != 0);
channel_count = read_32bitLE(0x04,streamFile); /* always 2? */
start_offset = 0x800;
+ data_size = get_streamfile_size(streamFile) - start_offset;
- /* build the VGMSTREAM */
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- vgmstream->channels = channel_count;
+ vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
- vgmstream->num_samples = ima_bytes_to_samples(get_streamfile_size(streamFile) - start_offset, channel_count);
+ vgmstream->num_samples = ima_bytes_to_samples(data_size, channel_count);
vgmstream->loop_start_sample = read_32bitLE(0x0C,streamFile);
- vgmstream->loop_end_sample = ima_bytes_to_samples(get_streamfile_size(streamFile) - start_offset, channel_count);
+ vgmstream->loop_end_sample = vgmstream->num_samples;
- vgmstream->coding_type = coding_DVI_IMA_int;
vgmstream->meta_type = meta_DC_IDVI;
-
- /* Calculating the short block... */
- if (channel_count > 1) {
- vgmstream->interleave_block_size = 0x400;
- vgmstream->interleave_smallblock_size = ((get_streamfile_size(streamFile)-start_offset)%(vgmstream->channels*vgmstream->interleave_block_size))/vgmstream->channels;
- vgmstream->layout_type = layout_interleave_shortblock;
- } else {
- vgmstream->layout_type = layout_none;
- }
+ vgmstream->coding_type = coding_DVI_IMA_int;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x400;
+ if (vgmstream->interleave_block_size)
+ vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/dc_str.c b/Frameworks/vgmstream/vgmstream/src/meta/dc_str.c
index 9bac3c362..d9be078db 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/dc_str.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/dc_str.c
@@ -39,7 +39,7 @@ VGMSTREAM * init_vgmstream_dc_str(STREAMFILE *streamFile) {
/* fill in the vital statistics */
switch (samples) {
case 4:
- vgmstream->coding_type = coding_AICA;
+ vgmstream->coding_type = coding_AICA_int;
vgmstream->num_samples = read_32bitLE(0x14,streamFile);
if (loop_flag) {
vgmstream->loop_start_sample = 0;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/dec.c b/Frameworks/vgmstream/vgmstream/src/meta/dec.c
index 0d562b7a4..43a3fe18e 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/dec.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/dec.c
@@ -103,23 +103,23 @@ static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *
/* try one of the many loop files */
- if ((streamText = open_stream_name(streamFile,"bgm.tbl")) != NULL) {
+ if ((streamText = open_streamfile_by_filename(streamFile,"bgm.tbl")) != NULL) {
type = XANADU_NEXT;
}
- else if ((streamText = open_stream_name(streamFile,"bgm.scr")) != NULL) {
+ else if ((streamText = open_streamfile_by_filename(streamFile,"bgm.scr")) != NULL) {
type = ZWEI;
}
- else if ((streamText = open_stream_name(streamFile,"loop.txt")) != NULL) { /* actual name in Shift JIS, 0x838B815B8376 */
+ else if ((streamText = open_streamfile_by_filename(streamFile,"loop.txt")) != NULL) { /* actual name in Shift JIS, 0x838B815B8376 */
type = DINOSAUR_RESURRECTION;
}
- else if ((streamText = open_stream_name(streamFile,"map.itm")) != NULL) {
+ else if ((streamText = open_streamfile_by_filename(streamFile,"map.itm")) != NULL) {
type = GURUMIN;
}
else {
goto end;
}
- get_streamfile_name(streamFile,filename,TXT_LINE_MAX);
+ get_streamfile_filename(streamFile,filename,TXT_LINE_MAX);
/* read line by line */
while (txt_offset < get_streamfile_size(streamText)) {
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/dsp_bdsp.c b/Frameworks/vgmstream/vgmstream/src/meta/dsp_bdsp.c
index d71b7141b..cd39bf622 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/dsp_bdsp.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/dsp_bdsp.c
@@ -35,7 +35,7 @@ VGMSTREAM * init_vgmstream_dsp_bdsp(STREAMFILE *streamFile) {
#endif
- vgmstream->layout_type = layout_dsp_bdsp_blocked;
+ vgmstream->layout_type = layout_blocked_bdsp;
vgmstream->interleave_block_size = 0x8;
vgmstream->meta_type = meta_DSP_BDSP;
@@ -64,17 +64,17 @@ VGMSTREAM * init_vgmstream_dsp_bdsp(STREAMFILE *streamFile) {
/* Calc num_samples */
start_offset = 0x0;
- dsp_bdsp_block_update(start_offset,vgmstream);
+ block_update_bdsp(start_offset,vgmstream);
vgmstream->num_samples=0;
do
{
vgmstream->num_samples += vgmstream->current_block_size*14/8;
- dsp_bdsp_block_update(vgmstream->next_block_offset,vgmstream);
+ block_update_bdsp(vgmstream->next_block_offset,vgmstream);
}
while (vgmstream->next_block_offset get_streamfile_size(streamFile))
+ max_offset = get_streamfile_size(streamFile);
+
+ /* find .sps start block */
+ while (sps_offset < max_offset) {
+ if ((read_32bitBE(sps_offset, streamFile) & 0xFFFFFF00) == 0x48000000) {
+ header_offset = sps_offset + 0x04;
+ start_offset = sps_offset + (read_32bitBE(sps_offset, streamFile) & 0x00FFFFFF);
+ break;
+ }
+ sps_offset += 0x04;
+ }
+
+ if (!start_offset)
+ goto fail; /* not found */
+
+ vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, header_offset, start_offset, meta_EA_SPS);
+ if (!vgmstream) goto fail;
+
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
/* EA newest header from RwAudioCore (RenderWare?) / EAAudioCore library (still generated by sx.exe).
* Audio "assets" come in separate RAM headers (.SNR/SPH) and raw blocked streams (.SNS/SPS),
@@ -114,28 +157,30 @@ fail:
* Some .SNR include stream data, while .SPS have headers so .SPH is optional. */
static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type) {
VGMSTREAM * vgmstream = NULL;
+ STREAMFILE* temp_streamFile = NULL;
int channel_count, loop_flag = 0, version, codec, channel_config, sample_rate, flags;
uint32_t num_samples, loop_start = 0, loop_end = 0;
/* EA SNR/SPH header */
- version = (read_8bit(header_offset + 0x00,streamHead) >> 4) & 0xf;
- codec = (read_8bit(header_offset + 0x00,streamHead) >> 0) & 0xf;
- channel_config = read_8bit(header_offset + 0x01,streamHead);
- sample_rate = (uint16_t)read_16bitBE(header_offset + 0x02,streamHead);
- flags = (uint8_t)read_8bit(header_offset + 0x04,streamHead); /* upper nibble only? */
- num_samples = (uint32_t)read_32bitBE(header_offset + 0x04,streamHead) & 0x00FFFFFF;
+ version = (read_8bit(header_offset + 0x00,streamHead) >> 4) & 0x0F;
+ codec = (read_8bit(header_offset + 0x00,streamHead) >> 0) & 0x0F;
+ channel_config = read_8bit(header_offset + 0x01,streamHead) & 0xFE;
+ sample_rate = read_32bitBE(header_offset + 0x00,streamHead) & 0x1FFFF; /* some Dead Space 2 (PC) uses 96000 */
+ flags = (uint8_t)read_8bit(header_offset + 0x04,streamHead) & 0xFE; //todo upper nibble only? (the first bit is part of size)
+ num_samples = (uint32_t)read_32bitBE(header_offset + 0x04,streamHead) & 0x01FFFFFF;
/* rest is optional, depends on flags header used (ex. SNU and SPS may have bigger headers):
* &0x20: 1 int (usually 0x00), &0x00/40: nothing, &0x60: 2 ints (usually 0x00 and 0x14) */
- /* V0: SNR+SNS, V1: SPR+SPS (not apparent differences) */
+ /* V0: SNR+SNS, V1: SPR+SPS (not apparent differences, other than the block flags used) */
if (version != 0 && version != 1) {
VGM_LOG("EA SNS/SPS: unknown version\n");
goto fail;
}
- /* 0x40: stream asset, 0x20: full loop, 0x00: default/RAM asset, 0x01: loop? */
+ /* 0x40: stream asset, 0x20: full loop, 0x00: default/RAM asset */
if (flags != 0x60 && flags != 0x40 && flags != 0x20 && flags != 0x00) {
VGM_LOG("EA SNS/SPS: unknown flag 0x%02x\n", flags);
+ goto fail;
}
/* seen in sfx and Dead Space ambient tracks */
@@ -216,14 +261,20 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
case 0x06: /* "L32P": EALayer3 v2 "PCM" [Battlefield 1943 (PS3)] */
case 0x07: { /* "L32S": EALayer3 v2 "Spike" [Dante's Inferno (PS3)] */
mpeg_custom_config cfg = {0};
- off_t mpeg_start_offset = start_offset + 0x08;
mpeg_custom_t type = (codec == 0x05 ? MPEG_EAL31b : (codec == 0x06) ? MPEG_EAL32P : MPEG_EAL32S);
- /* layout is still blocks, but should work fine with the custom mpeg decoder */
- vgmstream->codec_data = init_mpeg_custom(streamData, mpeg_start_offset, &vgmstream->coding_type, vgmstream->channels, type, &cfg);
- if (!vgmstream->codec_data) goto fail;
+ /* remove blocks on reads for some edge cases in L32P and to properly apply discard modes
+ * (otherwise, and removing discards, it'd work with layout_blocked_ea_sns) */
+ temp_streamFile = setup_eaac_streamfile(streamData, version, codec, start_offset, 0);
+ if (!temp_streamFile) goto fail;
+
+ start_offset = 0x00; /* must point to the custom streamfile's beginning */
+
+ /* layout is still blocks, but should work fine with the custom mpeg decoder */
+ vgmstream->codec_data = init_mpeg_custom(temp_streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, type, &cfg);
+ if (!vgmstream->codec_data) goto fail;
+ vgmstream->layout_type = layout_none;
- vgmstream->layout_type = layout_blocked_ea_sns;
break;
}
#endif
@@ -234,22 +285,28 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
/* DSP coefs are read in the blocks */
break;
-#if 0 //todo buffered ATRAC9
#ifdef VGM_USE_ATRAC9
case 0x0a: { /* EATrax */
atrac9_config cfg = {0};
+ size_t total_size;
cfg.channels = vgmstream->channels;
cfg.config_data = read_32bitBE(header_offset + 0x08,streamHead);
- /* 0x0c: data size without blocks?, 0x10: frame size? (same as config data?) */
+ /* 0x10: frame size? (same as config data?) */
+ total_size = read_32bitLE(header_offset + 0x0c,streamHead); /* actual data size without blocks, LE b/c why make sense */
vgmstream->codec_data = init_atrac9(&cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_ATRAC9;
- vgmstream->layout_type = layout_blocked_ea_sns;
+ vgmstream->layout_type = layout_none;
+
+ /* EATrax is "buffered" ATRAC9, uses custom IO since it's kind of complex to add to the decoder */
+ temp_streamFile = setup_eaac_streamfile(streamData, version, codec, start_offset, total_size);
+ if (!temp_streamFile) goto fail;
+
+ start_offset = 0x00; /* must point to the custom streamfile's beginning */
break;
}
-#endif
#endif
case 0x00: /* "NONE" (internal 'codec not set' flag) */
@@ -266,16 +323,17 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
}
- /* open the file for reading by each channel */
- if (!vgmstream_open_stream(vgmstream,streamData,start_offset))
+ if (!vgmstream_open_stream(vgmstream,temp_streamFile ? temp_streamFile : streamData,start_offset))
goto fail;
if (vgmstream->layout_type == layout_blocked_ea_sns)
block_update_ea_sns(start_offset, vgmstream);
+ close_streamfile(temp_streamFile);
return vgmstream;
fail:
+ close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac_streamfile.h b/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac_streamfile.h
new file mode 100644
index 000000000..4ecb24bfb
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac_streamfile.h
@@ -0,0 +1,218 @@
+#ifndef _EA_EAAC_STREAMFILE_H_
+#define _EA_EAAC_STREAMFILE_H_
+#include "../streamfile.h"
+
+
+typedef struct {
+ /* state */
+ off_t logical_offset; /* offset that corresponds to physical_offset */
+ off_t physical_offset; /* actual file offset */
+
+ /* config */
+ int version;
+ int codec;
+ off_t start_offset;
+ size_t total_size; /* size of the resulting substream */
+} eaac_io_data;
+
+
+/* Reads skipping EA's block headers, so the resulting data is smaller or larger than physical data.
+ * physical/logical_offset should always be at the start of a block and only advance when a block is fully done */
+static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, eaac_io_data* data) {
+ size_t total_read = 0;
+
+ /* ignore bad reads */
+ if (offset < 0 || offset > data->total_size) {
+ return total_read;
+ }
+
+ /* previous offset: re-start as we can't map logical<>physical offsets
+ * (kinda slow as it trashes buffers, but shouldn't happen often) */
+ if (offset < data->logical_offset) {
+ data->physical_offset = data->start_offset;
+ data->logical_offset = 0x00;
+ }
+
+ /* read doing one EA block at a time */
+ while (length > 0) {
+ size_t to_read, bytes_read;
+ off_t intrablock_offset, intradata_offset;
+ uint32_t block_flag, block_size, data_size, skip_size;
+
+ block_flag = read_8bit(data->physical_offset+0x00,streamfile);
+ block_size = read_32bitBE(data->physical_offset+0x00,streamfile) & 0x00FFFFFF;
+
+ if (data->version == 1 && block_flag == 0x48) {
+ data->physical_offset += block_size;
+ continue; /* skip header block */
+ }
+ if (data->version == 1 && block_flag == 0x45)
+ return total_read; /* stop on last block (always empty) */
+
+ switch(data->codec) {
+#if 0
+ case 0x03:
+ data_size = block_size - ???;
+ extra_size = (data_size % 0x800); /* deflated padding */
+
+
+ skip_size = 0x08 + 0x04*data->stream_count;
+ break;
+#endif
+
+ case 0x05: /* EALayer3 v1 */
+ case 0x06: /* EALayer3 v2 "PCM" */
+ case 0x07: /* EALayer3 v2 "Spike" */
+ data_size = block_size - 0x08;
+ skip_size = 0x08;
+ break;
+
+ case 0x0a: /* EATrax */
+ data_size = read_32bitBE(data->physical_offset+0x04,streamfile); /* should be block_size - 0x08 */
+ skip_size = 0x08;
+ break;
+
+ default:
+ return total_read;
+ }
+
+ /* requested offset is outside current block, try next */
+ if (offset >= data->logical_offset + data_size) {
+ data->physical_offset += block_size;
+ data->logical_offset += data_size;
+ continue;
+ }
+
+ /* reads could fall in the middle of the block */
+ intradata_offset = offset - data->logical_offset;
+ intrablock_offset = skip_size + intradata_offset;
+
+ /* clamp reads up to this block's end */
+ to_read = (data_size - intradata_offset);
+ if (to_read > length)
+ to_read = length;
+ if (to_read == 0)
+ return total_read; /* should never happen... */
+
+ /* finally read and move buffer/offsets */
+ bytes_read = read_streamfile(dest, data->physical_offset + intrablock_offset, to_read, streamfile);
+ total_read += bytes_read;
+ if (bytes_read != to_read)
+ return total_read; /* couldn't read fully */
+
+ dest += bytes_read;
+ offset += bytes_read;
+ length -= bytes_read;
+
+ /* block fully read, go next */
+ if (intradata_offset + bytes_read == data_size) {
+ data->physical_offset += block_size;
+ data->logical_offset += data_size;
+ }
+
+ if (data->version == 0 && block_flag == 0x80)
+ break; /* stop on last block */
+ }
+
+ return total_read;
+}
+
+static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
+ off_t physical_offset, max_physical_offset;
+ size_t total_size = 0;
+
+ if (data->total_size)
+ return data->total_size;
+
+ physical_offset = data->start_offset;
+ max_physical_offset = get_streamfile_size(streamfile) - data->start_offset;
+
+ /* get size of the underlying, non-blocked data */
+ while (physical_offset < max_physical_offset) {
+ uint32_t block_flag, block_size, data_size;
+
+ block_flag = read_8bit(physical_offset+0x00,streamfile);
+ block_size = read_32bitBE(physical_offset+0x00,streamfile) & 0x00FFFFFF;
+
+ if (data->version == 0 && block_flag != 0x00 && block_flag != 0x80)
+ break; /* data/end block expected */
+
+ if (data->version == 1 && block_flag == 0x48) {
+ physical_offset += block_size;
+ continue; /* skip header block */
+ }
+ if (data->version == 1 && block_flag == 0x45)
+ break; /* stop on last block (always empty) */
+ if (data->version == 1 && block_flag != 0x44)
+ break; /* data block expected */
+
+ switch(data->codec) {
+#if 0
+ case 0x03:
+ data_size = block_size - ???;
+ data_size += (data_size % 0x800); /* deflated padding */
+ break;
+#endif
+ case 0x05: /* EALayer3 v1 */
+ case 0x06: /* EALayer3 v2 "PCM" */
+ case 0x07: /* EALayer3 v2 "Spike" */
+ data_size = block_size - 0x08;
+ break;
+
+ case 0x0a: /* EATrax */
+ data_size = read_32bitBE(physical_offset+0x04,streamfile); /* should be block_size - 0x08 */
+ break;
+
+ default:
+ return 0;
+ }
+
+ physical_offset += block_size;
+ total_size += data_size;
+
+ if (data->version == 0 && block_flag == 0x80)
+ break; /* stop on last block */
+ }
+
+ data->total_size = total_size;
+ return data->total_size;
+}
+
+
+/* Prepares custom IO for some blocked EAAudioCore formats, that need clean reads without block headers:
+ * - EA-XMA: deflated XMA in multistreams (separate 2ch frames)
+ * - EALayer3: MPEG granule 1 can go in the next block (in V2"P" mainly, others could use layout blocked_sns)
+ * - EATrax: ATRAC9 frames can be split between blooks
+ */
+static STREAMFILE* setup_eaac_streamfile(STREAMFILE *streamFile, int version, int codec, off_t start_offset, size_t total_size) {
+ STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
+ eaac_io_data io_data = {0};
+ size_t io_data_size = sizeof(eaac_io_data);
+
+ io_data.version = version;
+ io_data.codec = codec;
+ io_data.start_offset = start_offset;
+ io_data.total_size = total_size; /* optional */
+ io_data.physical_offset = start_offset;
+
+ /* setup subfile */
+ new_streamFile = open_wrap_streamfile(streamFile);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, eaac_io_read,eaac_io_size);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_buffer_streamfile(new_streamFile,0);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ return temp_streamFile;
+
+fail:
+ close_streamfile(temp_streamFile);
+ return NULL;
+}
+
+#endif /* _EA_EAAC_STREAMFILE_H_ */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c
index c6986f66d..a2b784082 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c
@@ -82,21 +82,22 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
off_t start_offset, header_offset;
size_t header_size;
- ea_header ea;
+ ea_header ea = {0};
/* check extension; exts don't seem enforced by EA's tools, but usually:
* STR/ASF/MUS ~early, EAM ~mid, SNG/AUD ~late, rest uncommon/one game (ex. STRM: MySims Kingdom Wii) */
- if (!check_extensions(streamFile,"str,asf,mus,eam,sng,aud,sx,strm,xa,xsf,exa,stm,ast"))
+ if (!check_extensions(streamFile,"str,asf,mus,eam,sng,aud,sx,strm,xa,xsf,exa,stm,ast,trj,trm"))
goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x5343486C && /* "SCHl" */
- read_32bitBE(0x00,streamFile) != 0x5348454E) /* "SHEN" */
+ read_32bitBE(0x00,streamFile) != 0x5348454E && /* "SHEN" */
+ read_32bitBE(0x00,streamFile) != 0x53484652) /* "SHFR" */
goto fail;
/* stream is divided into blocks/chunks: SCHl=audio header, SCCl=count of SCDl, SCDl=data xN, SCLl=loop end, SCEl=end.
- * Video uses various blocks (MVhd/MV0K/etc) and sometimes alt audio blocks (SHEN/SDEN/SEEN).
+ * Video uses various blocks (MVhd/MV0K/etc) and sometimes alt audio blocks (SHxx/SCxx/SDxx/SExx where XX=language, EN/FR).
* The number/size is affected by: block rate setting, sample rate, channels, CPU location (SPU/main/DSP/others), etc */
header_size = read_32bitLE(0x04,streamFile);
@@ -120,7 +121,7 @@ fail:
VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE *streamFile) {
off_t start_offset, header_offset, offset, table_offset;
size_t header_size;
- ea_header ea;
+ ea_header ea = {0};
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
int i, bnk_version;
@@ -284,7 +285,11 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
break;
case EA_CODEC2_S16LE: /* PCM16LE */
- vgmstream->coding_type = coding_PCM16LE;
+ if (ea->version > 0) {
+ vgmstream->coding_type = coding_PCM16LE;
+ } else { /* Need for Speed III: Hot Pursuit (PC) */
+ vgmstream->coding_type = coding_PCM16_int;
+ }
break;
case EA_CODEC2_VAG: /* PS-ADPCM */
@@ -449,7 +454,6 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be
uint32_t platform_id;
int is_header_end = 0;
- memset(ea,0,sizeof(ea_header));
/* null defaults as 0 can be valid */
ea->version = EA_VERSION_NONE;
@@ -467,7 +471,7 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be
offset += 4 + 4; /* GSTRs have an extra field (config?): ex. 0x01000000, 0x010000D8 BE */
}
else if ((platform_id & 0xFFFF0000) == 0x50540000) { /* "PT" = PlaTform */
- ea->platform = (uint8_t)read_16bitLE(offset + 2,streamFile);
+ ea->platform = (uint16_t)read_16bitLE(offset + 2,streamFile);
offset += 4;
}
else {
@@ -769,7 +773,7 @@ static int get_ea_stream_total_samples(STREAMFILE* streamFile, off_t start_offse
block_samples = 0;
- if (id == 0x5343446C || id == 0x5344454E) { /* "SCDl" "SDEN" audio data */
+ if (id == 0x5343446C || id == 0x5344454E || id == 0x53444652) { /* "SCDl" "SDEN" "SDFR" audio data */
switch (ea->codec2) {
case EA_CODEC2_VAG:
block_samples = ps_bytes_to_samples(block_size-0x10, ea->channels);
@@ -785,7 +789,7 @@ static int get_ea_stream_total_samples(STREAMFILE* streamFile, off_t start_offse
block_size = 0x04;
}
- if (id == 0x5343486C || id == 0x5348454E) { /* "SCHl" "SHEN" end block */
+ if (id == 0x5343486C || id == 0x5348454E || id == 0x53484652) { /* "SCHl" "SHEN" "SHFR" end block */
new_schl = 1;
}
}
@@ -800,8 +804,8 @@ static int get_ea_stream_total_samples(STREAMFILE* streamFile, off_t start_offse
num_samples += block_samples;
block_offset += block_size;
- /* "SCEl" are aligned to 0x80 usually, but causes problems if not 32b-aligned (ex. Need for Speed 2 PC) */
- if ((id == 0x5343456C || id == 0x5345454E) && block_offset % 0x04) {
+ /* "SCEl" "SEEN" "SEFR" are aligned to 0x80 usually, but causes problems if not 32b-aligned (ex. Need for Speed 2 PC) */
+ if ((id == 0x5343456C || id == 0x5345454E || id == 0x53454652) && block_offset % 0x04) {
VGM_LOG_ONCE("EA SCHl: mis-aligned end offset found\n");
block_offset += 0x04 - (block_offset % 0x04);
}
@@ -832,10 +836,10 @@ static off_t get_ea_stream_mpeg_start_offset(STREAMFILE* streamFile, off_t start
if (block_size > 0x00F00000) /* size is always LE, except in early SAT/MAC */
block_size = read_32bitBE(block_offset+0x04,streamFile);
- if (id == 0x5343446C) { /* "SCDl" data block found */
+ if (id == 0x5343446C || id == 0x5344454E || id == 0x53444652) { /* "SCDl/SDEN/SDFR" data block found */
off_t offset = read_32bit(block_offset+0x0c,streamFile); /* first value seems ok, second is something else in EALayer3 */
return block_offset + 0x0c + ea->channels*0x04 + offset;
- } else if (id == 0x5343436C) { /* "SCCl" data count found */
+ } else if (id == 0x5343436C || id == 0x5343454E || id == 0x53434652) { /* "SCCl/SCEN/SCFR" data count found */
block_offset += block_size; /* size includes header */
continue;
} else {
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_swvr.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_swvr.c
index 8c9969470..fcdd7aa7a 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ea_swvr.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_swvr.c
@@ -3,68 +3,151 @@
#include "../coding/coding.h"
-/* SWVR - from EA games [Future Cop L.A.P.D. (PS/PC), Freekstyle (PS2/GC), EA Sports Supercross (PS)] */
+/* SWVR - from EA games, demuxed from .av/trk/mis/etc [Future Cop L.A.P.D. (PS/PC), Freekstyle (PS2/GC), EA Sports Supercross (PS)] */
VGMSTREAM * init_vgmstream_ea_swvr(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
- int loop_flag = 0, channel_count;
- int big_endian;
+ int loop_flag = 0, channel_count, sample_rate, big_endian;
+ coding_t coding;
+ uint32_t block_id;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
+ int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
+ int total_subsongs, target_subsong = streamFile->stream_index;
- /* check extension */
- if (!check_extensions(streamFile,"str"))
+ /* checks */
+ /* .stream: common (found inside files), .str: shortened, probably unnecessary */
+ if (!check_extensions(streamFile,"stream,str"))
goto fail;
- /* check header */
- if (read_32bitBE(0x00,streamFile) == 0x53575652) { /* "SWVR" (GC) */
- big_endian = 1;
- read_32bit = read_32bitBE;
- }
- else if (read_32bitBE(0x00,streamFile) == 0x52565753) { /* "RVWS" (PS/PS2) */
+ /* blocks ids are in machine endianness */
+ if (read_32bitBE(0x00,streamFile) == 0x52565753) { /* "RVWS" (PS1/PS2/PC) */
big_endian = 0;
read_32bit = read_32bitLE;
+ read_16bit = read_16bitLE;
+ start_offset = read_32bit(0x04, streamFile);
+ }
+ else if (read_32bitBE(0x00,streamFile) == 0x53575652) { /* "SWVR" (GC) */
+ big_endian = 1;
+ read_32bit = read_32bitBE;
+ read_16bit = read_16bitBE;
+ start_offset = read_32bit(0x04, streamFile);
+ }
+ else if (read_32bitBE(0x00,streamFile) == 0x4D474156) { /* "MGAV", Freekstyle (PS2) raw movies */
+ big_endian = 0;
+ read_32bit = read_32bitLE;
+ read_16bit = read_16bitLE;
+ start_offset = 0x00;
+ }
+ else if (read_32bitBE(0x00,streamFile) == 0x4453504D) { /* "DSPM", Freekstyle (GC) raw movies */
+ big_endian = 1;
+ read_32bit = read_32bitBE;
+ read_16bit = read_16bitBE;
+ start_offset = 0x00;
}
else {
goto fail;
}
+ start_offset = read_32bit(0x04, streamFile);
+ if (read_32bit(start_offset+0x00, streamFile) == 0x50414444) /* "PADD" (Freekstyle) */
+ start_offset += read_32bit(start_offset+0x04, streamFile);
+ else if (read_32bit(start_offset+0x10, streamFile) == 0x53484452) /* "SHDR" (Future Cop PC) */
+ start_offset += read_32bit(start_offset+0x04, streamFile);
- start_offset = read_32bit(0x04,streamFile);
- loop_flag = 1;
- channel_count = 2;
+ total_subsongs = 1;
+ block_id = read_32bit(start_offset, streamFile);
+
+ /* files are basically headerless so we inspect blocks the first block
+ * Freekstyle uses multiblocks/subsongs (though some subsongs may be clones?) */
+ switch(block_id) {
+ case 0x5641474D: /* "VAGM" */
+ coding = coding_PSX;
+ if (read_16bit(start_offset+0x1a, streamFile) == 0x0024) {
+ total_subsongs = read_32bit(start_offset+0x0c, streamFile)+1;
+ sample_rate = 24000;
+ }
+ else {
+ sample_rate = 14008;
+ }
+ channel_count = 2;
+ break;
+ case 0x56414742: /* "VAGB" */
+ coding = coding_PSX;
+ if (read_16bit(start_offset+0x1a, streamFile) == 0x6400) {
+ sample_rate = 24000;
+ }
+ else {
+ sample_rate = 14008;
+ }
+ channel_count = 1;
+ break;
+ case 0x4453504D: /* "DSPM" */
+ coding = coding_NGC_DSP;
+ total_subsongs = read_32bit(start_offset+0x0c, streamFile)+1;
+ sample_rate = 24000;
+ channel_count = 2;
+ break;
+ case 0x44535042: /* "DSPB" */
+ coding = coding_NGC_DSP;
+ channel_count = 1;
+ sample_rate = 24000;
+ break;
+ case 0x4D534943: /* "MSIC" */
+ coding = coding_PCM8_U_int;
+ channel_count = 2;
+ sample_rate = 14008;
+ break;
+ case 0x53484F43: /* "SHOC" (a generic block but hopefully has PC sounds) */
+ coding = coding_PCM8_U_int;
+ channel_count = 1;
+ sample_rate = 14008;
+ break;
+ default:
+ VGM_LOG("EA SWVR: unknown block id\n");
+ goto fail;
+ }
+
+ if (target_subsong == 0) target_subsong = 1;
+ if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
+
+ loop_flag = 0;//(channel_count > 1); /* some Future Cop LAPD tracks repeat but other games have fadeouts */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- vgmstream->sample_rate = 16000;
+ vgmstream->sample_rate = sample_rate;
vgmstream->codec_endian = big_endian;
+ vgmstream->num_streams = total_subsongs;
+ vgmstream->stream_size = get_streamfile_size(streamFile) / total_subsongs; /* approx... */
vgmstream->meta_type = meta_EA_SWVR;
+ vgmstream->coding_type = coding;
vgmstream->layout_type = layout_blocked_ea_swvr;
-
- vgmstream->coding_type = coding_PSX;
+ /* DSP coefs are loaded per block */
+ /* some files (voices etc) decode with pops but seems a mastering problem */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
-
- /* calculate samples */
+ /* calc num_samples manually */
{
- off_t current_chunk = start_offset;
-
- vgmstream->num_samples = 0;
- while ((current_chunk + start_offset) < (get_streamfile_size(streamFile))) {
- uint32_t block_id = (read_32bit(current_chunk,streamFile));
- if (block_id == 0x5641474D) { /* "VAGM" */
- block_update_ea_swvr(start_offset,vgmstream);
- vgmstream->num_samples += vgmstream->current_block_size/16*28;
- current_chunk += vgmstream->current_block_size + 0x1C;
+ int num_samples;
+ vgmstream->stream_index = target_subsong; /* needed to skip other subsong-blocks */
+ vgmstream->next_block_offset = start_offset;
+ do {
+ block_update_ea_swvr(vgmstream->next_block_offset,vgmstream);
+ switch(vgmstream->coding_type) {
+ case coding_PSX: num_samples = ps_bytes_to_samples(vgmstream->current_block_size,1); break;
+ case coding_NGC_DSP: num_samples = dsp_bytes_to_samples(vgmstream->current_block_size,1); break;
+ case coding_PCM8_U_int: num_samples = pcm_bytes_to_samples(vgmstream->current_block_size,1,8); break;
+ default: num_samples = 0; break;
}
- current_chunk += 0x10;
+ vgmstream->num_samples += num_samples;
}
+ while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
}
if (loop_flag) {
@@ -72,6 +155,7 @@ VGMSTREAM * init_vgmstream_ea_swvr(STREAMFILE *streamFile) {
vgmstream->loop_end_sample = vgmstream->num_samples;
}
+ block_update_ea_swvr(start_offset, vgmstream);
return vgmstream;
fail:
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_wve_ad10.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_wve_ad10.c
new file mode 100644
index 000000000..494a6b461
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_wve_ad10.c
@@ -0,0 +1,55 @@
+#include "meta.h"
+#include "../coding/coding.h"
+#include "../layout/layout.h"
+
+/* EA WVE (Ad10) - from Electronic Arts PS movies [Wing Commander 3/4 (PS)] */
+VGMSTREAM * init_vgmstream_ea_wve_ad10(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ int loop_flag, channel_count;
+
+
+ /* checks */
+ if (!check_extensions(streamFile, "wve"))
+ goto fail;
+
+ start_offset = 0x00;
+ if (read_32bitBE(start_offset, streamFile) != 0x41643130 && /* "Ad10" */
+ read_32bitBE(start_offset, streamFile) != 0x41643131) /* "Ad11" (last block, but could be first) */
+ goto fail;
+ loop_flag = 0;
+ /* no header = no channels, but seems if the first PS-ADPCM header is 00 then it's mono, somehow
+ * (ex. Wing Commander 3 intro / Wing Commander 4 = stereo, rest of Wing Commander 3 = mono) */
+ channel_count = read_8bit(start_offset+0x08,streamFile) != 0 ? 2 : 1;
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count, loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = 22050;
+ vgmstream->meta_type = meta_EA_WVE_AD10;
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = layout_blocked_ea_wve_ad10;
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
+
+ /* calc num_samples manually */
+ {
+ vgmstream->next_block_offset = start_offset;
+ do {
+ block_update_ea_wve_ad10(vgmstream->next_block_offset,vgmstream);
+ vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
+ }
+ while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
+ }
+
+ block_update_ea_wve_ad10(start_offset, vgmstream);
+
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_wve_au00.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_wve_au00.c
new file mode 100644
index 000000000..a4aea7a4d
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_wve_au00.c
@@ -0,0 +1,59 @@
+#include "meta.h"
+#include "../coding/coding.h"
+#include "../layout/layout.h"
+
+/* EA WVE (VLC0/au00) - from Electronic Arts PS movies [Future Cop - L.A.P.D. (PS), Supercross 2000 (PS)] */
+VGMSTREAM * init_vgmstream_ea_wve_au00(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ int loop_flag, channel_count;
+
+
+ /* checks */
+ /* .wve: common, .fsv: Future Cop LAPD (PS1) */
+ if (!check_extensions(streamFile, "wve,fsv"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x564C4330) /* "VLC0" */
+ goto fail;
+
+ start_offset = read_32bitBE(0x04,streamFile);
+ if (read_32bitBE(start_offset, streamFile) != 0x61753030 && /* "au00" */
+ read_32bitBE(start_offset, streamFile) != 0x61753031) /* "au01" (last block, but could be first) */
+ goto fail;
+ loop_flag = 0;
+ channel_count = 2;
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count, loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = 22050;
+ vgmstream->meta_type = meta_EA_WVE_AU00;
+
+ /* You'd think they'd use coding_EA_XA_int but instead it's PS-ADPCM without flags and 0x0f frame size
+ * (equivalent to configurable PS-ADPCM), surely to shoehorn EA-XA sizes into the PS1 hardware decoder */
+ vgmstream->coding_type = coding_PSX_cfg;
+ vgmstream->interleave_block_size = 0x0f;
+ vgmstream->layout_type = layout_blocked_ea_wve_au00;
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
+
+ /* calc num_samples manually */
+ {
+ vgmstream->next_block_offset = start_offset;
+ do {
+ block_update_ea_wve_au00(vgmstream->next_block_offset,vgmstream);
+ vgmstream->num_samples += ps_cfg_bytes_to_samples(vgmstream->current_block_size, vgmstream->interleave_block_size, 1);
+ }
+ while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
+ }
+
+ block_update_ea_wve_au00(start_offset, vgmstream);
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/emff.c b/Frameworks/vgmstream/vgmstream/src/meta/emff.c
index 10cb7645e..79928e66b 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/emff.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/emff.c
@@ -44,7 +44,7 @@ VGMSTREAM * init_vgmstream_emff_ps2(STREAMFILE *streamFile) {
vgmstream->channels = channel_count;
vgmstream->coding_type = coding_PSX;
- vgmstream->layout_type = layout_emff_ps2_blocked;
+ vgmstream->layout_type = layout_blocked_emff_ps2;
vgmstream->interleave_block_size = 0x10;
vgmstream->meta_type = meta_EMFF_PS2;
@@ -59,7 +59,7 @@ VGMSTREAM * init_vgmstream_emff_ps2(STREAMFILE *streamFile) {
}
/* Calc num_samples */
- emff_ps2_block_update(start_offset,vgmstream);
+ block_update_emff_ps2(start_offset,vgmstream);
vgmstream->num_samples = read_32bitLE(0x8,streamFile);
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitLE(0x28,streamFile)-start_offset)*28/16/channel_count;
@@ -148,7 +148,7 @@ VGMSTREAM * init_vgmstream_emff_ngc(STREAMFILE *streamFile) {
goto fail;
}
- vgmstream->layout_type = layout_emff_ngc_blocked;
+ vgmstream->layout_type = layout_blocked_emff_ngc;
vgmstream->interleave_block_size = 0x10;
vgmstream->meta_type = meta_EMFF_NGC;
@@ -163,7 +163,7 @@ VGMSTREAM * init_vgmstream_emff_ngc(STREAMFILE *streamFile) {
}
/* Calc num_samples */
- emff_ngc_block_update(start_offset,vgmstream);
+ block_update_emff_ngc(start_offset,vgmstream);
vgmstream->num_samples = read_32bitBE(0x8,streamFile);;
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitBE(0x28,streamFile))*14/8/channel_count;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ffmpeg.c b/Frameworks/vgmstream/vgmstream/src/meta/ffmpeg.c
index 87c8662e6..dc0639749 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ffmpeg.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ffmpeg.c
@@ -3,6 +3,8 @@
#ifdef VGM_USE_FFMPEG
+static int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile);
+
/**
* Generic init FFmpeg and vgmstream for any file supported by FFmpeg.
* Called by vgmstream when trying to identify the file type (if the player allows it).
@@ -75,4 +77,47 @@ fail:
return NULL;
}
+
+/**
+ * open file containing looping data and copy to buffer
+ *
+ * returns true if found and copied
+ */
+int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile) {
+ char posname[PATH_LIMIT];
+ char filename[PATH_LIMIT];
+ /*size_t bytes_read;*/
+ STREAMFILE * streamFilePos= NULL;
+
+ streamFile->get_name(streamFile,filename,sizeof(filename));
+
+ if (strlen(filename)+4 > sizeof(posname)) goto fail;
+
+ /* try to open a posfile using variations: "(name.ext).pos" */
+ {
+ strcpy(posname, filename);
+ strcat(posname, ".pos");
+ streamFilePos = streamFile->open(streamFile,posname,STREAMFILE_DEFAULT_BUFFER_SIZE);
+ if (streamFilePos) goto found;
+
+ goto fail;
+ }
+
+found:
+ //if (get_streamfile_size(streamFilePos) != bufsize) goto fail;
+
+ /* allow pos files to be of different sizes in case of new features, just fill all we can */
+ memset(buf, 0, bufsize);
+ read_streamfile(buf, 0, bufsize, streamFilePos);
+
+ close_streamfile(streamFilePos);
+
+ return 1;
+
+fail:
+ if (streamFilePos) close_streamfile(streamFilePos);
+
+ return 0;
+}
+
#endif
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c
index 99bf7d516..da2c2f414 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c
@@ -110,7 +110,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
break;
case 0x03: /* Loop Info */
LoopStart = read_32bitLE(ExtraFlagStart+0x04,streamFile);
- if (ExtraFlagSize > 0x04) /* probably no needed */
+ if (ExtraFlagSize > 0x04) /* probably not needed */
LoopEnd = read_32bitLE(ExtraFlagStart+0x08,streamFile);
/* when start is 0 seems the song repeats with no real looping (ex. Sonic Boom Fire & Ice jingles) */
@@ -118,9 +118,9 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
break;
case 0x04: /* free comment, or maybe SFX info */
break;
- //case 0x05: /* Unknown (32b) */
- // /* found in Tearaway Vita, value 0, first stream only */
- // break;
+ //case 0x05: /* Unknown (32b) */
+ // /* found in Tearaway Vita, value 0, first stream only */
+ // break;
case 0x06: /* XMA seek table */
/* no need for it */
break;
@@ -142,11 +142,11 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
* (xN entries)
*/
break;
- //case 0x0d: /* Unknown (32b) */
- // /* found in some XMA2 and Vorbis */
- // break;
+ //case 0x0d: /* Unknown (32b) */
+ // /* found in some XMA2/Vorbis/FADPCM */
+ // break;
default:
- VGM_LOG("FSB5: unknown extra flag 0x%x at 0x%04x (size 0x%x)\n", ExtraFlagType, ExtraFlagStart, ExtraFlagSize);
+ VGM_LOG("FSB5: unknown extra flag 0x%x at 0x%04x + 0x04 (size 0x%x)\n", ExtraFlagType, ExtraFlagStart, ExtraFlagSize);
break;
}
@@ -336,7 +336,10 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
#endif
case 0x10: /* FMOD_SOUND_FORMAT_FADPCM */
- goto fail;
+ vgmstream->coding_type = coding_FADPCM;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x8c;
+ break;
default:
goto fail;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb_encrypted.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb_encrypted.c
index 98af7df96..a6af18da7 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/fsb_encrypted.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb_encrypted.c
@@ -56,7 +56,7 @@ VGMSTREAM * init_vgmstream_fsb_encrypted(STREAMFILE * streamFile) {
for (i = 0; i < fsbkey_list_count; i++) {
fsbkey_info entry = fsbkey_list[i];
- ;VGM_LOG("fsbkey: size=%i, is_fsb5=%i, is_alt=%i\n", entry.fsbkey_size,entry.is_fsb5, entry.is_alt);
+ //;VGM_LOG("fsbkey: size=%i, is_fsb5=%i, is_alt=%i\n", entry.fsbkey_size,entry.is_fsb5, entry.is_alt);
temp_streamFile = setup_fsb_streamfile(streamFile, entry.fsbkey, entry.fsbkey_size, entry.is_alt);
if (!temp_streamFile) goto fail;
@@ -146,7 +146,7 @@ static STREAMFILE* setup_fsb_streamfile(STREAMFILE *streamFile, const uint8_t *
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
- new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, fsb_decryption_read);
+ new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, fsb_decryption_read,NULL);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/fsb_keys.h
index 1b3a6081d..b65bea954 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/fsb_keys.h
+++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb_keys.h
@@ -63,6 +63,12 @@ static const uint8_t key_inv[] = { 0x6D,0x69,0x6E,0x74,0x37,0x38,0x72,0x75,0x6E,
/* Guitar Hero 3 */ //"5atu6w4zaw"
static const uint8_t key_gh3[] = { 0x35,0x61,0x74,0x75,0x36,0x77,0x34,0x7A,0x61,0x77 };
+/* Supreme Commander 2 */ //"B2A7BB00"
+static const uint8_t key_sc2[] = { 0x42,0x32,0x41,0x37,0x42,0x42,0x30,0x30 };
+
+/* Cookie Run: Ovenbreak */ //"ghfxhslrghfxhslr"
+static const uint8_t key_cro[] = { 0x67,0x68,0x66,0x78,0x68,0x73,0x6C,0x72,0x67,0x68,0x66,0x78,0x68,0x73,0x6C,0x72 };
+
// Unknown:
// - Battle: Los Angeles
// - Guitar Hero: Warriors of Rock, DJ hero FSB
@@ -118,6 +124,11 @@ static const fsbkey_info fsbkey_list[] = {
{ 0,1, sizeof(key_gh3),key_gh3 },//untested
{ 1,0, sizeof(key_gh3),key_gh3 },//untested
{ 1,1, sizeof(key_gh3),key_gh3 },//untested
+ { 0,0, sizeof(key_sc2),key_sc2 },//untested
+ { 0,1, sizeof(key_sc2),key_sc2 },//untested
+ { 1,0, sizeof(key_sc2),key_sc2 },//untested
+ { 1,1, sizeof(key_sc2),key_sc2 },//untested
+ { 1,0, sizeof(key_cro),key_cro },
};
static const int fsbkey_list_count = sizeof(fsbkey_list) / sizeof(fsbkey_list[0]);
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/g1l.c b/Frameworks/vgmstream/vgmstream/src/meta/g1l.c
index 81b767d35..7c6e43d81 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/g1l.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/g1l.c
@@ -4,12 +4,12 @@
static VGMSTREAM * init_vgmstream_kt_wiibgm_offset(STREAMFILE *streamFile, off_t offset);
-/* Koei Tecmo G1L - pack format, sometimes containing a single stream
- *
+/* Koei Tecmo G1L - container format, sometimes containing a single stream.
* It probably makes more sense to extract it externally, it's here mainly for Hyrule Warriors */
VGMSTREAM * init_vgmstream_kt_g1l(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- int type, num_streams, target_stream = streamFile->stream_index;
+ int type;
+ int total_streams, target_stream = streamFile->stream_index;
off_t stream_offset;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
@@ -22,30 +22,30 @@ VGMSTREAM * init_vgmstream_kt_g1l(STREAMFILE *streamFile) {
&& read_32bitBE(0x4, streamFile) != 0x30303030) /* "0000" (version?) */
goto fail;
- if (read_32bitBE(0x0, streamFile) == 0x47314C5F ) {
+ if (read_32bitBE(0x0, streamFile) == 0x47314C5F) {
read_32bit = read_32bitBE;
} else {
read_32bit = read_32bitLE;
}
- /* 0x08 filesize */
- /* 0x0c first file offset (same as 0x18) */
+ /* 0x08: filesize, 0x0c: header size */
type = read_32bit(0x10,streamFile);
- num_streams = read_32bit(0x14,streamFile);
+ total_streams = read_32bit(0x14,streamFile);
if (target_stream==0) target_stream = 1;
- if (target_stream < 0 || target_stream > num_streams || num_streams < 1) goto fail;
+ if (target_stream < 0 || target_stream > total_streams || total_streams < 1) goto fail;
stream_offset = read_32bit(0x18 + 0x4*(target_stream-1),streamFile);
- /* filesize = stream_offset - stream_next_offset*/
+ //stream_size = stream_offset - stream_next_offset;//not ok, sometimes entries are unordered/repeats */
switch(type) { /* type may not be correct */
case 0x09: /* DSP (WiiBGM) from Hyrule Warriors (Wii U) */
vgmstream = init_vgmstream_kt_wiibgm_offset(streamFile, stream_offset);
break;
+ case 0x06: /* ATRAC9 (RIFF) from One Piece Pirate Warriors 3 (Vita) */
case 0x01: /* ATRAC3plus (RIFF) from One Piece Pirate Warriors 2 (PS3) */
case 0x00: /* OGG (KOVS) from Romance Three Kindgoms 13 (PC)*/
- case 0x0A: /* OGG (KOVS) from Dragon Quest Heroes (PC)*/
+ case 0x0A: /* OGG (KOVS) from Dragon Quest Heroes (PC), Bladestorm (PC) w/ single files */
default:
goto fail;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/gca.c b/Frameworks/vgmstream/vgmstream/src/meta/gca.c
index f48f9014d..246068773 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/gca.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/gca.c
@@ -1,69 +1,42 @@
#include "meta.h"
+#include "../coding/coding.h"
#include "../util.h"
-/* GCA (from Metal Slug Anthology [Wii]) */
+/* GCA - Terminal Reality games [Metal Slug Anthology (Wii), BlowOut (GC)] */
VGMSTREAM * init_vgmstream_gca(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
off_t start_offset;
- int loop_flag = 0;
- int channel_count = 1;
+ int loop_flag, channel_count;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("gca",filename_extension(filename))) goto fail;
+ /* checks */
+ if (!check_extensions(streamFile, "gca"))
+ goto fail;
- /* check header */
if (read_32bitBE(0x00,streamFile) != 0x47434131) /* "GCA1" */
goto fail;
-
+
+ start_offset = 0x40;
+ loop_flag = 0;
+ channel_count = 1;
+
/* 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_32bitBE(0x2A,streamFile);
vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->num_samples = read_32bitBE(0x26,streamFile)*7/8;
- if (loop_flag) {
- vgmstream->loop_start_sample = 0;
- vgmstream->loop_end_sample = read_32bitBE(0x26,streamFile)*7/8;
- }
+ vgmstream->num_samples = dsp_nibbles_to_samples(read_32bitBE(0x26,streamFile));//read_32bitBE(0x26,streamFile)*7/8;
- /* We have no interleave, so we have no layout */
- vgmstream->layout_type = layout_none;
+ vgmstream->layout_type = layout_none; /* we have no interleave, so we have no layout */
vgmstream->meta_type = meta_GCA;
- /* 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;
-
- }
- }
-
- /*Retrieving the coef table */
- {
- int i;
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x04+i*2,streamFile);
- }
- }
+ dsp_read_coefs_be(vgmstream,streamFile,0x04,0x00);
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/genh.c b/Frameworks/vgmstream/vgmstream/src/meta/genh.c
index ea67480af..70cac1066 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/genh.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/genh.c
@@ -157,6 +157,8 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
coding = coding_DVI_IMA_int;
if (coding == coding_IMA)
coding = coding_IMA_int;
+ if (coding == coding_AICA)
+ coding = coding_AICA_int;
}
/* to avoid endless loops */
@@ -173,7 +175,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
}
/* setup adpcm */
- if (coding == coding_AICA) {
+ if (coding == coding_AICA || coding == coding_AICA_int) {
int i;
for (i=0;ichannels;i++) {
vgmstream->ch[i].adpcm_step_index = 0x7f;
@@ -195,7 +197,15 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
vgmstream->layout_type = layout_none;
break;
case coding_XBOX_IMA:
- vgmstream->layout_type = layout_none;
+ if (genh.codec_mode == 1) {
+ if (!genh.interleave) goto fail; /* creates garbage */
+ coding = coding_XBOX_IMA_int;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = genh.interleave;
+ }
+ else {
+ vgmstream->layout_type = layout_none;
+ }
break;
case coding_NGC_DTK:
if (vgmstream->channels != 2) goto fail;
@@ -367,14 +377,16 @@ static int parse_genh(STREAMFILE * streamFile, genh_header * genh) {
genh->num_samples = read_32bitLE(0x40,streamFile);
genh->skip_samples = read_32bitLE(0x44,streamFile); /* for FFmpeg based codecs */
genh->skip_samples_mode = read_8bit(0x48,streamFile); /* 0=autodetect, 1=force manual value @ 0x44 */
- if (genh->codec == ATRAC3 || genh->codec == ATRAC3PLUS)
- genh->codec_mode = read_8bit(0x49,streamFile); /* 0=autodetect, 1=force joint stereo, 2=force full stereo */
- if (genh->codec == XMA1 || genh->codec == XMA2)
- genh->codec_mode = read_8bit(0x4a,streamFile); /* 0=default (4ch = 2ch + 2ch), 1=single (4ch = 1ch + 1ch + 1ch + 1ch) */
+ genh->codec_mode = read_8bit(0x4b,streamFile);
+ if ((genh->codec == ATRAC3 || genh->codec == ATRAC3PLUS) && genh->codec_mode==0)
+ genh->codec_mode = read_8bit(0x49,streamFile);
+ if ((genh->codec == XMA1 || genh->codec == XMA2) && genh->codec_mode==0)
+ genh->codec_mode = read_8bit(0x4a,streamFile);
genh->data_size = read_32bitLE(0x50,streamFile);
if (genh->data_size == 0)
genh->data_size = get_streamfile_size(streamFile) - genh->start_offset;
+
genh->num_samples = genh->num_samples > 0 ? genh->num_samples : genh->loop_end_sample;
genh->loop_flag = genh->loop_start_sample != -1;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/gsp_gsb.c b/Frameworks/vgmstream/vgmstream/src/meta/gsp_gsb.c
index 4e1c3021f..d51ec2407 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/gsp_gsb.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/gsp_gsb.c
@@ -16,7 +16,7 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
if (!check_extensions(streamFile,"gsb"))
goto fail;
- streamFileGSP = open_stream_ext(streamFile, "gsp");
+ streamFileGSP = open_streamfile_by_ext(streamFile, "gsp");
if (!streamFileGSP) goto fail;
/* check header */
@@ -63,7 +63,7 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
size_t num_blocks;
vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_gsb_blocked;
+ vgmstream->layout_type = layout_blocked_gsb;
if (!find_chunk_be(streamFileGSP, 0x47434558,first_offset,1, &chunk_offset,NULL)) goto fail; /*"GCEX"*/
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/halpst.c b/Frameworks/vgmstream/vgmstream/src/meta/halpst.c
index caec16ade..24e6e23cb 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/halpst.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/halpst.c
@@ -91,7 +91,7 @@ VGMSTREAM * init_vgmstream_halpst(STREAMFILE *streamFile) {
}
vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_halpst_blocked;
+ vgmstream->layout_type = layout_blocked_halpst;
vgmstream->meta_type = meta_HALPST;
/* load decode coefs */
@@ -120,7 +120,7 @@ VGMSTREAM * init_vgmstream_halpst(STREAMFILE *streamFile) {
}
/* start me up */
- halpst_block_update(header_length,vgmstream);
+ block_update_halpst(header_length,vgmstream);
return vgmstream;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h
index 231307cda..fce656081 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h
+++ b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h
@@ -228,6 +228,9 @@ static const hcakey_info hcakey_list[] = {
// Dx2 Shin Megami Tensei Liberation (iOS/Android)
{118714477}, // 000000000713706D
+ // Oira (Cygames) [iOS/Android]
+ {46460622}, // 0000000002C4EECE
+
};
#endif/*_HCA_KEYS_H_*/
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/idsp.c b/Frameworks/vgmstream/vgmstream/src/meta/idsp.c
index a5f2ad9a6..82f79a5d3 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/idsp.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/idsp.c
@@ -1,16 +1,16 @@
#include "meta.h"
#include "../util.h"
-/* "idsp/IDSP"
- Soul Calibur Legends (Wii)
- Sky Crawlers: Innocent Aces (Wii)
+/* "idsp/IDSP"
+ Soul Calibur Legends (Wii)
+ Sky Crawlers: Innocent Aces (Wii)
*/
VGMSTREAM * init_vgmstream_idsp2(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
int loop_flag;
- int channel_count;
- int i, j;
+ int channel_count;
+ int i, j;
off_t start_offset;
/* check extension, case insensitive */
@@ -20,60 +20,53 @@ VGMSTREAM * init_vgmstream_idsp2(STREAMFILE *streamFile) {
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x69647370 || /* "idsp" */
read_32bitBE(0xBC,streamFile) != 0x49445350) /* IDSP */
- goto fail;
+ goto fail;
loop_flag = read_32bitBE(0x20,streamFile);
channel_count = read_32bitBE(0xC4,streamFile);
if (channel_count > 8)
- {
- goto fail;
- }
+ goto fail;
- /* build the VGMSTREAM */
+
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- /* fill in the vital statistics */
- start_offset = (channel_count * 0x60) + 0x100;
- vgmstream->channels = channel_count;
- vgmstream->sample_rate = read_32bitBE(0xC8,streamFile);
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->num_samples = (read_32bitBE(0x14,streamFile))*14/8/channel_count;
+ start_offset = (channel_count * 0x60) + 0x100;
+ vgmstream->sample_rate = read_32bitBE(0xC8,streamFile);
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->num_samples = (read_32bitBE(0x14,streamFile))*14/8/channel_count;
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitBE(0xD0,streamFile));
vgmstream->loop_end_sample = (read_32bitBE(0xD4,streamFile));
}
-
- if (channel_count == 1)
- {
- vgmstream->layout_type = layout_none;
+
+ if (channel_count == 1) {
+ vgmstream->layout_type = layout_none;
}
- else if (channel_count > 1)
- {
- if (read_32bitBE(0xD8,streamFile) == 0)
- {
- vgmstream->layout_type = layout_none;
- vgmstream->interleave_block_size = (get_streamfile_size(streamFile)-start_offset)/2;
+ else if (channel_count > 1) {
+ if (read_32bitBE(0xD8,streamFile) == 0) {
+ vgmstream->layout_type = layout_none;
+ vgmstream->interleave_block_size = (get_streamfile_size(streamFile)-start_offset)/2;
}
- else if (read_32bitBE(0xD8,streamFile) > 0)
- {
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = read_32bitBE(0xD8,streamFile);
+ else if (read_32bitBE(0xD8,streamFile) > 0) {
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = read_32bitBE(0xD8,streamFile);
}
}
- vgmstream->meta_type = meta_IDSP;
+ vgmstream->meta_type = meta_IDSP;
- {
- if (vgmstream->coding_type == coding_NGC_DSP) {
- off_t coef_table[8] = {0x118,0x178,0x1D8,0x238,0x298,0x2F8,0x358,0x3B8};
- for (j=0;jchannels;j++) {
- for (i=0;i<16;i++) {
- vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_table[j]+i*2,streamFile);
- }
+ {
+ if (vgmstream->coding_type == coding_NGC_DSP) {
+ off_t coef_table[8] = {0x118,0x178,0x1D8,0x238,0x298,0x2F8,0x358,0x3B8};
+ for (j=0;jchannels;j++) {
+ for (i=0;i<16;i++) {
+ vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_table[j]+i*2,streamFile);
+ }
+ }
}
- }
}
/* open the file for reading */
@@ -121,17 +114,13 @@ VGMSTREAM * init_vgmstream_idsp3(STREAMFILE *streamFile) {
channel_count = read_32bitBE(0x24,streamFile);
if (channel_count > 8)
- {
- goto fail;
- }
+ goto fail;
- /* build the VGMSTREAM */
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- /* fill in the vital statistics */
start_offset = (channel_count*0x60)+0xC;
- vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x14,streamFile);
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->num_samples = read_32bitBE(0x0C,streamFile);
@@ -141,9 +130,9 @@ VGMSTREAM * init_vgmstream_idsp3(STREAMFILE *streamFile) {
}
vgmstream->interleave_block_size = read_32bitBE(0x04,streamFile);
- vgmstream->interleave_smallblock_size = ((vgmstream->num_samples/7*8)%(vgmstream->interleave_block_size)/vgmstream->channels);
- vgmstream->layout_type = layout_interleave_shortblock;
-
+ vgmstream->interleave_last_block_size = ((vgmstream->num_samples/7*8)%(vgmstream->interleave_block_size)/vgmstream->channels);
+ vgmstream->layout_type = layout_interleave;
+
vgmstream->meta_type = meta_IDSP;
if (vgmstream->coding_type == coding_NGC_DSP) {
@@ -170,7 +159,6 @@ VGMSTREAM * init_vgmstream_idsp3(STREAMFILE *streamFile) {
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
-
}
}
@@ -187,7 +175,7 @@ VGMSTREAM * init_vgmstream_idsp4(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
int loop_flag = 0;
- int channel_count;
+ int channel_count;
off_t start_offset;
/* check extension, case insensitive */
@@ -201,17 +189,13 @@ VGMSTREAM * init_vgmstream_idsp4(STREAMFILE *streamFile) {
channel_count = read_32bitBE(0x0C,streamFile);
if (channel_count > 2) // Refuse everything else for now
- {
- goto fail;
- }
+ goto fail;
- /* build the VGMSTREAM */
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- /* fill in the vital statistics */
start_offset = 0x70;
- vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x08,streamFile);
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->num_samples = read_32bitBE(0x04,streamFile)/channel_count/8*14;
@@ -220,27 +204,25 @@ VGMSTREAM * init_vgmstream_idsp4(STREAMFILE *streamFile) {
vgmstream->loop_end_sample = read_32bitBE(0x04,streamFile)/channel_count/8*14;
}
- if (channel_count == 1)
- {
- vgmstream->layout_type = layout_none;
+ if (channel_count == 1) {
+ vgmstream->layout_type = layout_none;
}
- else
- {
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = read_32bitBE(0x10,streamFile);
+ else {
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = read_32bitBE(0x10,streamFile);
}
vgmstream->meta_type = meta_IDSP;
- {
- int i;
- for (i=0;i<16;i++)
- vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x14+i*2,streamFile);
- if (channel_count == 2) {
- for (i=0;i<16;i++)
- vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x42+i*2,streamFile);
- }
- }
+ {
+ int i;
+ for (i=0;i<16;i++)
+ vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x14+i*2,streamFile);
+ if (channel_count == 2) {
+ for (i=0;i<16;i++)
+ vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x42+i*2,streamFile);
+ }
+ }
/* open the file for reading */
{
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ish_isd.c b/Frameworks/vgmstream/vgmstream/src/meta/ish_isd.c
index 6b3c734a9..84d2f22f3 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ish_isd.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ish_isd.c
@@ -1,91 +1,60 @@
#include "meta.h"
-#include "../util.h"
-
-/*
-ISH+ISD
-*/
+#include "../coding/coding.h"
+/* ISH+ISD - from various games [Chaos Field (GC), Pokemon XD - Gale of Darkness (GC)] */
VGMSTREAM * init_vgmstream_ish_isd(STREAMFILE *streamFile) {
-
VGMSTREAM * vgmstream = NULL;
- STREAMFILE * streamFileISH = NULL;
- char filename[PATH_LIMIT];
- char filenameISH[PATH_LIMIT];
- int i;
- int channel_count;
- int loop_flag;
+ STREAMFILE * streamHeader = NULL;
+ off_t start_offset;
+ int channel_count, loop_flag;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("isd",filename_extension(filename))) goto fail;
- strcpy(filenameISH,filename);
- strcpy(filenameISH+strlen(filenameISH)-3,"ish");
-
- streamFileISH = streamFile->open(streamFile,filenameISH,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!streamFileISH) goto fail;
-
- /* check header */
- if (read_32bitBE(0x00,streamFileISH) != 0x495F5346) /* "I_SF" */
+ /* checks */
+ if (!check_extensions(streamFile, "isd"))
goto fail;
-
- channel_count = read_32bitBE(0x14,streamFileISH);
- loop_flag = (read_32bitBE(0x1C,streamFileISH) !=0);
+
+ streamHeader = open_streamfile_by_ext(streamFile,"ish");
+ if (!streamHeader) goto fail;
+
+ if (read_32bitBE(0x00,streamHeader) != 0x495F5346) /* "I_SF" */
+ goto fail;
+
+ channel_count = read_32bitBE(0x14,streamHeader);
+ loop_flag = (read_32bitBE(0x1C,streamHeader) != 0);
+ start_offset = 0;
+
/* 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_32bitBE(0x08,streamFileISH);
- vgmstream->num_samples=read_32bitBE(0x0C,streamFileISH);
- vgmstream->coding_type = coding_NGC_DSP;
- if(loop_flag) {
- vgmstream->loop_start_sample = read_32bitBE(0x20,streamFileISH)*14/8/channel_count;
- vgmstream->loop_end_sample = read_32bitBE(0x24,streamFileISH)*14/8/channel_count;
- }
-
- if (channel_count == 1) {
- vgmstream->layout_type = layout_none;
- } else if (channel_count == 2) {
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = read_32bitBE(0x18,streamFileISH);
+ vgmstream->sample_rate = read_32bitBE(0x08,streamHeader);
+ vgmstream->num_samples = read_32bitBE(0x0C,streamHeader);
+ if (loop_flag) {
+ vgmstream->loop_start_sample = read_32bitBE(0x20,streamHeader)*14 / 0x08 /channel_count;
+ vgmstream->loop_end_sample = read_32bitBE(0x24,streamHeader)*14 / 0x08 / channel_count;
}
vgmstream->meta_type = meta_ISH_ISD;
-
- /* open the file for reading by each channel */
- {
- for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size);
-
- if (!vgmstream->ch[i].streamfile) goto fail;
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=i*vgmstream->interleave_block_size;
- }
- }
-
-
- if (vgmstream->coding_type == coding_NGC_DSP) {
- int i;
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x40+i*2,streamFileISH);
- }
- if (vgmstream->channels == 2) {
- for (i=0;i<16;i++) {
- vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x80+i*2,streamFileISH);
- }
- }
+ vgmstream->coding_type = coding_NGC_DSP;
+ if (channel_count == 1) {
+ vgmstream->layout_type = layout_none;
+ } else {
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = read_32bitBE(0x18,streamHeader);
}
- close_streamfile(streamFileISH); streamFileISH=NULL;
-
+ dsp_read_coefs_be(vgmstream,streamHeader,0x40,0x40);
+
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
+
+ close_streamfile(streamHeader);
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (streamFileISH) close_streamfile(streamFileISH);
- if (vgmstream) close_vgmstream(vgmstream);
+ close_streamfile(streamHeader);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ktss.c b/Frameworks/vgmstream/vgmstream/src/meta/ktss.c
index 9884b3b42..463ac152c 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ktss.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ktss.c
@@ -10,7 +10,7 @@ VGMSTREAM * init_vgmstream_ktss(STREAMFILE *streamFile) {
int32_t loop_length, coef_start_offset, coef_spacing;
off_t start_offset;
- if (!check_extensions(streamFile, "ktss"))
+ if (!check_extensions(streamFile, "kns,ktss"))
goto fail;
if (read_32bitBE(0, streamFile) != 0x4B545353) /* "KTSS" */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h
index 89e049d6f..c32d47152 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h
+++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h
@@ -76,8 +76,6 @@ VGMSTREAM * init_vgmstream_ps2_pnb(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_xbox_wavm(STREAMFILE *streamFile);
-VGMSTREAM * init_vgmstream_xbox_xwav(STREAMFILE *streamFile);
-
VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_caf(STREAMFILE *streamFile);
@@ -97,7 +95,6 @@ typedef struct {
int loop_end_found;
int32_t loop_end;
meta_t meta_type;
- layout_t layout_type;
off_t stream_size;
int total_subsongs;
@@ -106,11 +103,11 @@ typedef struct {
void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource);
uint8_t scd_xor;
off_t scd_xor_length;
- uint32_t sngw_xor;
+ uint32_t xor_value;
-} vgm_vorbis_info_t;
+} ogg_vorbis_meta_info_t;
-VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const char * filename, ov_callbacks *callbacks, off_t other_header_bytes, const vgm_vorbis_info_t *vgm_inf);
+VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callbacks *callbacks, off_t other_header_bytes, const ogg_vorbis_meta_info_t *ovmi);
VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE * streamFile);
#endif
@@ -128,7 +125,7 @@ VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_mp4_aac(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_mp4_aac_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size);
-VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile);
+VGMSTREAM * init_vgmstream_akb_mp4(STREAMFILE *streamFile);
#endif
VGMSTREAM * init_vgmstream_sfl(STREAMFILE * streamFile);
@@ -224,8 +221,6 @@ VGMSTREAM * init_vgmstream_ps2_pcm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_rkv(STREAMFILE * streamFile);
-VGMSTREAM * init_vgmstream_ps2_psw(STREAMFILE * streamFile);
-
VGMSTREAM * init_vgmstream_ps2_vas(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_tec(STREAMFILE * streamFile);
@@ -288,6 +283,7 @@ VGMSTREAM * init_vgmstream_psx_fag(STREAMFILE * streamFile);
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);
@@ -309,6 +305,8 @@ VGMSTREAM * init_vgmstream_rsd6xadp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd6radp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd6oogv(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_rsd6xma(STREAMFILE *streamFile);
+VGMSTREAM * init_vgmstream_rsd6at3p(STREAMFILE * streamFile);
+VGMSTREAM * init_vgmstream_rsd6wma(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_dc_asd(STREAMFILE * streamFile);
@@ -319,7 +317,8 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_ass(STREAMFILE * streamFile);
-VGMSTREAM * init_vgmstream_waa_wac_wad_wam(STREAMFILE * streamFile);
+VGMSTREAM * init_vgmstream_ubi_jade(STREAMFILE * streamFile);
+VGMSTREAM * init_vgmstream_ubi_jade_container(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_seg(STREAMFILE * streamFile);
@@ -478,7 +477,7 @@ VGMSTREAM * init_vgmstream_ps2_khv(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_pc_smp(STREAMFILE* streamFile);
-VGMSTREAM * init_vgmstream_ngc_bo2(STREAMFILE* streamFile);
+VGMSTREAM * init_vgmstream_ngc_rkv(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_dsp_ddsp(STREAMFILE* streamFile);
@@ -623,8 +622,8 @@ VGMSTREAM * init_vgmstream_x360_cxs(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_dsp_adx(STREAMFILE *streamFile);
-VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile);
-VGMSTREAM * init_vgmstream_akb2_multi(STREAMFILE *streamFile);
+VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile);
+VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_x360_ast(STREAMFILE *streamFile);
@@ -647,6 +646,7 @@ VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ta_aac_x360(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ta_aac_ps3(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ta_aac_mobile(STREAMFILE *streamFile);
+VGMSTREAM * init_vgmstream_ta_aac_mobile_vorbis(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ps3_mta2(STREAMFILE *streamFile);
@@ -669,7 +669,10 @@ VGMSTREAM * init_vgmstream_stm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_awc(STREAMFILE * streamFile);
-VGMSTREAM * init_vgmstream_nsw_opus(STREAMFILE * streamFile);
+VGMSTREAM * init_vgmstream_opus_std(STREAMFILE * streamFile);
+VGMSTREAM * init_vgmstream_opus_n1(STREAMFILE * streamFile);
+VGMSTREAM * init_vgmstream_opus_capcom(STREAMFILE * streamFile);
+VGMSTREAM * init_vgmstream_opus_nop(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_pc_al2(STREAMFILE * streamFile);
@@ -699,11 +702,52 @@ VGMSTREAM * init_vgmstream_fsb_encrypted(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_xwc(STREAMFILE *streamFile);
-VGMSTREAM * init_vgmstream_atsl3(STREAMFILE *streamFile);
+VGMSTREAM * init_vgmstream_atsl(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sps_n1(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_atx(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile);
+
+VGMSTREAM * init_vgmstream_waf(STREAMFILE * streamFile);
+
+VGMSTREAM * init_vgmstream_wave(STREAMFILE * streamFile);
+
+VGMSTREAM * init_vgmstream_wave_segmented(STREAMFILE * streamFile);
+
+VGMSTREAM * init_vgmstream_smv(STREAMFILE * streamFile);
+
+VGMSTREAM * init_vgmstream_nxap(STREAMFILE * streamFile);
+
+VGMSTREAM * init_vgmstream_ea_wve_au00(STREAMFILE * streamFile);
+
+VGMSTREAM * init_vgmstream_ea_wve_ad10(STREAMFILE * streamFile);
+
+VGMSTREAM * init_vgmstream_sthd(STREAMFILE * streamFile);
+
+VGMSTREAM * init_vgmstream_ngc_dsp_std_le(STREAMFILE *streamFile);
+
+VGMSTREAM * init_vgmstream_pcm_sre(STREAMFILE *streamFile);
+
+VGMSTREAM * init_vgmstream_dsp_mcadpcm(STREAMFILE *streamFile);
+
+VGMSTREAM * init_vgmstream_ubi_lyn(STREAMFILE * streamFile);
+VGMSTREAM * init_vgmstream_ubi_lyn_container(STREAMFILE * streamFile);
+
+VGMSTREAM * init_vgmstream_msb_msh(STREAMFILE * streamFile);
+
+VGMSTREAM * init_vgmstream_txtp(STREAMFILE * streamFile);
+
+VGMSTREAM * init_vgmstream_smc_smh(STREAMFILE * streamFile);
+
+VGMSTREAM * init_vgmstream_ea_sps_fb(STREAMFILE *streamFile);
+
+VGMSTREAM * init_vgmstream_ppst(STREAMFILE *streamFile);
+
+VGMSTREAM * init_vgmstream_opus_ppp(STREAMFILE *streamFile);
+
+VGMSTREAM * init_vgmstream_ubi_bao_pk(STREAMFILE *streamFile);
+
+VGMSTREAM * init_vgmstream_dsp_switch_audio(STREAMFILE *streamFile);
#endif /*_META_H*/
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mogg.c b/Frameworks/vgmstream/vgmstream/src/meta/mogg.c
index d14e7e1a7..9054d2350 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/mogg.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/mogg.c
@@ -1,9 +1,9 @@
/*
2017-12-10: Preliminary MOGG Support. As long as the stream is unencrypted, this should be fine.
- This will also work on unconventional 5 channel Vorbis streams but some sound cards might not like it.
- TODO (Eventually): Add decryption for encrypted MOGG types (Rock Band, etc.)
+ This will also work on unconventional 5 channel Vorbis streams but some sound cards might not like it.
+ TODO (Eventually): Add decryption for encrypted MOGG types (Rock Band, etc.)
- -bxaimc
+ -bxaimc
*/
#include "meta.h"
@@ -12,31 +12,28 @@
/* MOGG - Harmonix Music Systems (Guitar Hero)[Unencrypted Type] */
VGMSTREAM * init_vgmstream_mogg(STREAMFILE *streamFile) {
#ifdef VGM_USE_VORBIS
- char filename[PATH_LIMIT];
- off_t start_offset;
+ off_t start_offset;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile, filename, sizeof(filename));
- if (strcasecmp("mogg", filename_extension(filename))) goto fail;
+ /* checks */
+ if (!check_extensions(streamFile, "mogg"))
+ goto fail;
- {
- vgm_vorbis_info_t inf;
- VGMSTREAM * result = NULL;
+ {
+ ogg_vorbis_meta_info_t ovmi = {0};
+ VGMSTREAM * result = NULL;
- memset(&inf, 0, sizeof(inf));
- inf.layout_type = layout_ogg_vorbis;
- inf.meta_type = meta_MOGG;
+ ovmi.meta_type = meta_MOGG;
- start_offset = read_32bitLE(0x04, streamFile);
- result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf);
+ start_offset = read_32bitLE(0x04, streamFile);
+ result = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
- if (result != NULL) {
- return result;
- }
- }
+ if (result != NULL) {
+ return result;
+ }
+ }
fail:
- /* clean up anything we may have opened */
+ /* clean up anything we may have opened */
#endif
- return NULL;
-}
\ No newline at end of file
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mp4.c b/Frameworks/vgmstream/vgmstream/src/meta/mp4.c
index ee8e56c7b..ac53aa53e 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/mp4.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/mp4.c
@@ -181,8 +181,9 @@ VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE *streamFile) {
/* check extension, case insensitive */
- /* .bin: Final Fantasy Dimensions (iOS), Final Fantasy V (iOS) */
- if (!check_extensions(streamFile,"mp4,m4a,m4v,lmp4,bin"))
+ /* .bin: Final Fantasy Dimensions (iOS), Final Fantasy V (iOS)
+ * .msd: UNO (iOS) */
+ if (!check_extensions(streamFile,"mp4,m4a,m4v,lmp4,bin,msd"))
goto fail;
filesize = streamFile->get_size(streamFile);
@@ -239,7 +240,7 @@ VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE *streamFile) {
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
- vgmstream->meta_type = meta_FFmpeg;
+ vgmstream->meta_type = meta_MP4;
vgmstream->num_samples = ffmpeg_data->totalSamples;
vgmstream->sample_rate = ffmpeg_data->sampleRate;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/msb_msh.c b/Frameworks/vgmstream/vgmstream/src/meta/msb_msh.c
new file mode 100644
index 000000000..0333716f4
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/msb_msh.c
@@ -0,0 +1,85 @@
+#include "meta.h"
+#include "../coding/coding.h"
+
+/* MSB+MSH - Sony sfx container companion of MIH+MIB [namCollection - Ace Combat 2 (PS2) sfx, EyeToy Play (PS2)] */
+VGMSTREAM * init_vgmstream_msb_msh(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ STREAMFILE * streamHeader = NULL;
+ off_t start_offset, header_offset = 0;
+ size_t stream_size;
+ int loop_flag = 0, channel_count, sample_rate;
+ int total_subsongs, target_subsong = streamFile->stream_index;
+
+
+ /* checks */
+ if (!check_extensions(streamFile, "msb"))
+ goto fail;
+
+ streamHeader = open_streamfile_by_ext(streamFile, "msh");
+ if (!streamHeader) goto fail;
+
+ if (read_32bitLE(0x00,streamHeader) != get_streamfile_size(streamHeader))
+ goto fail;
+ /* 0x04: unknown */
+
+ /* parse entries */
+ {
+ int i;
+ int entries = read_32bitLE(0x08,streamHeader);
+
+ total_subsongs = 0;
+ if (target_subsong == 0) target_subsong = 1;
+
+ for (i = 0; i < entries; i++) {
+ if (read_32bitLE(0x0c + 0x10*i, streamHeader) == 0) /* size 0 = empty entry */
+ continue;
+
+ total_subsongs++;
+ if (total_subsongs == target_subsong && !header_offset) {
+ header_offset = 0x0c + 0x10*i;
+ }
+ }
+
+ if (!header_offset) goto fail;
+ if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
+ }
+
+
+
+ loop_flag = 0;
+ channel_count = 1;
+
+ stream_size = read_32bitLE(header_offset+0x00, streamHeader);
+ if (read_32bitLE(header_offset+0x04, streamHeader) != 0) /* stereo flag? */
+ goto fail;
+ start_offset = read_32bitLE(header_offset+0x08, streamHeader);
+ sample_rate = read_32bitLE(header_offset+0x0c, streamHeader); /* Ace Combat 2 seems to set wrong values but probably their bug */
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = sample_rate;
+ vgmstream->num_samples = ps_bytes_to_samples(stream_size,channel_count);
+
+ vgmstream->num_streams = total_subsongs;
+ vgmstream->stream_size = stream_size;
+ vgmstream->meta_type = meta_MSB_MSH;
+
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x10;
+
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
+
+ close_streamfile(streamHeader);
+ return vgmstream;
+
+fail:
+ close_streamfile(streamHeader);
+ close_vgmstream(vgmstream);
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mss.c b/Frameworks/vgmstream/vgmstream/src/meta/mss.c
index c7a1d15e2..e3596daec 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/mss.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/mss.c
@@ -18,7 +18,7 @@ VGMSTREAM * init_vgmstream_mss(STREAMFILE *streamFile) {
loop_flag = 0;
channel_count = read_16bitLE(0x16,streamFile);
- if (read_32bitLE(0x18,streamFile) == 0x4800 && vgmstream->channels > 2)
+ if (read_32bitLE(0x18,streamFile) == 0x4800 && channel_count > 2)
channel_count = 2; //todo add support for interleave stereo streams
/* build the VGMSTREAM */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mus_acm.c b/Frameworks/vgmstream/vgmstream/src/meta/mus_acm.c
index 185e29367..84cfc4e21 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/mus_acm.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/mus_acm.c
@@ -1,7 +1,6 @@
-#include "../vgmstream.h"
#include "meta.h"
-#include "../util.h"
-#include "../streamfile.h"
+#include "../layout/layout.h"
+#include "../coding/coding.h"
#include "../coding/acm_decoder.h"
#include
#include
@@ -13,11 +12,107 @@
#define DIRSEP '/'
#endif
-#define NAME_LENGTH PATH_LIMIT
+
+static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_loop_flag, int *out_loop_start_index, int *out_loop_end_index);
+static void clean_mus(char** mus_filenames, int file_count);
+
+/* .MUS - playlist for InterPlay games [Planescape: Torment (PC), Baldur's Gate Enhanced Edition (PC)] */
+VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ segmented_layout_data *data = NULL;
+
+ int channel_count, loop_flag = 0, loop_start_index = -1, loop_end_index = -1;
+ int32_t num_samples = 0, loop_start_samples = 0, loop_end_samples = 0;
+
+ char** mus_filenames = NULL;
+ int i, segment_count = 0;
+
+
+ /* checks */
+ if (!check_extensions(streamFile, "mus"))
+ goto fail;
+
+ /* get file paths from the .MUS text file */
+ mus_filenames = parse_mus(streamFile, &segment_count, &loop_flag, &loop_start_index, &loop_end_index);
+ if (!mus_filenames) goto fail;
+
+ /* init layout */
+ data = init_layout_segmented(segment_count);
+ if (!data) goto fail;
+
+ /* open each segment subfile */
+ for (i = 0; i < segment_count; i++) {
+ STREAMFILE* temp_streamFile = streamFile->open(streamFile, mus_filenames[i], STREAMFILE_DEFAULT_BUFFER_SIZE);
+ if (!temp_streamFile) goto fail;
+
+ /* find .ACM type */
+ switch(read_32bitBE(0x00,temp_streamFile)) {
+ case 0x97280301: /* ACM header id [Planescape: Torment (PC)] */
+ data->segments[i] = init_vgmstream_acm(temp_streamFile);
+ break;
+ case 0x4F676753: /* "OggS" [Planescape: Torment Enhanced Edition (PC)] */
+ data->segments[i] = init_vgmstream_ogg_vorbis(temp_streamFile);
+ break;
+ default:
+ data->segments[i] = NULL;
+ break;
+ }
+ close_streamfile(temp_streamFile);
+
+ if (!data->segments[i]) goto fail;
+
+
+ if (i==loop_start_index)
+ loop_start_samples = num_samples;
+ if (i==loop_end_index)
+ loop_end_samples = num_samples;
+
+ num_samples += data->segments[i]->num_samples;
+ }
+
+ if (i==loop_end_index)
+ loop_end_samples = num_samples;
+
+ /* setup segmented VGMSTREAMs */
+ if (!setup_layout_segmented(data))
+ goto fail;
+
+
+ channel_count = data->segments[0]->channels;
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = data->segments[0]->sample_rate;
+ vgmstream->num_samples = num_samples;
+ vgmstream->loop_start_sample = loop_start_samples;
+ vgmstream->loop_end_sample = loop_end_samples;
+
+ vgmstream->meta_type = meta_MUS_ACM;
+ vgmstream->coding_type = data->segments[0]->coding_type;
+ vgmstream->layout_type = layout_segmented;
+
+ vgmstream->layout_data = data;
+ data->loop_segment = loop_start_index;
+
+ clean_mus(mus_filenames, segment_count);
+ return vgmstream;
+
+fail:
+ clean_mus(mus_filenames, segment_count);
+ free_layout_segmented(data);
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+/* .mus text file parsing */
+
+#define NAME_LENGTH PATH_LIMIT
static int exists(char *filename, STREAMFILE *streamfile) {
- STREAMFILE * temp =
- streamfile->open(streamfile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
+ STREAMFILE * temp = streamfile->open(streamfile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!temp) return 0;
close_streamfile(temp);
@@ -91,57 +186,40 @@ fail:
return 1;
}
-/* MUS playlist for InterPlay ACM */
-VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- ACMStream *acm_stream = NULL;
- mus_acm_codec_data *data = NULL;
+static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_loop_flag, int *out_loop_start_index, int *out_loop_end_index) {
+ char** names = NULL;
char filename[NAME_LENGTH];
char line_buffer[NAME_LENGTH];
char * end_ptr;
char name_base[NAME_LENGTH];
- char (*names)[NAME_LENGTH] = NULL;
char dir_name[NAME_LENGTH];
char subdir_name[NAME_LENGTH];
- int i;
- int loop_flag = 0;
- int channel_count;
int file_count;
size_t line_bytes;
int whole_line_read = 0;
off_t mus_offset = 0;
- int loop_end_index = -1;
- int loop_start_index = -1;
- int32_t loop_start_samples = -1;
- int32_t loop_end_samples = -1;
+ int i;
+ int loop_flag = 0, loop_start_index = -1, loop_end_index = -1;
- int32_t total_samples = 0;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("mus",filename_extension(filename))) goto fail;
/* read file name base */
- line_bytes = get_streamfile_text_line(sizeof(line_buffer),line_buffer,
- mus_offset, streamFile, &whole_line_read);
+ line_bytes = get_streamfile_text_line(sizeof(line_buffer),line_buffer, mus_offset, streamFile, &whole_line_read);
if (!whole_line_read) goto fail;
mus_offset += line_bytes;
memcpy(name_base,line_buffer,sizeof(name_base));
/* uppercase name_base */
{
- int i;
- for (i=0;name_base[i];i++) name_base[i]=toupper(name_base[i]);
+ int j;
+ for (j=0;name_base[j];j++)
+ name_base[j] = toupper(name_base[j]);
}
- /*printf("name base: %s\n",name_base);*/
-
/* read track entry count */
- line_bytes = get_streamfile_text_line(sizeof(line_buffer),line_buffer,
- mus_offset, streamFile, &whole_line_read);
+ line_bytes = get_streamfile_text_line(sizeof(line_buffer),line_buffer, mus_offset, streamFile, &whole_line_read);
if (!whole_line_read) goto fail;
if (line_buffer[0] == '\0') goto fail;
mus_offset += line_bytes;
@@ -149,24 +227,26 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
/* didn't parse whole line as an integer (optional opening whitespace) */
if (*end_ptr != '\0') goto fail;
- /*printf("entries: %d\n",file_count);*/
-
- names = calloc(file_count,sizeof(names[0]));
+ /* set names */
+ names = calloc(file_count,sizeof(char*)); /* array of strings (size NAME_LENGTH) */
if (!names) goto fail;
+ for (i = 0; i < file_count; i++) {
+ names[i] = calloc(1,sizeof(char)*NAME_LENGTH);
+ if (!names[i]) goto fail;
+ }
+
dir_name[0]='\0';
+ streamFile->get_name(streamFile,filename,sizeof(filename));
concatn(sizeof(dir_name),dir_name,filename);
+ /* find directory name for the directory contianing the MUS */
{
- /* find directory name for the directory contianing the MUS */
- char * last_slash;
- last_slash = strrchr(dir_name,DIRSEP);
+ char * last_slash = strrchr(dir_name,DIRSEP);
if (last_slash != NULL) {
- /* trim off the file name */
- last_slash[1]='\0';
+ last_slash[1]='\0'; /* trim off the file name */
} else {
- /* no dir name? annihilate! */
- dir_name[0] = '\0';
+ dir_name[0] = '\0'; /* no dir name? annihilate! */
}
}
@@ -180,7 +260,8 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
char loop_name_temp[NAME_LENGTH];
char loop_name_base[NAME_LENGTH];
char loop_name[NAME_LENGTH];
- for (i=0;ifiles = calloc(file_count,sizeof(ACMStream *));
- if (!data->files) {
- free(data); data = NULL;
- goto fail;
- }
- /* open each file... */
- for (i=0;ifiles[i]=acm_stream;
-
- if (i==loop_start_index) loop_start_samples = total_samples;
- if (i==loop_end_index) loop_end_samples = total_samples;
-
- total_samples += acm_stream->total_values / acm_stream->info.channels;
-
- if (i>0) {
- if (acm_stream->info.channels != data->files[0]->info.channels ||
- acm_stream->info.rate != data->files[0]->info.rate) goto fail;
- }
- }
-
- if (i==loop_end_index) loop_end_samples = total_samples;
-
- channel_count = data->files[0]->info.channels;
- vgmstream = allocate_vgmstream(channel_count,loop_flag);
- if (!vgmstream) goto fail;
-
- vgmstream->channels = channel_count;
- vgmstream->sample_rate = data->files[0]->info.rate;
- vgmstream->coding_type = coding_ACM;
- vgmstream->num_samples = total_samples;
- vgmstream->loop_start_sample = loop_start_samples;
- vgmstream->loop_end_sample = loop_end_samples;
- vgmstream->layout_type = layout_mus_acm;
- vgmstream->meta_type = meta_MUS_ACM;
-
- data->file_count = file_count;
- data->current_file = 0;
- data->loop_start_file = loop_start_index;
- data->loop_end_file = loop_end_index;
- /*data->end_file = -1;*/
-
- vgmstream->codec_data = data;
-
- free(names);
-
- return vgmstream;
-
- /* clean up anything we may have opened */
+ return names;
fail:
- if (data) {
- int i;
- for (i=0;ifile_count;i++) {
- if (data->files[i]) {
- acm_close(data->files[i]);
- data->files[i] = NULL;
- }
- }
- }
- if (names) free(names);
- if (vgmstream) close_vgmstream(vgmstream);
+ clean_mus(names, file_count);
return NULL;
}
+
+static void clean_mus(char** mus_filenames, int file_count) {
+ int i;
+
+ if (!mus_filenames) return;
+
+ for (i = 0; i < file_count; i++) {
+ free(mus_filenames[i]);
+ }
+ free(mus_filenames);
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/musx.c b/Frameworks/vgmstream/vgmstream/src/meta/musx.c
index e174b4b2c..b3f211fdd 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/musx.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/musx.c
@@ -2,278 +2,243 @@
#include "../util.h"
-/* MUSX (Version 004) --------------------------------------->*/
+/* MUSX (Version 004) */
VGMSTREAM * init_vgmstream_musx_v004(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- int loop_flag;
- int channel_count;
off_t start_offset;
+ int loop_flag, channel_count;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("musx",filename_extension(filename))) goto fail;
- /* check header */
+ /* checks */
+ if (!check_extensions(streamFile, "musx"))
+ goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */
- goto fail;
- if (read_32bitBE(0x08,streamFile) != 0x04000000) /* "0x04000000" */
- goto fail;
+ goto fail;
+ if (read_32bitBE(0x08,streamFile) != 0x04000000)
+ goto fail;
loop_flag = (read_32bitLE(0x840,streamFile) != 0xFFFFFFFF);
channel_count = 2;
- /* build the VGMSTREAM */
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- switch (read_32bitBE(0x10,streamFile))
- {
- case 0x5053325F: /* PS2_ */
- start_offset = read_32bitLE(0x28,streamFile);
- vgmstream->channels = channel_count;
- vgmstream->sample_rate = 32000;
- vgmstream->coding_type = coding_PSX; // PS2 ADPCM
- vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))/16/channel_count*28;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = 0x80;
- if (loop_flag)
- {
- vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))/16/channel_count*28;
- vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))/16/channel_count*28;
- }
- break;
- case 0x47435F5F: /* GC__ */
- start_offset = read_32bitBE(0x28,streamFile);
- vgmstream->channels = channel_count;
- vgmstream->sample_rate = 32000;
- vgmstream->coding_type = coding_DAT4_IMA; // Eurocom DAT4 4-bit IMA ADPCM
- vgmstream->num_samples = (read_32bitBE(0x2C,streamFile))/16/channel_count*28;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = 0x20;
- if (loop_flag)
- {
- vgmstream->loop_start_sample = (read_32bitBE(0x890,streamFile))/16/channel_count*28;
- vgmstream->loop_end_sample = (read_32bitBE(0x89C,streamFile))/16/channel_count*28;
- }
- break;
- case 0x58425F5F: /* XB__ */
- start_offset = read_32bitLE(0x28,streamFile);
- vgmstream->channels = channel_count;
- vgmstream->sample_rate = 44100;
- vgmstream->coding_type = coding_DAT4_IMA; // Eurocom DAT4 4-bit IMA ADPCM
- vgmstream->num_samples = (read_32bitLE(0x2C,streamFile))/16/channel_count*28;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = 0x20;
- if (loop_flag)
- {
- vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))/16/channel_count*28;
- vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))/16/channel_count*28;
- }
- break;
+ switch (read_32bitBE(0x10,streamFile)) {
+ case 0x5053325F: /* PS2_ */
+ start_offset = read_32bitLE(0x28,streamFile);
+ vgmstream->channels = channel_count;
+ vgmstream->sample_rate = 32000;
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))/16/channel_count*28;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x80;
+ if (loop_flag) {
+ vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))/16/channel_count*28;
+ vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))/16/channel_count*28;
+ }
+ break;
+ case 0x47435F5F: /* GC__ */
+ start_offset = read_32bitBE(0x28,streamFile);
+ vgmstream->channels = channel_count;
+ vgmstream->sample_rate = 32000;
+ vgmstream->coding_type = coding_DAT4_IMA;
+ vgmstream->num_samples = (read_32bitBE(0x2C,streamFile))/16/channel_count*28;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x20;
+ if (loop_flag) {
+ vgmstream->loop_start_sample = (read_32bitBE(0x890,streamFile))/16/channel_count*28;
+ vgmstream->loop_end_sample = (read_32bitBE(0x89C,streamFile))/16/channel_count*28;
+ }
+ break;
+ case 0x58425F5F: /* XB__ */
+ start_offset = read_32bitLE(0x28,streamFile);
+ vgmstream->channels = channel_count;
+ vgmstream->sample_rate = 44100;
+ vgmstream->coding_type = coding_DAT4_IMA;
+ vgmstream->num_samples = (read_32bitLE(0x2C,streamFile))/16/channel_count*28;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x20;
+ if (loop_flag) {
+ vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))/16/channel_count*28;
+ vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))/16/channel_count*28;
+ }
+ break;
default:
- goto fail;
+ goto fail;
}
vgmstream->meta_type = meta_MUSX_V004;
- /* open the file for reading */
- {
- int i;
- STREAMFILE * file;
- file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!file) goto fail;
- for (i=0;ich[i].streamfile = file;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=start_offset+
- vgmstream->interleave_block_size*i;
- }
- }
-
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
-/* <--------------------------------------- MUSX (Version 004) */
-/* MUSX (Version 005) --------------------------------------->*/
+/* MUSX (Version 005) [Predator: Concrete Jungle (PS2/Xbox) ] */
VGMSTREAM * init_vgmstream_musx_v005(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- int loop_flag;
- int channel_count;
off_t start_offset;
+ int loop_flag, channel_count;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("musx",filename_extension(filename))) goto fail;
- /* check header */
+ /* checks */
+ /* .sfx: Batman Begins, .musx: header id */
+ if (!check_extensions(streamFile, "musx,sfx"))
+ goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */
- goto fail;
- if (read_32bitBE(0x08,streamFile) != 0x05000000) /* "0x04000000" */
- goto fail;
+ goto fail;
+ if (read_32bitBE(0x08,streamFile) != 0x05000000)
+ goto fail;
loop_flag = (read_32bitLE(0x840,streamFile) != 0xFFFFFFFF);
channel_count = 2;
- /* build the VGMSTREAM */
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- switch (read_32bitBE(0x10,streamFile))
- {
- case 0x47435F5F: /* GC__ */
- start_offset = read_32bitBE(0x28,streamFile);
- vgmstream->channels = channel_count;
- vgmstream->sample_rate = 32000;
- vgmstream->coding_type = coding_DAT4_IMA; // Eurocom DAT4 4-bit IMA ADPCM
- vgmstream->num_samples = (read_32bitBE(0x2C,streamFile))/16/channel_count*28;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = 0x20;
- if (loop_flag)
- {
- vgmstream->loop_start_sample = (read_32bitBE(0x890,streamFile))/16/channel_count*28;
- vgmstream->loop_end_sample = (read_32bitBE(0x89C,streamFile))/16/channel_count*28;
- }
- break;
+ switch (read_32bitBE(0x10,streamFile)) {
+ case 0x5053325F: /* PS2_ */
+ start_offset = read_32bitLE(0x28,streamFile);
+ vgmstream->channels = channel_count;
+ vgmstream->sample_rate = 32000;
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))/16/channel_count*28;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x80;
+ if (loop_flag) {
+ vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))/16/channel_count*28;
+ vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))/16/channel_count*28;
+ }
+ break;
+ case 0x47435F5F: /* GC__ */
+ start_offset = read_32bitBE(0x28,streamFile);
+ vgmstream->channels = channel_count;
+ vgmstream->sample_rate = 32000;
+ vgmstream->coding_type = coding_DAT4_IMA;
+ vgmstream->num_samples = (read_32bitBE(0x2C,streamFile))/16/channel_count*28;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x20;
+ if (loop_flag) {
+ vgmstream->loop_start_sample = (read_32bitBE(0x890,streamFile))/16/channel_count*28;
+ vgmstream->loop_end_sample = (read_32bitBE(0x89C,streamFile))/16/channel_count*28;
+ }
+ break;
+ case 0x58425F5F: /* XB__ */
+ start_offset = read_32bitLE(0x28,streamFile);
+ vgmstream->channels = channel_count;
+ vgmstream->sample_rate = 44100;
+ vgmstream->coding_type = coding_DAT4_IMA;
+ vgmstream->num_samples = (read_32bitLE(0x2C,streamFile))/16/channel_count*28;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x20;
+ if (loop_flag) {
+ vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))/16/channel_count*28;
+ vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))/16/channel_count*28;
+ }
+ break;
default:
- goto fail;
+ goto fail;
}
vgmstream->meta_type = meta_MUSX_V005;
-
- /* open the file for reading */
- {
- int i;
- STREAMFILE * file;
- file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!file) goto fail;
- for (i=0;ich[i].streamfile = file;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=start_offset+
- vgmstream->interleave_block_size*i;
- }
- }
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
-/* <--------------------------------------- MUSX (Version 005) */
-
-/* MUSX (Version 006) ---------------------------------------> */
+/* MUSX (Version 006) [Batman Begins (GC)] */
VGMSTREAM * init_vgmstream_musx_v006(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- int loop_flag;
- int channel_count;
off_t start_offset;
+ int loop_flag, channel_count;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("musx",filename_extension(filename))) goto fail;
- /* check header */
+ /* checks */
+ /* .sfx: Batman Begins, .musx: header id */
+ if (!check_extensions(streamFile, "sfx,musx"))
+ goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */
- goto fail;
-
- if (read_32bitBE(0x08,streamFile) != 0x06000000) /* "0x06000000" */
- goto fail;
+ goto fail;
+ if (read_32bitBE(0x08,streamFile) != 0x06000000)
+ goto fail;
loop_flag = (read_32bitLE(0x840,streamFile)!=0xFFFFFFFF);
channel_count = 2;
- /* build the VGMSTREAM */
+ //todo some files (ex. Batman Begins) have a subsong table at 0x800, not sure what signals it (flags at 0x04/0x14?)
+
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
- if (!vgmstream) goto fail;
+ if (!vgmstream) goto fail;
- /* fill in the vital statistics */
- switch (read_32bitBE(0x10,streamFile))
- {
- case 0x5053325F: /* PS2_ */
- start_offset = read_32bitLE(0x28,streamFile);
- vgmstream->channels = channel_count;
- vgmstream->sample_rate = 32000;
- vgmstream->coding_type = coding_PSX;
- vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))*28/16/channel_count;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = 0x80;
- vgmstream->meta_type = meta_MUSX_V006;
- if (loop_flag)
- {
- vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))*28/16/channel_count;
- vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))*28/16/channel_count;
- }
- break;
- case 0x47435F5F: /* GC__ */
- start_offset = read_32bitBE(0x28,streamFile);
- vgmstream->channels = channel_count;
- vgmstream->sample_rate = 32000;
- vgmstream->coding_type = coding_DAT4_IMA;
- vgmstream->num_samples = (read_32bitBE(0x2C,streamFile))*28/16/channel_count;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = 0x20;
- vgmstream->meta_type = meta_MUSX_V006;
- if (loop_flag)
- {
- vgmstream->loop_start_sample = (read_32bitBE(0x890,streamFile))*28/16/channel_count;
- vgmstream->loop_end_sample = (read_32bitBE(0x89C,streamFile))*28/16/channel_count;
- }
- break;
- default:
- goto fail;
+ switch (read_32bitBE(0x10,streamFile)) {
+ case 0x5053325F: /* PS2_ */
+ start_offset = read_32bitLE(0x28,streamFile);
+ vgmstream->channels = channel_count;
+ vgmstream->sample_rate = 32000;
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))*28/16/channel_count;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x80;
+ vgmstream->meta_type = meta_MUSX_V006;
+ if (loop_flag) {
+ vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))*28/16/channel_count;
+ vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))*28/16/channel_count;
+ }
+ break;
+ case 0x47435F5F: /* GC__ */
+ start_offset = read_32bitBE(0x28,streamFile);
+ if (start_offset == 0 || start_offset == 0xABABABAB) goto fail; /* some are empty */
+
+ vgmstream->channels = channel_count;
+ vgmstream->sample_rate = 32000;
+ vgmstream->coding_type = coding_DAT4_IMA;
+ vgmstream->num_samples = (read_32bitBE(0x2C,streamFile))*28/16/channel_count;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x20;
+ vgmstream->meta_type = meta_MUSX_V006;
+ if (loop_flag) {
+ vgmstream->loop_start_sample = (read_32bitBE(0x890,streamFile))*28/16/channel_count;
+ vgmstream->loop_end_sample = (read_32bitBE(0x89C,streamFile))*28/16/channel_count;
+ }
+ break;
+ default:
+ goto fail;
}
- /* open the file for reading */
- {
- int i;
- STREAMFILE * file;
- file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!file) goto fail;
- for (i=0;ich[i].streamfile = file;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=start_offset+
- vgmstream->interleave_block_size*i;
-
- }
- }
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
-/* <--------------------------------------- MUSX (Version 006) */
-/* MUSX (Version 010) --------------------------------------->*/
-/* WII_ in Dead Space: Extraction */
+/* MUSX (Version 010) [Dead Space: Extraction (Wii), Rio (PS3), Pirates of the Caribbean: At World's End (PSP)] */
VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
- int musx_type; /* determining the decoder by strings like "PS2_", "GC__" and so on */
- //int musx_version; /* 0x08 provides a "version" byte */
- int loop_flag = 0;
- int channel_count;
+ int musx_type; /* determining the decoder by strings like "PS2_", "GC__" and so on */
+ //int musx_version; /* 0x08 provides a "version" byte */
+ int loop_flag = 0;
+ int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
@@ -281,17 +246,17 @@ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */
- goto fail;
+ goto fail;
if (read_32bitBE(0x800,streamFile) == 0x53424E4B) /* "SBNK", */ // SoundBank, refuse
- goto fail;
- if (read_32bitBE(0x08,streamFile) != 0x0A000000) /* "0x0A000000" */
- goto fail;
+ goto fail;
+ if (read_32bitBE(0x08,streamFile) != 0x0A000000) /* "0x0A000000" */
+ goto fail;
- loop_flag = ((read_32bitLE(0x34,streamFile)!=0x00000000) &&
- (read_32bitLE(0x34,streamFile)!=0xABABABAB));
+ loop_flag = ((read_32bitLE(0x34,streamFile)!=0x00000000) &&
+ (read_32bitLE(0x34,streamFile)!=0xABABABAB));
channel_count = 2;
- musx_type=(read_32bitBE(0x10,streamFile));
+ musx_type=(read_32bitBE(0x10,streamFile));
if (musx_type == 0x5749495F && /* WII_ */
(read_16bitBE(0x40,streamFile) == 0x4441) && /* DA */
@@ -300,7 +265,7 @@ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
channel_count = read_32bitLE(0x48,streamFile);
loop_flag = (read_32bitLE(0x64,streamFile) != -1);
}
- if (musx_type == 0x5053335F && /* PS3_ */
+ if (musx_type == 0x5053335F && /* PS3_ */
(read_16bitBE(0x40,streamFile) == 0x4441) && /* DA */
(read_8bit(0x42,streamFile) == 0x54)) /* T */
{
@@ -312,11 +277,11 @@ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
loop_flag = 0;
}
- /* build the VGMSTREAM */
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
+
+ /* fill in the vital statistics */
switch (musx_type) {
case 0x5053325F: /* PS2_ */
start_offset = 0x800;
@@ -351,24 +316,24 @@ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
vgmstream->interleave_block_size = 0x20;
vgmstream->meta_type = meta_MUSX_V010;
- if (read_32bitBE(0x40,streamFile)==0x44415438){
+ if (read_32bitBE(0x40,streamFile)==0x44415438){
vgmstream->num_samples = read_32bitLE(0x60,streamFile);
- vgmstream->sample_rate = read_32bitLE(0x4C,streamFile);
- if (loop_flag)
+ vgmstream->sample_rate = read_32bitLE(0x4C,streamFile);
+ if (loop_flag)
{
vgmstream->loop_start_sample = read_32bitLE(0x64,streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x60,streamFile);
}
- }
- else {
- vgmstream->sample_rate = 44100;
- vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)/2/(0x20)*((0x20-4)*2);
- if (loop_flag)
+ }
+ else {
+ vgmstream->sample_rate = 44100;
+ vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)/2/(0x20)*((0x20-4)*2);
+ if (loop_flag)
{
vgmstream->loop_start_sample = read_32bitLE(0x44,streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x40,streamFile);
}
- }
+ }
break;
case 0x5749495F: /* WII_ */
start_offset = 0x800;
@@ -377,7 +342,7 @@ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
switch (read_32bitBE(0x40,streamFile))
{
case 0x44415434: /* DAT4 */
- case 0x44415438: /* DAT8 */
+ case 0x44415438: /* DAT8 [GoldenEye 007 (Wii)] */
vgmstream->coding_type = coding_DAT4_IMA;
break;
default:
@@ -406,7 +371,7 @@ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
break;
default:
goto fail;
- }
+ }
/* open the file for reading */
{
@@ -426,79 +391,78 @@ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
-/* <--------------------------------------- MUSX (Version 010) */
-/* MUSX (Version 201) --------------------------------------->*/
+/* MUSX (Version 201) */
VGMSTREAM * init_vgmstream_musx_v201(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
- //int musx_version; /* 0x08 provides a "version" byte */
- int loop_flag;
- int channel_count;
- int loop_detect;
- int loop_offsets;
-
+ //int musx_version; /* 0x08 provides a "version" byte */
+ int loop_flag;
+ int channel_count;
+ int loop_detect;
+ int loop_offsets;
+
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("musx",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */
- goto fail;
- if ((read_32bitBE(0x08,streamFile) != 0xC9000000) &&
- (read_32bitLE(0x08,streamFile) != 0xC9000000)) /* "0xC9000000" */
- goto fail;
+ goto fail;
+ if ((read_32bitBE(0x08,streamFile) != 0xC9000000) &&
+ (read_32bitLE(0x08,streamFile) != 0xC9000000)) /* "0xC9000000" */
+ goto fail;
channel_count = 2;
- loop_detect = read_32bitBE(0x800,streamFile);
- switch (loop_detect) {
- case 0x02000000:
- loop_offsets = 0x8E0;
- break;
- case 0x03000000:
- loop_offsets = 0x880;
- break;
- case 0x04000000:
- loop_offsets = 0x8B4;
- break;
- case 0x05000000:
- loop_offsets = 0x8E8;
- break;
- case 0x06000000:
- loop_offsets = 0x91C;
- break;
- default:
- goto fail;
- }
+ loop_detect = read_32bitBE(0x800,streamFile);
+ switch (loop_detect) {
+ case 0x02000000:
+ loop_offsets = 0x8E0;
+ break;
+ case 0x03000000:
+ loop_offsets = 0x880;
+ break;
+ case 0x04000000:
+ loop_offsets = 0x8B4;
+ break;
+ case 0x05000000:
+ loop_offsets = 0x8E8;
+ break;
+ case 0x06000000:
+ loop_offsets = 0x91C;
+ break;
+ default:
+ goto fail;
+ }
- loop_flag = (read_32bitLE(loop_offsets+0x04,streamFile) !=0x00000000);
+ loop_flag = (read_32bitLE(loop_offsets+0x04,streamFile) !=0x00000000);
+ start_offset = read_32bitLE(0x18,streamFile);
- /* build the VGMSTREAM */
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- /* fill in the vital statistics */
- start_offset = read_32bitLE(0x18,streamFile);
- vgmstream->channels = channel_count;
- vgmstream->sample_rate = 32000;
- vgmstream->coding_type = coding_PSX;
- vgmstream->num_samples = read_32bitLE(loop_offsets,streamFile)*28/16/channel_count;
- if (loop_flag) {
- vgmstream->loop_start_sample = read_32bitLE(loop_offsets+0x10,streamFile)*28/16/channel_count;
- vgmstream->loop_end_sample = read_32bitLE(loop_offsets,streamFile)*28/16/channel_count;
- }
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = 0x80;
- vgmstream->meta_type = meta_MUSX_V201;
-
+ {
+ vgmstream->channels = channel_count;
+ vgmstream->sample_rate = 32000;
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->num_samples = read_32bitLE(loop_offsets,streamFile)*28/16/channel_count;
+ if (loop_flag) {
+ vgmstream->loop_start_sample = read_32bitLE(loop_offsets+0x10,streamFile)*28/16/channel_count;
+ vgmstream->loop_end_sample = read_32bitLE(loop_offsets,streamFile)*28/16/channel_count;
+ }
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x80;
+ vgmstream->meta_type = meta_MUSX_V201;
+ }
+
/* open the file for reading */
{
int i;
@@ -517,9 +481,7 @@ VGMSTREAM * init_vgmstream_musx_v201(STREAMFILE *streamFile) {
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
-/* <--------------------------------------- MUSX (Version 201) */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/naomi_adpcm.c b/Frameworks/vgmstream/vgmstream/src/meta/naomi_adpcm.c
index 7ca6ec969..764f3a1b1 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/naomi_adpcm.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/naomi_adpcm.c
@@ -1,67 +1,44 @@
#include "meta.h"
-#include "../util.h"
+#include "../coding/coding.h"
-/* ADPCM (from NAOMI/NAOMI2 Arcade games) */
+/* ADPCM - from NAOMI/NAOMI2 Arcade games [F355 Challenge (Naomi)] */
VGMSTREAM * init_vgmstream_naomi_adpcm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
off_t start_offset;
- int loop_flag = 0;
- int channel_count;
+ int loop_flag, channel_count;
+ size_t data_size;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("adpcm",filename_extension(filename))) goto fail;
-#if 0
- /* check header */
- if ((read_32bitBE(0x00,streamFile) != 0x41445043) || /* "ADPC" */
- (read_32bitBE(0x04,streamFile) != 0x41445043)) /* "M_v0" */
- goto fail;
-#endif
+ /* checks */
+ if (!check_extensions(streamFile, "adpcm"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x41445043 || /* "ADPC" */
+ read_32bitBE(0x04,streamFile) != 0x4D5F7630) /* "M_v0" */
+ goto fail;
+ /* there is some kind of info in the end padding, loop related? */
loop_flag = 0;
channel_count = 2;
-
- /* build the VGMSTREAM */
+ start_offset = 0x40;
+ data_size = read_32bitLE(0x10,streamFile) * 0x100; /* data has padding */
+
+ /* 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 = 44100;
- vgmstream->coding_type = coding_AICA;
- vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset);
- if (loop_flag) {
- vgmstream->loop_start_sample = 0;
- vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset);
- }
+ vgmstream->num_samples = aica_bytes_to_samples(data_size, channel_count);
+ vgmstream->coding_type = coding_AICA_int;
vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile) * 0x80;
+ vgmstream->interleave_block_size = data_size / channel_count;
vgmstream->meta_type = meta_NAOMI_ADPCM;
- /* 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->ch[i].adpcm_step_index = 0x7f; /* AICA */
- }
- }
-
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/naomi_spsd.c b/Frameworks/vgmstream/vgmstream/src/meta/naomi_spsd.c
index d8d683cd5..5780774b4 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/naomi_spsd.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/naomi_spsd.c
@@ -1,88 +1,112 @@
#include "meta.h"
-#include "../util.h"
+#include "../coding/coding.h"
-/* SPSD (Guilty Gear X [NAOMI GD-ROM]) */
+/* SPSD - Naomi (arcade) streams [Guilty Gear X (Naomi), Crazy Taxi (Naomi), Virtua Tennis 2 (Naomi)] */
VGMSTREAM * init_vgmstream_naomi_spsd(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
off_t start_offset;
- int coding;
- int loop_flag;
- int channel_count;
+ size_t data_size;
+ int loop_flag, channel_count, codec, flags, index;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("spsd",filename_extension(filename))) goto fail;
- /* check header */
+ /* checks */
+ /* .spsd: header id */
+ if (!check_extensions(streamFile, "spsd"))
+ goto fail;
if (read_32bitBE(0x00,streamFile) != 0x53505344) /* "SPSD" */
goto fail;
- loop_flag = 0;
- channel_count = 2;
-
+ if (read_32bitBE(0x04,streamFile) != 0x01010004 && /* standard version */
+ read_32bitBE(0x04,streamFile) != 0x00010004) /* uncommon version [Crazy Taxi (Naomi)] */
+ goto fail;
+
+
+ codec = read_8bit(0x08,streamFile);
+ flags = read_8bit(0x09,streamFile);
+ index = read_16bitLE(0x0a,streamFile);
+ data_size = read_32bitLE(0x0c,streamFile);
+ //if (data_size + start_offset != get_streamfile_size(streamFile))
+ // goto fail; /* some rips out there have incorrect padding */
+
+ //todo with 0x80 seems 0x2c is a loop_start_sample but must be adjusted to +1 block? (uncommon flag though)
+ loop_flag = (flags & 0x80);
+ channel_count = ((flags & 0x01) || (flags & 0x02)) ? 2 : 1; /* 0x02 is rare but looks normal (Virtua Tennis 2) */
+ start_offset = 0x40;
+
+
/* 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(0x2A,streamFile);
-
- switch (read_8bit(0x8,streamFile))
- {
- case 0x01:
- coding = coding_PCM8;
- break;
- case 0x03:
- coding = coding_AICA;
- break;
- default:
- goto fail;
- }
-
- vgmstream->coding_type = coding;
- vgmstream->num_samples = read_32bitLE(0x0C,streamFile);
-
-#if 0
- if (loop_flag)
- {
- vgmstream->loop_start_sample = 0;
- vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile);
- }
-#endif
-
- vgmstream->interleave_block_size = 0x2000;
- if (channel_count > 1) {
- vgmstream->interleave_smallblock_size = ((get_streamfile_size(streamFile)-start_offset)%(vgmstream->channels*vgmstream->interleave_block_size))/vgmstream->channels;
- vgmstream->layout_type = layout_interleave_shortblock;
- } else {
- vgmstream->layout_type = layout_none;
- }
vgmstream->meta_type = meta_NAOMI_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,channel_count,16);
+ vgmstream->loop_start_sample = read_32bitLE(0x2c,streamFile) + pcm_bytes_to_samples(0x2000*channel_count,channel_count,16);
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+ break;
- /* open the file for reading */
+ case 0x01: /* [Virtua Tennis 2 (Naomi)] */
+ vgmstream->coding_type = coding_PCM8;
+ vgmstream->num_samples = pcm_bytes_to_samples(data_size,channel_count,8);
+ vgmstream->loop_start_sample = read_32bitLE(0x2c,streamFile) + pcm_bytes_to_samples(0x2000*channel_count,channel_count,8);
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+
+ break;
+
+ case 0x03: /* standard */
+ vgmstream->coding_type = coding_AICA_int;
+ vgmstream->num_samples = aica_bytes_to_samples(data_size,channel_count);
+ vgmstream->loop_start_sample = /*read_32bitLE(0x2c,streamFile) +*/ aica_bytes_to_samples(0x2000*channel_count,channel_count);
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+ break;
+
+ default:
+ goto fail;
+ }
+
+ /* interleave index, maybe */
+ switch(index) {
+ case 0x0000:
+ if (channel_count != 1) goto fail;
+ vgmstream->layout_type = layout_none;
+ break;
+
+ case 0x000d:
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x2000;
+ if (vgmstream->interleave_block_size)
+ vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
+ break;
+
+ case 0x00ff:
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = data_size / channel_count;
+ break;
+
+ default:
+ 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;
- 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->ch[i].adpcm_step_index = 0x7f; /* AICA */
+ for (i = 0; i < channel_count; i++) {
+ vgmstream->ch[i].adpcm_step_index = 0x7f;
}
}
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/nds_hwas.c b/Frameworks/vgmstream/vgmstream/src/meta/nds_hwas.c
index e50e614ea..37d78ff22 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/nds_hwas.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/nds_hwas.c
@@ -8,7 +8,8 @@ VGMSTREAM * init_vgmstream_nds_hwas(STREAMFILE *streamFile) {
off_t start_offset;
int channel_count, loop_flag = 0;
- /* check extension, case insensitive (made-up extension) */
+ /* checks */
+ /* .hwas: usually in archives but also found named (ex. Guitar Hero On Tour) */
if (!check_extensions(streamFile,"hwas"))
goto fail;
@@ -34,14 +35,14 @@ VGMSTREAM * init_vgmstream_nds_hwas(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_NDS_HWAS;
vgmstream->coding_type = coding_IMA_int;
- vgmstream->layout_type = layout_hwas_blocked;
+ vgmstream->layout_type = layout_blocked_hwas;
vgmstream->full_block_size = read_32bitLE(0x04,streamFile); /* usually 0x2000, 0x4000 or 0x8000 */
/* open the file for reading by each channel */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
- hwas_block_update(start_offset, vgmstream);
+ block_update_hwas(start_offset, vgmstream);
return vgmstream;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/nds_strm.c b/Frameworks/vgmstream/vgmstream/src/meta/nds_strm.c
index adef717aa..cbd534f5a 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/nds_strm.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/nds_strm.c
@@ -4,103 +4,66 @@
/* STRM - common Nintendo NDS streaming format */
VGMSTREAM * init_vgmstream_nds_strm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
-
- coding_t coding_type;
-
- int codec_number;
- int channel_count;
- int loop_flag;
-
off_t start_offset;
+ int channel_count, loop_flag, codec;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("strm",filename_extension(filename))) goto fail;
- /* check header */
- if ((uint32_t)read_32bitBE(0x00,streamFile)!=0x5354524D) /* STRM */
- goto fail;
- if ((uint32_t)read_32bitBE(0x04,streamFile)!=0xFFFE0001 && /* Old Header Check */
- ((uint32_t)read_32bitBE(0x04,streamFile)!=0xFEFF0001)) /* Some newer games have a new flag */
+ /* checks */
+ if (!check_extensions(streamFile, "strm"))
goto fail;
-
-
- /* check for HEAD section */
- if ((uint32_t)read_32bitBE(0x10,streamFile)!=0x48454144 && /* "HEAD" */
- (uint32_t)read_32bitLE(0x14,streamFile)!=0x50) /* 0x50-sized head is all I've seen */
+ if (read_32bitBE(0x00,streamFile) != 0x5354524D) /* "STRM" */
+ goto fail;
+ if (read_32bitBE(0x04,streamFile) != 0xFFFE0001 && /* Old Header Check */
+ (read_32bitBE(0x04,streamFile) != 0xFEFF0001)) /* Some newer games have a new flag */
goto fail;
- /* check type details */
- codec_number = read_8bit(0x18,streamFile);
+ if (read_32bitBE(0x10,streamFile) != 0x48454144 && /* "HEAD" */
+ read_32bitLE(0x14,streamFile) != 0x50) /* 0x50-sized head is all I've seen */
+ goto fail;
+
+ codec = read_8bit(0x18,streamFile);
loop_flag = read_8bit(0x19,streamFile);
channel_count = read_8bit(0x1a,streamFile);
+ if (channel_count > 2) goto fail;
- switch (codec_number) {
- case 0:
- coding_type = coding_PCM8;
+ start_offset = read_32bitLE(0x28,streamFile);
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = (uint16_t)read_16bitLE(0x1c,streamFile);
+ vgmstream->num_samples = read_32bitLE(0x24,streamFile);
+ vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile);
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+
+ vgmstream->meta_type = meta_STRM;
+
+ switch (codec) {
+ case 0x00: /* [Bleach - Dark Souls (DS)] */
+ vgmstream->coding_type = coding_PCM8;
break;
- case 1:
- coding_type = coding_PCM16LE;
+ case 0x01:
+ vgmstream->coding_type = coding_PCM16LE;
break;
- case 2:
- coding_type = coding_NDS_IMA;
+ case 0x02: /* [SaGa 2 (DS)] */
+ vgmstream->coding_type = coding_NDS_IMA;
break;
default:
goto fail;
}
-
- /* TODO: only mono and stereo supported */
- if (channel_count < 1 || channel_count > 2) goto fail;
-
- /* build the VGMSTREAM */
-
- vgmstream = allocate_vgmstream(channel_count,loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = read_32bitLE(0x24,streamFile);
- vgmstream->sample_rate = (uint16_t)read_16bitLE(0x1c,streamFile);
- /* channels and loop flag are set by allocate_vgmstream */
- vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile);
- vgmstream->loop_end_sample = vgmstream->num_samples;
-
- vgmstream->coding_type = coding_type;
- vgmstream->meta_type = meta_STRM;
-
+ vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitLE(0x30,streamFile);
- vgmstream->interleave_smallblock_size = read_32bitLE(0x38,streamFile);
+ vgmstream->interleave_last_block_size = read_32bitLE(0x38,streamFile);
- if (coding_type==coding_PCM8 || coding_type==coding_PCM16LE)
- vgmstream->layout_type = layout_none;
- else
- vgmstream->layout_type = layout_interleave_shortblock;
-
- start_offset = read_32bitLE(0x28,streamFile);
-
- /* open the file for reading by each channel */
- {
- int i;
- for (i=0;ilayout_type==layout_interleave_shortblock)
- vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,
- vgmstream->interleave_block_size);
- else
- vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,
- 0x1000);
- if (!vgmstream->ch[i].streamfile) goto fail;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=
- start_offset + i*vgmstream->interleave_block_size;
- }
- }
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ngc_adpdtk.c b/Frameworks/vgmstream/vgmstream/src/meta/ngc_adpdtk.c
index 82e0a70d5..ab3852c6f 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ngc_adpdtk.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ngc_adpdtk.c
@@ -2,17 +2,19 @@
#include "meta.h"
#include "../util.h"
+/* DTK - headerless Nintendo DTK file [Harvest Moon - Another Wonderful Life (GC), XGRA (GC)] */
VGMSTREAM * init_vgmstream_ngc_adpdtk(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset = 0;
int channel_count = 2, loop_flag = 0; /* always stereo, no loop */
- /* check extension, case insensitive */
- if ( !check_extensions(streamFile,"dtk,adp"))
+ /* checks */
+ /* dtk: standard [XGRA (GC)], adp: standard [Harvest Moon AWL (GC)], wav/lwav: Alien Hominid (GC) */
+ if ( !check_extensions(streamFile,"dtk,adp,wav,lwav"))
goto fail;
- /* .adp files have no header, and the ext is common, so all we can do is look for valid first frames */
- if (check_extensions(streamFile,"adp")) {
+ /* files have no header, and the ext is common, so all we can do is look for valid first frames */
+ if (check_extensions(streamFile,"adp,wav,lwav")) {
int i;
for (i = 0; i < 10; i++) { /* try a bunch of frames */
if (read_8bit(0x00 + i*0x20,streamFile) != read_8bit(0x02 + i*0x20,streamFile) ||
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ngc_bo2.c b/Frameworks/vgmstream/vgmstream/src/meta/ngc_bo2.c
deleted file mode 100644
index 74ee379f1..000000000
--- a/Frameworks/vgmstream/vgmstream/src/meta/ngc_bo2.c
+++ /dev/null
@@ -1,100 +0,0 @@
-#include "meta.h"
-#include "../util.h"
-
-/* BO2 (Blood Omen 2 NGC) */
-VGMSTREAM * init_vgmstream_ngc_bo2(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- int loop_flag;
- int channels;
- int channel_count;
- off_t start_offset;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("bo2",filename_extension(filename))) goto fail;
-
- /* check header */
- if (read_32bitBE(0x00,streamFile) != 0x0) /* "IDSP" */
- goto fail;
-
- switch (read_32bitBE(0x10,streamFile))
- {
- case 0x0:
- channels = 1;
- break;
- case 0x1:
- channels = 2;
- break;
- default:
- goto fail;
- }
-
- if ((get_streamfile_size(streamFile)) < ((read_32bitBE(0x0C,streamFile)/14*8*channels)+0x800))
- {
- goto fail;
- }
-
- channel_count = channels;
- loop_flag = (read_32bitBE(0x08,streamFile) != 0xFFFFFFFF);
-
- /* 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(0x04,streamFile);
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->num_samples = read_32bitBE(0x0C,streamFile);
- if (loop_flag) {
- vgmstream->loop_start_sample = read_32bitBE(0x08,streamFile);
- vgmstream->loop_end_sample = read_32bitBE(0x0C,streamFile);
- }
-
- if (channel_count == 1)
- {
- vgmstream->layout_type = layout_none;
- }
- else
- {
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = 0x400;
- }
-
- vgmstream->meta_type = meta_NGC_BO2;
-
- {
- int i;
- for (i=0;i<16;i++)
- vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x24+i*2,streamFile);
- if (channel_count == 2) {
- for (i=0;i<16;i++)
- vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x52+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/ngc_caf.c b/Frameworks/vgmstream/vgmstream/src/meta/ngc_caf.c
deleted file mode 100644
index fce124882..000000000
--- a/Frameworks/vgmstream/vgmstream/src/meta/ngc_caf.c
+++ /dev/null
@@ -1,75 +0,0 @@
-#include "meta.h"
-#include "../layout/layout.h"
-#include "../util.h"
-
-VGMSTREAM * init_vgmstream_caf(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
-
- // Calculate sample length ...
- int32_t num_of_samples=0;
- int32_t block_count=0;
-
- uint32_t loop_start=-1;
-
- off_t offset=0;
- off_t next_block;
- off_t file_length;
- int i;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("cfn",filename_extension(filename))) goto fail;
-
- /* Check "CAF " ID */
- if (read_32bitBE(0,streamFile)!=0x43414620) goto fail;
-
- // Calculate sample length ...
- file_length=(off_t)get_streamfile_size(streamFile);
-
- do {
- next_block=read_32bitBE(offset+0x04,streamFile);
- num_of_samples+=read_32bitBE(offset+0x14,streamFile)/8*14;
-
- if(read_32bitBE(offset+0x20,streamFile)==read_32bitBE(offset+0x08,streamFile)) {
- loop_start=num_of_samples-read_32bitBE(offset+0x14,streamFile)/8*14;
- }
- offset+=next_block;
- block_count++;
- } while(offsetchannels=2;
- vgmstream->sample_rate=32000;
- vgmstream->num_samples=num_of_samples;
-
- if(loop_start!=-1) {
- vgmstream->loop_start_sample=loop_start;
- vgmstream->loop_end_sample=num_of_samples;
- }
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_caf_blocked;
- vgmstream->meta_type = meta_CFN;
-
- /* open the file for reading by each channel */
- {
- for (i=0;i<2;i++) {
- vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000);
-
- if (!vgmstream->ch[i].streamfile) goto fail;
- }
- }
-
- caf_block_update(0,vgmstream);
-
- 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/ngc_dsp_std.c b/Frameworks/vgmstream/vgmstream/src/meta/ngc_dsp_std.c
index dd9a58cd3..990a1c210 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ngc_dsp_std.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ngc_dsp_std.c
@@ -24,80 +24,288 @@ struct dsp_header {
uint16_t loop_ps;
int16_t loop_hist1;
int16_t loop_hist2;
- int16_t channel_count;
+ int16_t channel_count; /* DSPADPCM.exe ~v2.7 extension */
int16_t block_size;
+ /* padding/reserved up to 0x60 */
+ /* DSPADPCM.exe from GC adds some extra data here (uninitialized MSVC memory?) */
};
-/* nonzero on failure */
-static int read_dsp_header(struct dsp_header *header, off_t offset, STREAMFILE *file) {
+/* read the above struct; returns nonzero on failure */
+static int read_dsp_header_endian(struct dsp_header *header, off_t offset, STREAMFILE *streamFile, int big_endian) {
+ int32_t (*get_32bit)(uint8_t *) = big_endian ? get_32bitBE : get_32bitLE;
+ int16_t (*get_16bit)(uint8_t *) = big_endian ? get_16bitBE : get_16bitLE;
int i;
- uint8_t buf[0x4e]; /* usually padded out to 0x60 */
- if (read_streamfile(buf, offset, 0x4e, file) != 0x4e) return 1;
+ uint8_t buf[0x4e];
- header->sample_count =
- get_32bitBE(buf+0x00);
- header->nibble_count =
- get_32bitBE(buf+0x04);
- header->sample_rate =
- get_32bitBE(buf+0x08);
- header->loop_flag =
- get_16bitBE(buf+0x0c);
- header->format =
- get_16bitBE(buf+0x0e);
- header->loop_start_offset =
- get_32bitBE(buf+0x10);
- header->loop_end_offset =
- get_32bitBE(buf+0x14);
- header->ca =
- get_32bitBE(buf+0x18);
+ if (read_streamfile(buf, offset, 0x4e, streamFile) != 0x4e)
+ return 1;
+ header->sample_count = get_32bit(buf+0x00);
+ header->nibble_count = get_32bit(buf+0x04);
+ header->sample_rate = get_32bit(buf+0x08);
+ header->loop_flag = get_16bit(buf+0x0c);
+ header->format = get_16bit(buf+0x0e);
+ header->loop_start_offset = get_32bit(buf+0x10);
+ header->loop_end_offset = get_32bit(buf+0x14);
+ header->ca = get_32bit(buf+0x18);
for (i=0; i < 16; i++)
- header->coef[i] =
- get_16bitBE(buf+0x1c+i*2);
- header->gain =
- get_16bitBE(buf+0x3c);
- header->initial_ps =
- get_16bitBE(buf+0x3e);
- header->initial_hist1 =
- get_16bitBE(buf+0x40);
- header->initial_hist2 =
- get_16bitBE(buf+0x42);
- header->loop_ps =
- get_16bitBE(buf+0x44);
- header->loop_hist1 =
- get_16bitBE(buf+0x46);
- header->loop_hist2 =
- get_16bitBE(buf+0x48);
- header->channel_count =
- get_16bitBE(buf+0x4a);
- header->block_size =
- get_16bitBE(buf+0x4c);
+ header->coef[i] = get_16bit(buf+0x1c+i*0x02);
+ header->gain = get_16bit(buf+0x3c);
+ header->initial_ps = get_16bit(buf+0x3e);
+ header->initial_hist1 = get_16bit(buf+0x40);
+ header->initial_hist2 = get_16bit(buf+0x42);
+ header->loop_ps = get_16bit(buf+0x44);
+ header->loop_hist1 = get_16bit(buf+0x46);
+ header->loop_hist2 = get_16bit(buf+0x48);
+ header->channel_count = get_16bit(buf+0x4a);
+ header->block_size = get_16bit(buf+0x4c);
+ return 0;
+}
+static int read_dsp_header(struct dsp_header *header, off_t offset, STREAMFILE *file) {
+ return read_dsp_header_endian(header, offset, file, 1);
+}
+static int read_dsp_header_le(struct dsp_header *header, off_t offset, STREAMFILE *file) {
+ return read_dsp_header_endian(header, offset, file, 0);
+}
+
+static void setup_vgmstream_dsp(VGMSTREAM* vgmstream, struct dsp_header* ch_header) {
+ int i, j;
+
+ /* set coeffs and initial history (usually 0) */
+ for (i = 0; i < vgmstream->channels; i++){
+ for (j = 0; j < 16; j++) {
+ vgmstream->ch[i].adpcm_coef[j] = ch_header[i].coef[j];
+ }
+ vgmstream->ch[i].adpcm_history1_16 = ch_header[i].initial_hist1;
+ vgmstream->ch[i].adpcm_history2_16 = ch_header[i].initial_hist2;
+ }
+}
+
+static int dsp_load_header_endian(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing, int big_endian) {
+ int i;
+
+ /* load standard dsp header per channel */
+ for (i = 0; i < channels; i++) {
+ if (read_dsp_header_endian(&ch_header[i], offset + i*spacing, streamFile, big_endian))
+ goto fail;
+ }
+
+ return 1;
+fail:
+ return 0;
+}
+static int dsp_load_header(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) {
+ return dsp_load_header_endian(ch_header, channels, streamFile, offset, spacing, 1);
+}
+//static int dsp_load_header_le(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) {
+// return dsp_load_header_endian(ch_header, channels, streamFile, offset, spacing, 0);
+//}
+static int check_dsp_format(struct dsp_header* ch_header, int channels) {
+ int i;
+
+ /* check type==0 and gain==0 */
+ for (i = 0; i < channels; i++) {
+ if (ch_header[i].format || ch_header[i].gain)
+ goto fail;
+ }
+
+ return 1;
+fail:
+ return 0;
+}
+static int check_dsp_samples(struct dsp_header* ch_header, int channels) {
+ int i;
+
+ /* check for agreement between channels */
+ for (i = 0; i < channels - 1; i++) {
+ if (ch_header[i].sample_count != ch_header[i+1].sample_count ||
+ ch_header[i].nibble_count != ch_header[i+1].nibble_count ||
+ ch_header[i].sample_rate != ch_header[i+1].sample_rate ||
+ ch_header[i].loop_flag != ch_header[i+1].loop_flag ||
+ ch_header[i].loop_start_offset != ch_header[i+1].loop_start_offset ||
+ ch_header[i].loop_end_offset != ch_header[i+1].loop_end_offset ) {
+ goto fail;
+ }
+ }
+
+ return 1;
+fail:
+ return 0;
+}
+static int check_dsp_initial_ps(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t interleave) {
+ int i;
+
+ /* check initial predictor/scale */
+ for (i = 0; i < channels; i++) {
+ off_t start_offset = offset + i*interleave;
+ if (ch_header[i].initial_ps != (uint8_t)read_8bit(start_offset, streamFile)){
+ goto fail;
+ }
+ }
+
+ return 1;
+fail:
+ return 0;
+}
+static int check_dsp_loop_ps(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t interleave) {
+ int i;
+
+ if (!ch_header[0].loop_flag)
+ return 1;
+
+ /* check loop predictor/scale */
+ for (i = 0; i < channels; i++) {
+ off_t loop_offset = ch_header[i].loop_start_offset;
+ if (interleave) {
+ loop_offset = loop_offset / 16 * 8;
+ loop_offset = (loop_offset / interleave * interleave * channels) + (loop_offset % interleave);
+ }
+
+ if (ch_header[i].loop_ps != (uint8_t)read_8bit(offset + i*interleave + loop_offset,streamFile))
+ goto fail;
+ }
+
+ return 1;
+fail:
return 0;
}
-/* the standard .dsp, as generated by DSPADPCM.exe */
+/* ********************************* */
+/* common parser config as most DSPs are basically the same with minor changes */
+typedef struct {
+ int little_endian;
+ int channel_count;
+ int max_channels;
+
+ int force_loop; /* force full loop */
+ int fix_looping; /* fix loop end going past num_samples */
+ int fix_loop_start; /* weird files with bad loop start */
+ int single_header; /* all channels share header, thus totals are off */
+ int ignore_header_agreement; /* sometimes there are minor differences between headers */
+ int ignore_loop_check; /* loop info in header should match data, but sometimes it's weird */ //todo check if needed anymore
+
+ off_t header_offset;
+ size_t header_spacing;
+ off_t start_offset;
+ size_t interleave;
+
+ meta_t meta_type;
+} dsp_meta;
+
+#define COMMON_DSP_MAX_CHANNELS 6
+static VGMSTREAM * init_vgmstream_dsp_common(STREAMFILE *streamFile, dsp_meta *dspm) {
+ VGMSTREAM * vgmstream = NULL;
+ int loop_flag;
+ struct dsp_header ch_header[COMMON_DSP_MAX_CHANNELS];
+
+ if (dspm->channel_count > dspm->max_channels)
+ goto fail;
+ if (dspm->channel_count > COMMON_DSP_MAX_CHANNELS)
+ goto fail;
+
+
+ /* read dsp */
+ if (!dsp_load_header_endian(ch_header, dspm->channel_count, streamFile,dspm->header_offset,dspm->header_spacing, !dspm->little_endian))
+ goto fail;
+
+ if (dspm->fix_loop_start) {
+ int i;
+ for (i = 0; i < dspm->channel_count; i++) {
+ /* bad/fixed value in loop start */
+ if (ch_header[i].loop_flag)
+ ch_header[i].loop_start_offset = 0x00;
+ }
+ }
+
+ if (!check_dsp_format(ch_header, dspm->channel_count))
+ goto fail;
+
+ if (!dspm->ignore_header_agreement && !check_dsp_samples(ch_header, dspm->channel_count))
+ goto fail;
+
+ if (dspm->single_header && !check_dsp_initial_ps(ch_header, 1, streamFile,dspm->start_offset,dspm->interleave))
+ goto fail;
+ if (!dspm->single_header && !check_dsp_initial_ps(ch_header, dspm->channel_count, streamFile,dspm->start_offset,dspm->interleave))
+ goto fail;
+
+ if (!dspm->ignore_loop_check) {
+ if (dspm->single_header && !check_dsp_loop_ps(ch_header, 1, streamFile,dspm->start_offset,dspm->interleave))
+ goto fail;
+ if (!dspm->single_header && !check_dsp_loop_ps(ch_header, dspm->channel_count, streamFile,dspm->start_offset,dspm->interleave))
+ goto fail;
+ }
+
+
+ loop_flag = ch_header[0].loop_flag;
+ if (dspm->force_loop)
+ loop_flag = 1;
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(dspm->channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = ch_header[0].sample_rate;
+ vgmstream->num_samples = ch_header[0].sample_count;
+ vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset);
+ vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1;
+
+ vgmstream->meta_type = dspm->meta_type;
+ vgmstream->coding_type = coding_NGC_DSP;
+ if (dspm->interleave > 0 && dspm->interleave < 0x08)
+ vgmstream->coding_type = coding_NGC_DSP_subint;
+ vgmstream->layout_type = layout_interleave;
+ if (dspm->interleave == 0 || vgmstream->coding_type == coding_NGC_DSP_subint)
+ vgmstream->layout_type = layout_none;
+ vgmstream->interleave_block_size = dspm->interleave;
+
+ setup_vgmstream_dsp(vgmstream, ch_header);
+
+ /* don't know why, but it does happen*/
+ if (dspm->fix_looping && vgmstream->loop_end_sample > vgmstream->num_samples)
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+
+ if (dspm->single_header) {
+ vgmstream->num_samples /= dspm->channel_count;
+ vgmstream->loop_start_sample /= dspm->channel_count;
+ vgmstream->loop_end_sample /= dspm->channel_count;
+ }
+
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,dspm->start_offset))
+ goto fail;
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+/* ********************************* */
+
+/* .dsp - standard dsp as generated by DSPADPCM.exe */
VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
-
struct dsp_header header;
- const off_t start_offset = 0x60;
- int i;
+ const size_t header_size = 0x60;
+ off_t start_offset;
+ int i, channel_count;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("dsp",filename_extension(filename))) goto fail;
+ /* checks */
+ /* .dsp: standard, .adp: Dr. Muto/Battalion Wars (GC) mono files */
+ if (!check_extensions(streamFile, "dsp,adp"))
+ goto fail;
- if (read_dsp_header(&header, 0, streamFile)) goto fail;
+ if (read_dsp_header(&header, 0x00, streamFile))
+ goto fail;
+
+ channel_count = 1;
+ start_offset = header_size;
- /* check initial predictor/scale */
if (header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
+ goto fail; /* check initial predictor/scale */
if (header.format || header.gain)
- goto fail;
+ goto fail; /* check type==0 and gain==0 */
/* Check for a matching second header. If we find one and it checks
* out thoroughly, we're probably not dealing with a genuine mono DSP.
@@ -105,13 +313,14 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) {
* predictor/scale check if the first byte is 0 */
{
struct dsp_header header2;
-
- read_dsp_header(&header2, 0x60, streamFile);
+ read_dsp_header(&header2, header_size, streamFile);
if (header.sample_count == header2.sample_count &&
header.nibble_count == header2.nibble_count &&
header.sample_rate == header2.sample_rate &&
- header.loop_flag == header2.loop_flag) goto fail;
+ header.loop_flag == header2.loop_flag) {
+ goto fail;
+ }
}
if (header.loop_flag) {
@@ -119,7 +328,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) {
/* check loop predictor/scale */
loop_off = header.loop_start_offset/16*8;
if (header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) {
- /* rarely won't match (ex ESPN 2002), not sure if header or calc problem, but doesn't seem to matter
+ /* rarely won't match (ex ESPN 2002), not sure if header or calc problem, but doesn't seem to matter
* (there may be a "click" when looping, or loop values may be too big and loop disabled anyway) */
VGM_LOG("DSP (std): bad loop_predictor\n");
//header.loop_flag = 0;
@@ -127,123 +336,176 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) {
}
}
- /* compare num_samples with nibble count */
- /*
- fprintf(stderr,"num samples (literal): %d\n",read_32bitBE(0,streamFile));
- fprintf(stderr,"num samples (nibbles): %d\n",dsp_nibbles_to_samples(read_32bitBE(4,streamFile)));
- */
/* build the VGMSTREAM */
-
-
- vgmstream = allocate_vgmstream(1,header.loop_flag);
+ vgmstream = allocate_vgmstream(channel_count,header.loop_flag);
if (!vgmstream) goto fail;
- /* fill in the vital statistics */
- vgmstream->num_samples = header.sample_count;
vgmstream->sample_rate = header.sample_rate;
-
- vgmstream->loop_start_sample = dsp_nibbles_to_samples(
- header.loop_start_offset);
- vgmstream->loop_end_sample = dsp_nibbles_to_samples(
- header.loop_end_offset)+1;
-
- /* don't know why, but it does happen*/
- if (vgmstream->loop_end_sample > vgmstream->num_samples)
+ vgmstream->num_samples = header.sample_count;
+ vgmstream->loop_start_sample = dsp_nibbles_to_samples(header.loop_start_offset);
+ vgmstream->loop_end_sample = dsp_nibbles_to_samples(header.loop_end_offset)+1;
+ if (vgmstream->loop_end_sample > vgmstream->num_samples) /* don't know why, but it does happen */
vgmstream->loop_end_sample = vgmstream->num_samples;
+ vgmstream->meta_type = meta_DSP_STD;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
- vgmstream->meta_type = meta_DSP_STD;
- /* coeffs */
- for (i=0;i<16;i++)
- vgmstream->ch[0].adpcm_coef[i] = header.coef[i];
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = header.initial_hist2;
-
- /* open the file for reading */
- vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
-
- if (!vgmstream->ch[0].streamfile) goto fail;
-
- vgmstream->ch[0].channel_start_offset=
- vgmstream->ch[0].offset=start_offset;
+ {
+ /* adpcm coeffs/history */
+ for (i = 0; i < 16; i++)
+ vgmstream->ch[0].adpcm_coef[i] = header.coef[i];
+ vgmstream->ch[0].adpcm_history1_16 = header.initial_hist1;
+ vgmstream->ch[0].adpcm_history2_16 = header.initial_hist2;
+ }
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
-/* the standard multi-channel .dsp, as generated by DSPADPCM.exe */
+/* .dsp - little endian dsp, possibly main Switch .dsp [LEGO Worlds (Switch)] */
+VGMSTREAM * init_vgmstream_ngc_dsp_std_le(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ struct dsp_header header;
+ const size_t header_size = 0x60;
+ off_t start_offset;
+ int i, channel_count;
+ /* checks */
+ /* .adpcm: LEGO Worlds */
+ if (!check_extensions(streamFile, "adpcm"))
+ goto fail;
+
+ if (read_dsp_header_le(&header, 0x00, streamFile))
+ goto fail;
+
+ channel_count = 1;
+ start_offset = header_size;
+
+ if (header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile))
+ goto fail; /* check initial predictor/scale */
+ if (header.format || header.gain)
+ goto fail; /* check type==0 and gain==0 */
+
+ /* Check for a matching second header. If we find one and it checks
+ * out thoroughly, we're probably not dealing with a genuine mono DSP.
+ * In many cases these will pass all the other checks, including the
+ * predictor/scale check if the first byte is 0 */
+ {
+ struct dsp_header header2;
+ read_dsp_header_le(&header2, header_size, streamFile);
+
+ if (header.sample_count == header2.sample_count &&
+ header.nibble_count == header2.nibble_count &&
+ header.sample_rate == header2.sample_rate &&
+ header.loop_flag == header2.loop_flag) {
+ goto fail;
+ }
+ }
+
+ if (header.loop_flag) {
+ off_t loop_off;
+ /* check loop predictor/scale */
+ loop_off = header.loop_start_offset/16*8;
+ if (header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) {
+ /* rarely won't match (ex ESPN 2002), not sure if header or calc problem, but doesn't seem to matter
+ * (there may be a "click" when looping, or loop values may be too big and loop disabled anyway) */
+ VGM_LOG("DSP (std): bad loop_predictor\n");
+ //header.loop_flag = 0;
+ //goto fail;
+ }
+ }
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,header.loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = header.sample_rate;
+ vgmstream->num_samples = header.sample_count;
+ vgmstream->loop_start_sample = dsp_nibbles_to_samples(header.loop_start_offset);
+ vgmstream->loop_end_sample = dsp_nibbles_to_samples(header.loop_end_offset)+1;
+ if (vgmstream->loop_end_sample > vgmstream->num_samples) /* don't know why, but it does happen */
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+
+ vgmstream->meta_type = meta_DSP_STD;
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = layout_none;
+
+ {
+ /* adpcm coeffs/history */
+ for (i = 0; i < 16; i++)
+ vgmstream->ch[0].adpcm_coef[i] = header.coef[i];
+ vgmstream->ch[0].adpcm_history1_16 = header.initial_hist1;
+ vgmstream->ch[0].adpcm_history2_16 = header.initial_hist2;
+ }
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+/* .dsp - standard multi-channel dsp as generated by DSPADPCM.exe (later revisions) */
VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
-
struct dsp_header header;
- const off_t header_size = 0x60;
+ const size_t header_size = 0x60;
off_t start_offset;
int i, c, channel_count;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile, filename, sizeof(filename));
- if (strcasecmp("dsp", filename_extension(filename)) &&
- strcasecmp("mdsp", filename_extension(filename))) goto fail;
+ /* checks */
+ if (!check_extensions(streamFile, "dsp,mdsp"))
+ goto fail;
- if (read_dsp_header(&header, 0, streamFile)) goto fail;
+ if (read_dsp_header(&header, 0x00, streamFile))
+ goto fail;
channel_count = header.channel_count==0 ? 1 : header.channel_count;
start_offset = header_size * channel_count;
- /* check initial predictor/scale */
- if (header.initial_ps != (uint8_t)read_8bit(start_offset, streamFile))
+ /* named .dsp and no channels? likely another interleaved dsp */
+ if (check_extensions(streamFile,"dsp") && header.channel_count == 0)
goto fail;
- /* check type==0 and gain==0 */
+ if (header.initial_ps != (uint8_t)read_8bit(start_offset, streamFile))
+ goto fail; /* check initial predictor/scale */
if (header.format || header.gain)
- goto fail;
+ goto fail; /* check type==0 and gain==0 */
/* build the VGMSTREAM */
-
vgmstream = allocate_vgmstream(channel_count, header.loop_flag);
if (!vgmstream) goto fail;
- /* fill in the vital statistics */
- vgmstream->num_samples = header.sample_count;
vgmstream->sample_rate = header.sample_rate;
-
- vgmstream->loop_start_sample = dsp_nibbles_to_samples(
- header.loop_start_offset);
- vgmstream->loop_end_sample = dsp_nibbles_to_samples(
- header.loop_end_offset) + 1;
-
- /* don't know why, but it does happen*/
- if (vgmstream->loop_end_sample > vgmstream->num_samples)
+ vgmstream->num_samples = header.sample_count;
+ vgmstream->loop_start_sample = dsp_nibbles_to_samples(header.loop_start_offset);
+ vgmstream->loop_end_sample = dsp_nibbles_to_samples(header.loop_end_offset) + 1;
+ if (vgmstream->loop_end_sample > vgmstream->num_samples) /* don't know why, but it does happen*/
vgmstream->loop_end_sample = vgmstream->num_samples;
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave_shortblock;
vgmstream->meta_type = meta_DSP_STD;
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
vgmstream->interleave_block_size = header.block_size * 8;
if (vgmstream->interleave_block_size)
- vgmstream->interleave_smallblock_size = (header.nibble_count / 2 % vgmstream->interleave_block_size + 7) / 8 * 8;
+ vgmstream->interleave_last_block_size = (header.nibble_count / 2 % vgmstream->interleave_block_size + 7) / 8 * 8;
for (i = 0; i < channel_count; i++) {
if (read_dsp_header(&header, header_size * i, streamFile)) goto fail;
- /* coeffs */
+ /* adpcm coeffs/history */
for (c = 0; c < 16; c++)
vgmstream->ch[i].adpcm_coef[c] = header.coef[c];
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
vgmstream->ch[i].adpcm_history1_16 = header.initial_hist1;
vgmstream->ch[i].adpcm_history2_16 = header.initial_hist2;
}
@@ -253,554 +515,272 @@ VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile) {
return vgmstream;
fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
+
/* Some very simple stereo variants of standard dsp just use the standard header
- * twice and add interleave, or just concatenate the channels. We'll support
- * them all here.
- * Note that Cstr isn't here, despite using the form of the standard header,
- * because its loop values are wacky. */
+ * twice and add interleave, or just concatenate the channels. We'll support them all here. */
-/* .stm
- * Used in Paper Mario 2, Fire Emblem: Path of Radiance, Cubivore
- * I suspected that this was an Intelligent Systems format, but its use in
- * Cubivore calls that into question. */
+/* .stm - Intelligent Systems + others (same programmers) full interleaved dsp [Paper Mario TTYD (GC), Fire Emblem: POR (GC), Cubivore (GC)] */
VGMSTREAM * init_vgmstream_ngc_dsp_stm(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
+ dsp_meta dspm = {0};
- struct dsp_header ch0_header, ch1_header;
- int i;
- int stm_header_sample_rate;
- int channel_count;
- const off_t start_offset = 0x100;
- off_t first_channel_size;
- off_t second_channel_start;
+ /* checks */
+ /* .lstm/dsp: renamed to avoid hijacking Scream Tracker 2 Modules */
+ if (!check_extensions(streamFile, "stm,lstm,dsp"))
+ goto fail;
+ if (read_16bitBE(0x00, streamFile) != 0x0200)
+ goto fail;
+ /* 0x02(2): sample rate, 0x08+: channel sizes/loop offsets? */
- /* check extension, case insensitive */
- /* to avoid collision with Scream Tracker 2 Modules, also ending in .stm
- * and supported by default in Winamp, it was policy in the old days to
- * rename these files to .dsp */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("stm",filename_extension(filename)) &&
- strcasecmp("dsp",filename_extension(filename))) goto fail;
+ dspm.channel_count = read_32bitBE(0x04, streamFile);
+ dspm.max_channels = 2;
+ dspm.fix_looping = 1;
- /* check intro magic */
- if (read_16bitBE(0, streamFile) != 0x0200) goto fail;
-
- channel_count = read_32bitBE(4, streamFile);
- /* only stereo and mono are known */
- if (channel_count != 1 && channel_count != 2) goto fail;
-
- first_channel_size = read_32bitBE(8, streamFile);
- /* this is bad rounding, wastes space, but it looks like that's what's
- * used */
- second_channel_start = ((start_offset+first_channel_size)+0x20)/0x20*0x20;
-
- /* an additional check */
- stm_header_sample_rate = (uint16_t)read_16bitBE(2, streamFile);
-
- /* read the DSP headers */
- if (read_dsp_header(&ch0_header, 0x40, streamFile)) goto fail;
- if (channel_count == 2) {
- if (read_dsp_header(&ch1_header, 0xa0, streamFile)) goto fail;
- }
-
- /* checks for fist channel */
- {
- if (ch0_header.sample_rate != stm_header_sample_rate) goto fail;
-
- /* check initial predictor/scale */
- if (ch0_header.initial_ps != (uint8_t)read_8bit(start_offset, streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch0_header.format || ch0_header.gain)
- goto fail;
-
- if (ch0_header.loop_flag) {
- off_t loop_off;
- /* check loop predictor/scale */
- loop_off = ch0_header.loop_start_offset/16*8;
- if (ch0_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile))
- goto fail;
- }
- }
-
-
- /* checks for second channel */
- if (channel_count == 2) {
- if (ch1_header.sample_rate != stm_header_sample_rate) goto fail;
-
- /* check for agreement with first channel header */
- if (
- ch0_header.sample_count != ch1_header.sample_count ||
- ch0_header.nibble_count != ch1_header.nibble_count ||
- ch0_header.loop_flag != ch1_header.loop_flag ||
- ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
- ch0_header.loop_end_offset != ch1_header.loop_end_offset
- ) goto fail;
-
- /* check initial predictor/scale */
- if (ch1_header.initial_ps != (uint8_t)read_8bit(second_channel_start, streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch1_header.format || ch1_header.gain)
- goto fail;
-
- if (ch1_header.loop_flag) {
- off_t loop_off;
- /* check loop predictor/scale */
- loop_off = ch1_header.loop_start_offset/16*8;
- /*printf("loop_start_offset=%x\nloop_ps=%x\nloop_off=%x\n",ch1_header.loop_start_offset,ch1_header.loop_ps,second_channel_start+loop_off);*/
- if (ch1_header.loop_ps != (uint8_t)read_8bit(second_channel_start+loop_off,streamFile))
- goto fail;
- }
- }
-
- /* build the VGMSTREAM */
-
- vgmstream = allocate_vgmstream(channel_count, ch0_header.loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch0_header.sample_count;
- vgmstream->sample_rate = ch0_header.sample_rate;
-
- 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;
-
- /* don't know why, but it does happen*/
- if (vgmstream->loop_end_sample > vgmstream->num_samples)
- vgmstream->loop_end_sample = vgmstream->num_samples;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_none;
- vgmstream->meta_type = meta_DSP_STM;
-
- /* coeffs */
- for (i=0;i<16;i++)
- vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
-
- if (channel_count == 2) {
- /* coeffs */
- for (i=0;i<16;i++)
- vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
- vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
- }
-
- /* open the file for reading */
- vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
-
- if (!vgmstream->ch[0].streamfile) goto fail;
-
- vgmstream->ch[0].channel_start_offset=
- vgmstream->ch[0].offset=start_offset;
-
- if (channel_count == 2) {
- vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
-
- if (!vgmstream->ch[1].streamfile) goto fail;
-
- vgmstream->ch[1].channel_start_offset=
- vgmstream->ch[1].offset=second_channel_start;
- }
-
- return vgmstream;
+ dspm.header_offset = 0x40;
+ dspm.header_spacing = 0x60;
+ dspm.start_offset = 0x100;
+ dspm.interleave = (read_32bitBE(0x08, streamFile) + 0x20) / 0x20 * 0x20; /* strange rounding, but works */
+ dspm.meta_type = meta_DSP_STM;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
-/* mpdsp: looks like a standard .dsp header, but the data is actually
- * interleaved stereo
- * The files originally had a .dsp extension, we rename them to .mpdsp so we
- * can catch this.
- */
-
+/* .(mp)dsp - single header + interleaved dsp [Monopoly Party! (GC)] */
VGMSTREAM * init_vgmstream_ngc_mpdsp(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
+ dsp_meta dspm = {0};
- struct dsp_header header;
- const off_t start_offset = 0x60;
- int i;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("mpdsp",filename_extension(filename))) goto fail;
-
- if (read_dsp_header(&header, 0, streamFile)) goto fail;
-
- /* none have loop flag set, save us from loop code that involves them */
- if (header.loop_flag) goto fail;
-
- /* check initial predictor/scale */
- if (header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile))
+ /* checks */
+ /* .mpdsp: renamed since standard .dsp would catch it otherwise */
+ if (!check_extensions(streamFile, "mpdsp"))
goto fail;
- /* check type==0 and gain==0 */
- if (header.format || header.gain)
- goto fail;
-
- /* build the VGMSTREAM */
+ /* at 0x48 is extra data that could help differenciating these DSPs, but other games
+ * put similar stuff there, needs more checks (ex. Battallion Wars, Army Men) */
+ //0x00005300 60A94000 64FF1200 00000000 00000000 00000000
+ /* 0x02(2): sample rate, 0x08+: channel sizes/loop offsets? */
+ dspm.channel_count = 2;
+ dspm.max_channels = 2;
+ dspm.single_header = 1;
- /* no loop flag, but they do loop */
- vgmstream = allocate_vgmstream(2,0);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = header.sample_count/2;
- vgmstream->sample_rate = header.sample_rate;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = 0xf000;
- vgmstream->meta_type = meta_DSP_MPDSP;
-
- /* coeffs */
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = header.coef[i];
- vgmstream->ch[1].adpcm_coef[i] = header.coef[i];
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = header.initial_hist2;
- vgmstream->ch[1].adpcm_history1_16 = header.initial_hist1;
- vgmstream->ch[1].adpcm_history2_16 = header.initial_hist2;
-
- /* open the file for reading */
- for (i=0;i<2;i++) {
- vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,
- vgmstream->interleave_block_size);
-
- if (!vgmstream->ch[i].streamfile) goto fail;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=start_offset+
- vgmstream->interleave_block_size*i;
- }
-
- return vgmstream;
+ dspm.header_offset = 0x00;
+ dspm.header_spacing = 0x00; /* same header for both channels */
+ dspm.start_offset = 0x60;
+ dspm.interleave = 0xf000;
+ dspm.meta_type = meta_DSP_MPDSP;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
-/* str: a very simple header format with implicit loop values
- * it's allways in interleaved stereo format
- */
-VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
-
- const off_t start_offset = 0x60;
- int i;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("str",filename_extension(filename))) goto fail;
-
- /* always 0xFAAF0001 @ offset 0 */
- if (read_32bitBE(0x00,streamFile)!=0xFAAF0001) goto fail;
-
- /* build the VGMSTREAM */
- /* always loop & stereo */
- vgmstream = allocate_vgmstream(2,1);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = read_32bitBE(0x08,streamFile);
- vgmstream->sample_rate = read_32bitBE(0x04,streamFile);
-
- /* always loop to the beginning */
- vgmstream->loop_start_sample=0;
- vgmstream->loop_end_sample=vgmstream->num_samples;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = read_32bitBE(0x0C,streamFile);
- vgmstream->meta_type = meta_DSP_STR;
-
- /* 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(0x30+(i*2),streamFile);
- }
-
- /* open the file for reading */
- for (i=0;i<2;i++) {
- vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,
- vgmstream->interleave_block_size);
-
- if (!vgmstream->ch[i].streamfile) goto fail;
-
- 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;
-}
-
-/* a bunch of formats that are identical except for file extension,
- * but have different interleaves */
-
+/* various dsp with differing extensions and interleave values */
VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
+ dsp_meta dspm = {0};
char filename[PATH_LIMIT];
- const off_t start_offset = 0xc0;
- off_t interleave;
- int meta_type;
+ /* checks */
+ if (!check_extensions(streamFile, "dsp,mss,gcm"))
+ goto fail;
- struct dsp_header ch0_header,ch1_header;
+ dspm.channel_count = 2;
+ dspm.max_channels = 2;
+ dspm.fix_looping = 1;
- int i;
+ dspm.header_offset = 0x00;
+ dspm.header_spacing = 0x60;
+ dspm.start_offset = 0xc0;
- /* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strlen(filename) > 7 && !strcasecmp("_lr.dsp",filename+strlen(filename)-7)) {
- /* Bomberman Jetters */
- interleave = 0x14180;
- meta_type = meta_DSP_JETTERS;
+ dspm.interleave = 0x14180;
+ dspm.meta_type = meta_DSP_JETTERS; /* Bomberman Jetters (GC) */
} else if (!strcasecmp("mss",filename_extension(filename))) {
- interleave = 0x1000;
- meta_type = meta_DSP_MSS;
- } else if (!strcasecmp("gcm",filename_extension(filename))) {
- interleave = 0x8000;
- meta_type = meta_DSP_GCM;
- } else goto fail;
-
- if (read_dsp_header(&ch0_header, 0, streamFile)) goto fail;
- if (read_dsp_header(&ch1_header, 0x60, streamFile)) goto fail;
-
- /* check initial predictor/scale */
- if (ch0_header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile))
- goto fail;
- if (ch1_header.initial_ps != (uint8_t)read_8bit(start_offset+interleave,streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch0_header.format || ch0_header.gain ||
- ch1_header.format || ch1_header.gain)
- goto fail;
-
- /* check for agreement */
- if (
- ch0_header.sample_count != ch1_header.sample_count ||
- ch0_header.nibble_count != ch1_header.nibble_count ||
- ch0_header.sample_rate != ch1_header.sample_rate ||
- ch0_header.loop_flag != ch1_header.loop_flag ||
- ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
- ch0_header.loop_end_offset != ch1_header.loop_end_offset
- ) {
+ dspm.interleave = 0x1000;
+ dspm.meta_type = meta_DSP_MSS; /* Free Radical GC games */
/* Timesplitters 2 GC's ts2_atom_smasher_44_fx.mss differs slightly in samples but plays ok */
- if (meta_type != meta_DSP_MSS)
- goto fail;
+ dspm.ignore_header_agreement = 1;
+ } else if (!strcasecmp("gcm",filename_extension(filename))) {
+ dspm.interleave = 0x8000;
+ dspm.meta_type = meta_DSP_GCM; /* some of Traveller's Tales games */
+ } else {
+ goto fail;
}
- 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;
- }
-
- /* build the VGMSTREAM */
-
- vgmstream = allocate_vgmstream(2,ch0_header.loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch0_header.sample_count;
- vgmstream->sample_rate = ch0_header.sample_rate;
-
- /* TODO: adjust for interleave? */
- 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;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = interleave;
- vgmstream->meta_type = meta_type;
-
- /* coeffs */
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
- vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
- vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
- vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
-
- /* open the file for reading */
- for (i=0;i<2;i++) {
- vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
-
- if (!vgmstream->ch[i].streamfile) goto fail;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=start_offset+i*interleave;
- }
-
- return vgmstream;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
-/* IDSP with multiple standard DSP headers - from SSB4 (3DS), Tekken Tag Tournament 2 (Wii U) */
-#define MULTI_IDSP_MAX_CHANNELS 8
+/* IDSP - Namco header + interleaved dsp [SSB4 (3DS), Tekken Tag Tournament 2 (WiiU)] */
VGMSTREAM * init_vgmstream_3ds_idsp(STREAMFILE *streamFile) {
+ dsp_meta dspm = {0};
+ off_t offset;
+
+ /* checks */
+ if (!check_extensions(streamFile, "idsp,nus3bank"))
+ goto fail;
+
+ /* try NUS3BANK container */
+ if (read_32bitBE(0x00,streamFile) == 0x4E555333) { /* "NUS3" */
+ offset = 0x14 + read_32bitLE(0x10, streamFile); /* header size */
+ offset += read_32bitLE(0x1C, streamFile) + 0x08;
+ offset += read_32bitLE(0x24, streamFile) + 0x08;
+ offset += read_32bitLE(0x2C, streamFile) + 0x08;
+ offset += read_32bitLE(0x34, streamFile) + 0x08;
+ offset += read_32bitLE(0x3C, streamFile) + 0x08;
+ offset += read_32bitLE(0x44, streamFile) + 0x08;
+ offset += 0x08;
+ }
+ else {
+ offset = 0x00;
+ }
+
+ if (read_32bitBE(offset,streamFile) != 0x49445350) /* "IDSP" */
+ goto fail;
+ /* 0x0c: sample rate, 0x10: num_samples, 0x14: loop_start_sample, 0x18: loop_start_sample */
+
+ dspm.channel_count = read_32bitBE(offset+0x08, streamFile);
+ dspm.max_channels = 8;
+ /* games do adjust loop_end if bigger than num_samples (only happens in user-created IDSPs) */
+ dspm.fix_looping = 1;
+
+ dspm.header_offset = read_32bitBE(offset+0x20,streamFile) + offset;
+ dspm.header_spacing = read_32bitBE(offset+0x24,streamFile);
+ dspm.start_offset = read_32bitBE(offset+0x28,streamFile) + offset;
+ dspm.interleave = read_32bitBE(offset+0x1c,streamFile); /* usually 0x10 */
+ if (dspm.interleave == 0) /* Taiko no Tatsujin: Atsumete Tomodachi Daisakusen (WiiU) */
+ dspm.interleave = read_32bitBE(offset+0x2c,streamFile); /* half interleave, use channel size */
+
+ dspm.meta_type = meta_3DS_IDSP;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
+fail:
+ return NULL;
+}
+
+/* sadb - Procyon Studio header + interleaved dsp [Shiren the Wanderer 3 (Wii), Disaster: Day of Crisis (Wii)] */
+VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile) {
+ dsp_meta dspm = {0};
+
+ /* checks */
+ if (!check_extensions(streamFile, "sad"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x73616462) /* "sadb" */
+ goto fail;
+
+ dspm.channel_count = read_8bit(0x32, streamFile);
+ dspm.max_channels = 2;
+
+ dspm.header_offset = 0x80;
+ dspm.header_spacing = 0x60;
+ dspm.start_offset = read_32bitBE(0x48,streamFile);
+ dspm.interleave = 0x10;
+
+ dspm.meta_type = meta_DSP_SADB;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
+fail:
+ return NULL;
+}
+
+#define WSI_MAX_CHANNELS 2
+/* .wsi - blocked dsp [Alone in the Dark (Wii)] */
+VGMSTREAM * init_vgmstream_wsi(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
-
- off_t idsp_offset = 0;
- off_t start_offset;
- off_t interleave;
-
- struct dsp_header ch_headers[MULTI_IDSP_MAX_CHANNELS];
- int i, ch;
+ off_t start_offset, header_offset;
+ size_t header_spacing;
+ struct dsp_header ch_header[WSI_MAX_CHANNELS];
int channel_count;
- /* check extension, case insensitive */
- //if (check_extensions(streamFile,"idsp,nus3bank")) goto fail;
+ /* checks */
+ if (!check_extensions(streamFile, "wsi"))
+ goto fail;
- /* check header magic */
- if( read_32bitBE(0x0,streamFile) != 0x49445350 ) /* "IDSP" */
+ /* I don't know if this is actually the channel count, or a block type
+ * for the first block. Won't know until I see a mono .wsi */
+ channel_count = read_32bitBE(0x04,streamFile);
+ if (channel_count != 2) goto fail;
+
+ /* check for consistent block headers */
{
- /* try NUS3 format instead */
- if (read_32bitBE(0,streamFile) != 0x4E555333) goto fail; /* "NUS3" */
-
- /* Header size */
- idsp_offset = 0x14 + read_32bitLE( 0x10, streamFile );
-
- idsp_offset += read_32bitLE( 0x1C, streamFile ) + 8;
- idsp_offset += read_32bitLE( 0x24, streamFile ) + 8;
- idsp_offset += read_32bitLE( 0x2C, streamFile ) + 8;
- idsp_offset += read_32bitLE( 0x34, streamFile ) + 8;
- idsp_offset += read_32bitLE( 0x3C, streamFile ) + 8;
- idsp_offset += read_32bitLE( 0x44, streamFile ) + 8;
- idsp_offset += 8;
+ off_t block_offset;
+ off_t block_size_has_been;
+ int i;
+
+ block_offset = read_32bitBE(0x00,streamFile);
+ if (block_offset < 0x08) goto fail;
- /* check magic */
- if (read_32bitBE(idsp_offset,streamFile) != 0x49445350) goto fail; /* "IDSP" */
- }
-
- channel_count = read_32bitBE(idsp_offset+0x8, streamFile);
- if (channel_count > MULTI_IDSP_MAX_CHANNELS) goto fail;
+ block_size_has_been = block_offset;
- start_offset = read_32bitBE(idsp_offset+0x28,streamFile) + idsp_offset;
- interleave = 0x10;
+ /* check 4 blocks, to get an idea */
+ for (i = 0; i < 4*channel_count; i++) {
+ off_t block_size = read_32bitBE(block_offset,streamFile);
- /* read standard dsp header per channel and do some validations */
- for (ch=0; ch < channel_count; ch++) {
- /* read 0x60 header per channel */
- if (read_dsp_header(&ch_headers[ch], idsp_offset + 0x40 + 0x60*ch, streamFile)) goto fail;
+ if (block_size < 0x10)
+ goto fail; /* expect at least the block header */
+ if (i%channel_count+1 != read_32bitBE(block_offset+0x08,streamFile))
+ goto fail; /* expect the channel numbers to alternate */
- /* check initial values */
- if (ch_headers[ch].initial_ps != (uint8_t)read_8bit(start_offset + interleave*ch, streamFile)) goto fail;
- if (ch_headers[ch].format || ch_headers[ch].gain) goto fail;
+ if (i%channel_count==0)
+ block_size_has_been = block_size;
+ else if (block_size != block_size_has_been)
+ goto fail; /* expect every block in a set of channels to have the same size */
- /* check for agreement with prev channel*/
- if (ch > 0 && (
- ch_headers[ch].sample_count != ch_headers[ch-1].sample_count ||
- ch_headers[ch].nibble_count != ch_headers[ch-1].nibble_count ||
- ch_headers[ch].sample_rate != ch_headers[ch-1].sample_rate ||
- ch_headers[ch].loop_flag != ch_headers[ch-1].loop_flag ||
- ch_headers[ch].loop_start_offset != ch_headers[ch-1].loop_start_offset ||
- ch_headers[ch].loop_end_offset != ch_headers[ch-1].loop_end_offset
- )) goto fail;
-
-
-#if 0 //this is wrong for >2ch and will fail
- /* check loop predictor/scale */
- if (ch_headers[ch].loop_flag) {
- off_t loop_off;
- loop_off = ch_headers[ch].loop_start_offset / 8 / channel_count * 8;
- loop_off = (loop_off / interleave * interleave * channel_count) + (loop_off%interleave);
- if (ch_headers[ch].loop_ps != (uint8_t)read_8bit(start_offset + loop_off + interleave*ch, streamFile)) goto fail;
+ block_offset += block_size;
}
-#endif
}
- /* check first channel (implicitly all ch) agree with main sample rate */
- if (ch_headers[0].sample_rate != read_32bitBE(idsp_offset+0xc, streamFile)) goto fail;
+
+ start_offset = read_32bitBE(0x00, streamFile);
+ header_offset = start_offset + 0x10;
+ header_spacing = read_32bitBE(start_offset,streamFile);
+
+ /* read dsp */
+ if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail;
+ if (!check_dsp_format(ch_header, channel_count)) goto fail;
+ if (!check_dsp_samples(ch_header, channel_count)) goto fail;
+ //if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail;
+ //if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail;
/* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(channel_count,ch_headers[0].loop_flag);
+ vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag);
if (!vgmstream) goto fail;
- vgmstream->num_samples = ch_headers[0].sample_count;
- vgmstream->sample_rate = ch_headers[0].sample_rate;
+ vgmstream->sample_rate = ch_header[0].sample_rate;
- /* TODO: adjust for interleave? */
- vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_headers[0].loop_start_offset);
- vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_headers[0].loop_end_offset) + 1;
- /* games will ignore loop_end and use num_samples if going over it
- * only needed for user-created IDSPs, but it's possible loop_end_sample shouldn't add +1 above */
- if (vgmstream->loop_end_sample > vgmstream->num_samples)
+ vgmstream->num_samples = ch_header[0].sample_count / 14 * 14; /* remove incomplete last frame */
+ vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset);
+ vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1;
+ if (vgmstream->loop_end_sample > vgmstream->num_samples) /* don't know why, but it does happen*/
vgmstream->loop_end_sample = vgmstream->num_samples;
+ vgmstream->meta_type = meta_DSP_WSI;
vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = channel_count > 1 ? layout_interleave : layout_none;
- vgmstream->interleave_block_size = interleave;
- vgmstream->meta_type = meta_3DS_IDSP;
+ vgmstream->layout_type = layout_blocked_wsi;
+
+ setup_vgmstream_dsp(vgmstream, ch_header);
- /* set DSP coefs/history */
- for (ch=0; ch < channel_count; ch++) {
- for (i=0;i<16;i++) {
- vgmstream->ch[ch].adpcm_coef[i] = ch_headers[ch].coef[i];
- }
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[ch].adpcm_history1_16 = ch_headers[ch].initial_hist1;
- vgmstream->ch[ch].adpcm_history2_16 = ch_headers[ch].initial_hist2;
- }
-
- /* open the file for reading */
- if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
+ block_update_wsi(start_offset,vgmstream);
+
+ /* first block has DSP header */
+ {
+ int i;
+
+ vgmstream->current_block_size -= 0x60;
+ for (i = 0; i < vgmstream->channels; i++) {
+ vgmstream->ch[i].offset += 0x60;
+ }
+ }
+
return vgmstream;
fail:
@@ -809,408 +789,30 @@ fail:
}
-/* sadb - .SAD files, two standard DSP headers */
-VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
-
- off_t start_offset;
- off_t interleave;
-
- struct dsp_header ch0_header,ch1_header;
- int i;
- int channel_count;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("sad",filename_extension(filename))) goto fail;
-
- /* check header magic */
- if (read_32bitBE(0x0,streamFile) != 0x73616462) goto fail; /* "sadb" */
-
- channel_count = read_8bit(0x32, streamFile);
- if (channel_count != 1 && channel_count != 2) goto fail;
-
- if (read_dsp_header(&ch0_header, 0x80, streamFile)) goto fail;
- if (channel_count == 2 && read_dsp_header(&ch1_header, 0xe0, streamFile)) goto fail;
-
- start_offset = read_32bitBE(0x48,streamFile);
- interleave = 16;
-
- /* check initial predictor/scale */
- if (ch0_header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile))
- goto fail;
- if (channel_count == 2 && ch1_header.initial_ps != (uint8_t)read_8bit(start_offset+interleave,streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch0_header.format || ch0_header.gain ||
- (channel_count == 2 &&(ch1_header.format || ch1_header.gain)))
- goto fail;
-
- /* check for agreement */
- if ( channel_count == 2 &&(
- ch0_header.sample_count != ch1_header.sample_count ||
- ch0_header.nibble_count != ch1_header.nibble_count ||
- ch0_header.sample_rate != ch1_header.sample_rate ||
- ch0_header.loop_flag != ch1_header.loop_flag ||
- ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
- ch0_header.loop_end_offset != ch1_header.loop_end_offset
- )) goto fail;
-
- if (ch0_header.loop_flag) {
- off_t loop_off;
- /* check loop predictor/scale */
- loop_off = ch0_header.loop_start_offset/8/channel_count*8;
- loop_off = (loop_off/interleave*interleave*channel_count) + (loop_off%interleave);
- if (ch0_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile))
- goto fail;
- if (channel_count == 2 &&
- ch1_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off+interleave,streamFile))
- goto fail;
- }
-
- /* build the VGMSTREAM */
-
- vgmstream = allocate_vgmstream(channel_count,ch0_header.loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch0_header.sample_count;
- vgmstream->sample_rate = ch0_header.sample_rate;
-
- /* TODO: adjust for interleave? */
- 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;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = channel_count == 2 ? layout_interleave : layout_none;
- vgmstream->interleave_block_size = interleave;
- vgmstream->meta_type = meta_DSP_SADB;
-
- /* coeffs */
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
- if (channel_count == 2)
- vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
-
- vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
-
- if (channel_count == 2) {
- vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
- vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
- vgmstream->ch[1].streamfile = vgmstream->ch[0].streamfile;
- }
-
- if (!vgmstream->ch[0].streamfile) goto fail;
- /* open the file for reading */
- for (i=0;ich[i].channel_start_offset=
- vgmstream->ch[i].offset=start_offset+i*interleave;
- }
-
- return vgmstream;
-
-fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
- return NULL;
-}
-
-/* .wsi as found in Alone in the Dark for Wii */
-/* These appear to be standard .dsp, but interleaved in a blocked format */
-
-VGMSTREAM * init_vgmstream_wsi(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- struct dsp_header header[2];
- off_t start_offset[2];
-
- int channel_count;
- size_t est_block_size = 0;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("wsi",filename_extension(filename))) goto fail;
-
- /* I don't know if this is actually the channel count, or a block type
- for the first block. Won't know until I see a mono .wsi */
- channel_count = read_32bitBE(0x04,streamFile);
-
- /* I've only allocated two headers, and I want to be alerted if a mono
- .wsi shows up */
- if (channel_count != 2) goto fail;
-
- /* check for consistent block headers */
- {
- off_t check_offset;
- off_t block_size_has_been;
- int i;
-
- check_offset = read_32bitBE(0x0,streamFile);
- if (check_offset < 8) goto fail;
-
- block_size_has_been = check_offset;
-
- /* check 4 blocks, to get an idea */
- for (i=0;i<4*channel_count;i++) {
- off_t block_size;
- block_size = read_32bitBE(check_offset,streamFile);
-
- /* expect at least the block header */
- if (block_size < 0x10) goto fail;
-
- /* expect the channel numbers to alternate */
- if (i%channel_count+1 != read_32bitBE(check_offset+8,streamFile)) goto fail;
-
- /* expect every block in a set of channels to have the same size */
- if (i%channel_count==0) block_size_has_been = block_size;
- else if (block_size != block_size_has_been) goto fail;
-
- /* get an estimate of block size for buffer sizing */
- if (block_size > est_block_size) est_block_size = block_size;
-
- check_offset += block_size;
- }
- }
-
- /* look at DSP headers */
-
- {
- off_t check_offset;
- int i;
-
- check_offset = read_32bitBE(0x0,streamFile);
-
- for (i=0;inum_samples = header[0].sample_count/14*14;
- vgmstream->sample_rate = header[0].sample_rate;
-
- vgmstream->loop_start_sample = dsp_nibbles_to_samples(
- header[0].loop_start_offset);
- vgmstream->loop_end_sample = dsp_nibbles_to_samples(
- header[0].loop_end_offset)+1;
-
- /* don't know why, but it does happen*/
- if (vgmstream->loop_end_sample > vgmstream->num_samples)
- vgmstream->loop_end_sample = vgmstream->num_samples;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_wsi_blocked;
- vgmstream->meta_type = meta_DSP_WSI;
-
- /* coeffs */
- {
- int i,j;
- for (j=0;jch[j].adpcm_coef[i] = header[j].coef[i];
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[j].adpcm_history1_16 = header[j].initial_hist1;
- vgmstream->ch[j].adpcm_history2_16 = header[j].initial_hist2;
- }
- }
-
-
- /* open the file for reading */
- vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,est_block_size*4);
-
- if (!vgmstream->ch[0].streamfile) goto fail;
-
- wsi_block_update(read_32bitBE(0,streamFile),vgmstream);
-
- {
- int i;
-
- for (i=0;ich[i].streamfile = vgmstream->ch[0].streamfile;
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=start_offset[i];
- }
-
- }
-
- /* first block isn't full of musics */
- vgmstream->current_block_size -= 0x60;
-
- return vgmstream;
-
-fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
- return NULL;
-}
-
-
-/* SWD (found in Conflict - Desert Storm 1 & 2 */
+/* SWD - PSF chunks + interleaved dsps [Conflict: Desert Storm 1 & 2] */
VGMSTREAM * init_vgmstream_ngc_swd(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- off_t start_offset;
- off_t interleave;
+ dsp_meta dspm = {0};
- struct dsp_header ch0_header, ch1_header;
- int i;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("swd",filename_extension(filename))) goto fail;
-
- if (read_dsp_header(&ch0_header, 0x08, streamFile)) goto fail;
- if (read_dsp_header(&ch1_header, 0x68, streamFile)) goto fail;
-
- /* check header magic */
- if (read_32bitBE(0x00,streamFile) != 0x505346D1) /* PSF\0xD1 */
+ /* checks */
+ if (!check_extensions(streamFile, "swd"))
goto fail;
- start_offset = 0xC8;
- interleave = 0x8;
+ //todo blocked layout when first chunk is 0x50534631 (count + table of 0x0c with offset/sizes)
-#if 0
- /* check initial predictor/scale */
- if (ch0_header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile))
- goto fail;
- if (ch1_header.initial_ps != (uint8_t)read_8bit(start_offset+interleave,streamFile))
- goto fail;
-#endif
-
- /* check type==0 and gain==0 */
- if (ch0_header.format || ch0_header.gain ||
- ch1_header.format || ch1_header.gain)
+ if (read_32bitBE(0x00,streamFile) != 0x505346d1) /* PSF\0xd1 */
goto fail;
- /* check for agreement */
- if (
- ch0_header.sample_count != ch1_header.sample_count ||
- ch0_header.nibble_count != ch1_header.nibble_count ||
- ch0_header.sample_rate != ch1_header.sample_rate ||
- ch0_header.loop_flag != ch1_header.loop_flag ||
- ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
- ch0_header.loop_end_offset != ch1_header.loop_end_offset
- ) goto fail;
+ dspm.channel_count = 2;
+ dspm.max_channels = 2;
-#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,ch0_header.loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch0_header.sample_count;
- vgmstream->sample_rate = ch0_header.sample_rate;
-
- /* TODO: adjust for interleave? */
- 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;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = interleave;
- vgmstream->meta_type = meta_NGC_SWD;
-
- /* coeffs */
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
- vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
- vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
- vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
-
- vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- vgmstream->ch[1].streamfile = vgmstream->ch[0].streamfile;
-
- if (!vgmstream->ch[0].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;
+ dspm.header_offset = 0x08;
+ dspm.header_spacing = 0x60;
+ dspm.start_offset = dspm.header_offset + 0x60 * dspm.channel_count;
+ dspm.interleave = 0x08;
+ dspm.meta_type = meta_NGC_SWD;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
@@ -1219,7 +821,7 @@ fail:
Lego Indiana Jones - The Original Adventures (Wii)
Lego Indiana Jones 2 - The Adventure Continues (Wii)
Lego Star Wars - The Complete Saga (Wii)
- Lego The Lord of the Rings (Wii)
+ Lego The Lord of the Rings (Wii)
The Chronicles of Narnia - Prince Caspian (Wii) */
VGMSTREAM * init_vgmstream_wii_idsp(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
@@ -1232,7 +834,7 @@ VGMSTREAM * init_vgmstream_wii_idsp(STREAMFILE *streamFile) {
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if ((strcasecmp("gcm",filename_extension(filename))) &&
- (strcasecmp("idsp",filename_extension(filename))))
+ (strcasecmp("idsp",filename_extension(filename))))
goto fail;
/* check header magic */
@@ -1255,14 +857,14 @@ VGMSTREAM * init_vgmstream_wii_idsp(STREAMFILE *streamFile) {
start_offset = 0xe0;
}
- else if (read_32bitBE(0x4, streamFile) == 3 && //Lego The Lord of the Rings (Wii)
- read_32bitBE(0x8, streamFile) == 0x12c)
- {
- if (read_dsp_header(&ch0_header, 0x20, streamFile)) goto fail;
- if (read_dsp_header(&ch1_header, 0x80, streamFile)) goto fail;
+ else if (read_32bitBE(0x4, streamFile) == 3 && //Lego The Lord of the Rings (Wii)
+ read_32bitBE(0x8, streamFile) == 0x12c)
+ {
+ if (read_dsp_header(&ch0_header, 0x20, streamFile)) goto fail;
+ if (read_dsp_header(&ch1_header, 0x80, streamFile)) goto fail;
- start_offset = 0xe0;
- }
+ start_offset = 0xe0;
+ }
else goto fail;
interleave = read_32bitBE(0xc, streamFile);
@@ -1309,10 +911,8 @@ VGMSTREAM * init_vgmstream_wii_idsp(STREAMFILE *streamFile) {
vgmstream->sample_rate = ch0_header.sample_rate;
/* TODO: adjust for interleave? */
- 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;
+ 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;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
@@ -1350,1281 +950,306 @@ fail:
return NULL;
}
-/* .wsd files, two DSP files stuck together */
-/* found in Phantom Brave Wii */
+/* .wsd - Custom header + full interleaved dsp [Phantom Brave (Wii)] */
VGMSTREAM * init_vgmstream_wii_wsd(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
+ dsp_meta dspm = {0};
- off_t channel_1_start, channel_2_start, channel_1_size, channel_2_size;
-
- struct dsp_header ch0_header,ch1_header;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("wsd",filename_extension(filename))) goto fail;
-
- /* read .wsd header */
- channel_1_start = read_32bitBE(0x0,streamFile);
- channel_2_start = read_32bitBE(0x4,streamFile);
- channel_1_size = read_32bitBE(0x8,streamFile);
- channel_2_size = read_32bitBE(0xc,streamFile);
-
- /* check header */
- if (channel_1_size != channel_2_size) goto fail;
- if (channel_1_start != 0x20) goto fail;
- if (channel_1_size < 0x20 || channel_2_size < 0x20) goto fail;
- if (channel_1_start + channel_1_size > channel_2_start) goto fail;
- if (channel_2_start + channel_2_size > get_streamfile_size(streamFile))
+ /* checks */
+ if (!check_extensions(streamFile, "wsd"))
+ goto fail;
+ if (read_32bitBE(0x08,streamFile) != read_32bitBE(0x0c,streamFile)) /* channel sizes */
goto fail;
- /* get DSP headers */
- if (read_dsp_header(&ch0_header, channel_1_start, streamFile)) goto fail;
- if (read_dsp_header(&ch1_header, channel_2_start, streamFile)) goto fail;
+ dspm.channel_count = 2;
+ dspm.max_channels = 2;
- /* check initial predictor/scale */
- if (ch0_header.initial_ps !=
- (uint8_t)read_8bit(channel_1_start + 0x60, streamFile))
- goto fail;
-
- if (ch1_header.initial_ps !=
- (uint8_t)read_8bit(channel_2_start + 0x60, streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch0_header.format || ch0_header.gain ||
- ch1_header.format || ch1_header.gain)
- goto fail;
-
- /* check for agreement */
- if (
- ch0_header.sample_count != ch1_header.sample_count ||
- ch0_header.nibble_count != ch1_header.nibble_count ||
- ch0_header.sample_rate != ch1_header.sample_rate ||
- ch0_header.loop_flag != ch1_header.loop_flag ||
- ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
- ch0_header.loop_end_offset != ch1_header.loop_end_offset
- ) goto fail;
-
- if (ch0_header.loop_flag) {
- off_t loop_off;
- /* check loop predictor/scale */
- loop_off = ch0_header.loop_start_offset/16*8;
- if (ch0_header.loop_ps !=
- (uint8_t)read_8bit(channel_1_start+0x60+loop_off,streamFile))
- goto fail;
- if (ch1_header.loop_ps !=
- (uint8_t)read_8bit(channel_2_start+0x60+loop_off,streamFile))
- goto fail;
- }
-
- /* build the VGMSTREAM */
-
- vgmstream = allocate_vgmstream(2,ch0_header.loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch0_header.sample_count;
- vgmstream->sample_rate = ch0_header.sample_rate;
-
- 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;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_none;
- vgmstream->meta_type = meta_DSP_WII_WSD;
-
- /* coeffs */
- {
- int i;
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
- vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
- }
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
- vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
- vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
-
- /* open the file for reading */
- 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;
-
- vgmstream->ch[0].channel_start_offset =
- vgmstream->ch[0].offset=channel_1_start+0x60;
- vgmstream->ch[1].channel_start_offset =
- vgmstream->ch[1].offset=channel_2_start+0x60;
-
- return vgmstream;
+ dspm.header_offset = read_32bitBE(0x00,streamFile);
+ dspm.header_spacing = read_32bitBE(0x04,streamFile) - dspm.header_offset;
+ dspm.start_offset = dspm.header_offset + 0x60;
+ dspm.interleave = dspm.header_spacing;
+ dspm.meta_type = meta_DSP_WII_WSD;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
-
-/* .ddsp files, two DSP files stuck together, without additional header */
+/* .ddsp - full interleaved dsp [The Sims 2 - Pets (Wii)] */
VGMSTREAM * init_vgmstream_dsp_ddsp(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
+ dsp_meta dspm = {0};
- off_t channel_1_start, channel_2_start, channel_1_size, channel_2_size;
-
- struct dsp_header ch0_header,ch1_header;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("ddsp",filename_extension(filename))) goto fail;
-
- /* read .wsd header */
- channel_1_start = 0;
- channel_2_start = (get_streamfile_size(streamFile)/2);
- channel_1_size = (get_streamfile_size(streamFile)/2)-0x60;
- channel_2_size = (get_streamfile_size(streamFile)/2)-0x60;
-
- /* check header */
- if (channel_1_size != channel_2_size) goto fail;
- if (channel_1_start != 0x0) goto fail;
- if (channel_1_size < 0x20 || channel_2_size < 0x20) goto fail;
- if (channel_1_start + channel_1_size > channel_2_start) goto fail;
- if (channel_2_start + channel_2_size > get_streamfile_size(streamFile))
+ /* checks */
+ if (!check_extensions(streamFile, "ddsp"))
goto fail;
- /* get DSP headers */
- if (read_dsp_header(&ch0_header, channel_1_start, streamFile)) goto fail;
- if (read_dsp_header(&ch1_header, channel_2_start, streamFile)) goto fail;
+ dspm.channel_count = 2;
+ dspm.max_channels = 2;
- /* check initial predictor/scale */
- if (ch0_header.initial_ps !=
- (uint8_t)read_8bit(channel_1_start + 0x60, streamFile))
- goto fail;
-
- if (ch1_header.initial_ps !=
- (uint8_t)read_8bit(channel_2_start + 0x60, streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch0_header.format || ch0_header.gain ||
- ch1_header.format || ch1_header.gain)
- goto fail;
-
- /* check for agreement */
- if (
- ch0_header.sample_count != ch1_header.sample_count ||
- ch0_header.nibble_count != ch1_header.nibble_count ||
- ch0_header.sample_rate != ch1_header.sample_rate ||
- ch0_header.loop_flag != ch1_header.loop_flag ||
- ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
- ch0_header.loop_end_offset != ch1_header.loop_end_offset
- ) goto fail;
-
- if (ch0_header.loop_flag) {
- off_t loop_off;
- /* check loop predictor/scale */
- loop_off = ch0_header.loop_start_offset/16*8;
- if (ch0_header.loop_ps !=
- (uint8_t)read_8bit(channel_1_start+0x60+loop_off,streamFile))
- goto fail;
- if (ch1_header.loop_ps !=
- (uint8_t)read_8bit(channel_2_start+0x60+loop_off,streamFile))
- goto fail;
- }
-
- /* build the VGMSTREAM */
-
- vgmstream = allocate_vgmstream(2,ch0_header.loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch0_header.sample_count;
- vgmstream->sample_rate = ch0_header.sample_rate;
-
- 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;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_none;
- vgmstream->meta_type = meta_DSP_DDSP;
-
- /* coeffs */
- {
- int i;
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
- vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
- }
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
- vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
- vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
-
- /* open the file for reading */
- 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;
-
- vgmstream->ch[0].channel_start_offset =
- vgmstream->ch[0].offset=channel_1_start+0x60;
- vgmstream->ch[1].channel_start_offset =
- vgmstream->ch[1].offset=channel_2_start+0x60;
-
- return vgmstream;
+ dspm.header_offset = 0x00;
+ dspm.header_spacing = (get_streamfile_size(streamFile) / dspm.channel_count);
+ dspm.start_offset = 0x60;
+ dspm.interleave = dspm.header_spacing;
+ dspm.meta_type = meta_DSP_DDSP;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
-
-/* .was files, DSP file(s), with additional iSWS header */
+/* iSWS - Sumo Digital header + interleaved dsp [DiRT 2 (Wii), F1 2009 (Wii)] */
VGMSTREAM * init_vgmstream_wii_was(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- struct dsp_header ch0_header,ch1_header;
- off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start;
- int channel_count;
- int i;
+ dsp_meta dspm = {0};
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if ((strcasecmp("dsp",filename_extension(filename))) &&
- (strcasecmp("isws",filename_extension(filename))) &&
- (strcasecmp("was",filename_extension(filename))))
- goto fail;
+ /* checks */
+ if (!check_extensions(streamFile, "was,dsp,isws"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x69535753) /* "iSWS" */
+ goto fail;
- /* read iSWS header */
- if (read_32bitBE(0x0,streamFile) != 0x69535753)
- goto fail;
+ dspm.channel_count = read_32bitBE(0x08,streamFile);
+ dspm.max_channels = 2;
- channel_count = read_32bitBE(0x08,streamFile);
-
- if (channel_count == 1)
- {
-
- ch1_header_start = 0x20;
- ch1_start = 0x80;
-
- /* get DSP headers */
- if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail;
-
- /* check initial predictor/scale */
- if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch0_header.format || ch0_header.gain)
- goto fail;
-
- if (ch0_header.loop_flag)
- {
- off_t loop_off;
- /* check loop predictor/scale */
- loop_off = ch0_header.loop_start_offset/16*8;
- if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile))
- goto fail;
- }
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(1,ch0_header.loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch0_header.sample_count;
- vgmstream->sample_rate = ch0_header.sample_rate;
-
- 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;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_none;
- vgmstream->meta_type = meta_WII_WAS;
-
- /* coeffs */
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
-
- /* open the file for reading */
- vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[0].streamfile)
- goto fail;
- vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start;
-
- }
- else if (channel_count == 2)
- {
-
-
- ch1_header_start = 0x20;
- ch2_header_start = 0x80;
- ch1_start = 0xE0;
- ch2_start = 0xE0 + (read_32bitBE(0x10,streamFile));
-
- /* get DSP headers */
- if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail;
- if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail;
-
- /* check initial predictor/scale */
- if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile))
- goto fail;
- if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch0_header.format || ch0_header.gain)
- goto fail;
- if (ch1_header.format || ch1_header.gain)
- goto fail;
-
- /* check for agreement */
- if (
- ch0_header.sample_count != ch1_header.sample_count ||
- ch0_header.nibble_count != ch1_header.nibble_count ||
- ch0_header.sample_rate != ch1_header.sample_rate ||
- ch0_header.loop_flag != ch1_header.loop_flag ||
- ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
- ch0_header.loop_end_offset != ch1_header.loop_end_offset
- ) goto fail;
-
- if (ch0_header.loop_flag)
- {
- off_t loop_off;
- /* check loop predictor/scale */
- loop_off = ch0_header.loop_start_offset/16*8;
-
- if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile))
- goto fail;
- if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile))
- goto fail;
- }
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(2,ch0_header.loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch0_header.sample_count;
- vgmstream->sample_rate = ch0_header.sample_rate;
-
- 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;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = read_32bitBE(0x10,streamFile);
- vgmstream->meta_type = meta_WII_WAS;
-
- /* coeffs */
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
- vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
- vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
- vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
-
- /* open the file for reading */
- vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[0].streamfile)
- goto fail;
- vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start;
-
- vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[1].streamfile)
- goto fail;
- vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start;
-
- }
- else
- {
- goto fail;
- }
-
- return vgmstream;
-
+ dspm.header_offset = 0x08 + read_32bitBE(0x04,streamFile);
+ dspm.header_spacing = 0x60;
+ dspm.start_offset = dspm.header_offset + dspm.channel_count*dspm.header_spacing;
+ dspm.interleave = read_32bitBE(0x10,streamFile);
+ dspm.meta_type = meta_WII_WAS;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
-
-/* .str found in Micro Machines, Superman: Shadow of Apokolips */
+/* .str - Infogrames raw interleaved dsp [Micro Machines (GC), Superman: Shadow of Apokolips (GC)] */
VGMSTREAM * init_vgmstream_dsp_str_ig(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- struct dsp_header ch0_header,ch1_header;
- off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start;
- int channel_count;
- int i;
+ dsp_meta dspm = {0};
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("str",filename_extension(filename)))
- goto fail;
+ /* checks */
+ if (!check_extensions(streamFile, "str"))
+ goto fail;
- channel_count = 2;
+ dspm.channel_count = 2;
+ dspm.max_channels = 2;
- ch1_header_start = 0x00;
- ch2_header_start = 0x80;
- ch1_start = 0x800;
- ch2_start = 0x4800;
-
- /* get DSP headers */
- if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail;
- if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail;
+ dspm.header_offset = 0x00;
+ dspm.header_spacing = 0x80;
+ dspm.start_offset = 0x800;
+ dspm.interleave = 0x4000;
- /* check initial predictor/scale */
- if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile))
- goto fail;
- if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch0_header.format || ch0_header.gain)
- goto fail;
- if (ch1_header.format || ch1_header.gain)
- goto fail;
-
- /* check for agreement */
- if (
- ch0_header.sample_count != ch1_header.sample_count ||
- ch0_header.nibble_count != ch1_header.nibble_count ||
- ch0_header.sample_rate != ch1_header.sample_rate ||
- ch0_header.loop_flag != ch1_header.loop_flag ||
- ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
- ch0_header.loop_end_offset != ch1_header.loop_end_offset
- ) goto fail;
-
- if (ch0_header.loop_flag)
- {
- off_t loop_off;
- /* check loop predictor/scale */
- loop_off = ch0_header.loop_start_offset/16*8;
-
- if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile))
- goto fail;
- if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile))
- goto fail;
- }
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(channel_count, ch0_header.loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch0_header.sample_count;
- vgmstream->sample_rate = ch0_header.sample_rate;
-
- 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;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = 0x4000;
- vgmstream->meta_type = meta_DSP_STR_IG;
-
- /* coeffs */
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
- vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
- vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
- vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
-
- /* open the file for reading */
- vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[0].streamfile)
- goto fail;
- vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start;
-
- vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[1].streamfile)
- goto fail;
- vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start;
-
- return vgmstream;
-
-
+ dspm.meta_type = meta_DSP_STR_IG;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
-/* .dsp found in: Speed Challenge - Jacques Villeneuve's Racing Vision (NGC)
- XIII (NGC)
- always 2 channels, and an interleave of 0x8 */
+/* .dsp - Ubisoft interleaved dsp with bad loop start [Speed Challenge: Jacques Villeneuve's Racing Vision (GC), XIII (GC)] */
VGMSTREAM * init_vgmstream_dsp_xiii(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- struct dsp_header ch0_header,ch1_header;
- off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start;
- int channel_count;
- int i;
+ dsp_meta dspm = {0};
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("dsp",filename_extension(filename)))
- goto fail;
+ /* checks */
+ if (!check_extensions(streamFile, "dsp"))
+ goto fail;
- channel_count = 2;
-
- ch1_header_start = 0x00;
- ch2_header_start = 0x60;
- ch1_start = 0xC0;
- ch2_start = 0xC8;
-
- /* get DSP headers */
- if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail;
- if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail;
-
- /* check initial predictor/scale */
- if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile))
- goto fail;
- if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch0_header.format || ch0_header.gain)
- goto fail;
- if (ch1_header.format || ch1_header.gain)
- goto fail;
-
- /* check for agreement */
- if (
- ch0_header.sample_count != ch1_header.sample_count ||
- ch0_header.nibble_count != ch1_header.nibble_count ||
- ch0_header.sample_rate != ch1_header.sample_rate ||
- ch0_header.loop_flag != ch1_header.loop_flag ||
- //ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
- ch0_header.loop_end_offset != ch1_header.loop_end_offset
- ) goto fail;
-
- if (ch0_header.loop_flag)
- {
- off_t loop_off;
- /* check loop predictor/scale */
- loop_off = 0x0; //ch0_header.loop_start_offset/16*8;
-
- if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile))
- goto fail;
- if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile))
- goto fail;
- }
-
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(channel_count, ch1_header.loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch0_header.sample_count;
- vgmstream->sample_rate = ch0_header.sample_rate;
-
- vgmstream->loop_start_sample = 0x0; //dsp_nibbles_to_samples(ch0_header.loop_start_offset);
- vgmstream->loop_end_sample = dsp_nibbles_to_samples(
- ch0_header.loop_end_offset)+1;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = 0x8;
- vgmstream->meta_type = meta_DSP_XIII;
-
- /* coeffs */
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
- vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
- vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
- vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
-
- /* open the file for reading */
- vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[0].streamfile)
- goto fail;
- vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start;
-
- vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[1].streamfile)
- goto fail;
- vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start;
-
- return vgmstream;
+ dspm.channel_count = 2;
+ dspm.max_channels = 2;
+ dspm.fix_loop_start = 1; /* loop flag but strange loop start instead of 0 (maybe shouldn't loop) */
+ dspm.header_offset = 0x00;
+ dspm.header_spacing = 0x60;
+ dspm.start_offset = dspm.header_offset + dspm.header_spacing * dspm.channel_count;
+ dspm.interleave = 0x08;
+ dspm.meta_type = meta_DSP_XIII;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
-
-/* .ndp found in Vertigo (WII) */
+/* NPD - Icon Games header + subinterleaved DSPs [Vertigo (Wii), Build n' Race (Wii)] */
VGMSTREAM * init_vgmstream_wii_ndp(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- struct dsp_header ch0_header,ch1_header;
- off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start;
- int i;
+ dsp_meta dspm = {0};
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("ndp",filename_extension(filename)))
- goto fail;
-
- /* check header */
- if (read_32bitBE(0x0,streamFile) != 0x4E445000) /* NDP */
- goto fail;
-
- /* check size */
- if ((read_32bitLE(0x8,streamFile)+0x18 != get_streamfile_size(streamFile))) /* NDP */
- goto fail;
-
- //channel_count = (read_16bitLE(0x10,streamFile) != 2);
-
- ch1_header_start = 0x18;
- ch2_header_start = 0x78;
- ch1_start = 0xD8;
- ch2_start = 0xDC;
-
- /* get DSP headers */
- if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail;
- if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail;
-
- /* check initial predictor/scale */
- if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile))
- goto fail;
- if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch0_header.format || ch0_header.gain)
- goto fail;
- if (ch1_header.format || ch1_header.gain)
- goto fail;
-
- /* check for agreement */
- if (
- ch0_header.sample_count != ch1_header.sample_count ||
- ch0_header.nibble_count != ch1_header.nibble_count ||
- ch0_header.sample_rate != ch1_header.sample_rate ||
- ch0_header.loop_flag != ch1_header.loop_flag ||
- ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
- ch0_header.loop_end_offset != ch1_header.loop_end_offset
- ) goto fail;
-
- if (ch0_header.loop_flag)
- {
- off_t loop_off;
- /* check loop predictor/scale */
- loop_off = ch0_header.loop_start_offset/16*8;
-
- if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile))
- goto fail;
- if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile))
- goto fail;
- }
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(2, ch0_header.loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch0_header.sample_count;
- vgmstream->sample_rate = ch0_header.sample_rate;
-
- 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;
-
- vgmstream->coding_type = coding_NGC_DSP_subint;
- vgmstream->layout_type = layout_none;
- vgmstream->interleave_block_size = 0x4;
- vgmstream->meta_type = meta_WII_NDP;
-
- /* coeffs */
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
- vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
- vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
- vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
-
- /* open the file for reading */
- if (!vgmstream_open_stream(vgmstream,streamFile,ch1_start))
+ /* checks */
+ if (!check_extensions(streamFile, "ndp"))
goto fail;
- return vgmstream;
+ if (read_32bitBE(0x00,streamFile) != 0x4E445000) /* "NDP\0" */
+ goto fail;
+ if (read_32bitLE(0x08,streamFile) + 0x18 != get_streamfile_size(streamFile))
+ goto fail;
+ /* 0x0c: sample rate */
+ dspm.channel_count = read_32bitLE(0x10,streamFile);
+ dspm.max_channels = 2;
+
+ dspm.header_offset = 0x18;
+ dspm.header_spacing = 0x60;
+ dspm.start_offset = dspm.header_offset + dspm.channel_count*dspm.header_spacing;
+ dspm.interleave = 0x04;
+
+ dspm.meta_type = meta_WII_NDP;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
- close_vgmstream(vgmstream);
return NULL;
}
-/* found in "Cabelas" games, always stereo, looped and an interleave of 0x10 bytes */
+/* Cabela's series (Magic Wand dev?) - header + interleaved dsp [Cabela's Big Game Hunt 2005 Adventures (GC), Cabela's Outdoor Adventures (GC)] */
VGMSTREAM * init_vgmstream_dsp_cabelas(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- struct dsp_header ch0_header,ch1_header;
- off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start;
- int channel_count;
- int i;
+ dsp_meta dspm = {0};
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("dsp",filename_extension(filename)))
- goto fail;
-
- channel_count = 2;
-
- ch1_header_start = 0x00;
- ch2_header_start = 0x60;
- ch1_start = 0xC0;
- ch2_start = 0xD0;
-
- /* get DSP headers */
- if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail;
- if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail;
-
- /* check initial predictor/scale */
- if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile))
- goto fail;
- if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch0_header.format || ch0_header.gain)
- goto fail;
- if (ch1_header.format || ch1_header.gain)
- goto fail;
-
- /* check for agreement */
- if (
- ch0_header.sample_count != ch1_header.sample_count ||
- ch0_header.nibble_count != ch1_header.nibble_count ||
- ch0_header.sample_rate != ch1_header.sample_rate ||
- ch0_header.loop_flag != ch1_header.loop_flag ||
- ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
- ch0_header.loop_end_offset != ch1_header.loop_end_offset
- ) goto fail;
-
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(channel_count, 1);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch0_header.sample_count;
- vgmstream->sample_rate = ch0_header.sample_rate;
-
- vgmstream->loop_start_sample = 0;
- vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch0_header.loop_end_offset)+1;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = 0x10;
- vgmstream->meta_type = meta_DSP_CABELAS;
-
- /* coeffs */
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
- vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
- vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
- vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
-
- /* open the file for reading */
- vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[0].streamfile)
- goto fail;
- vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start;
-
- vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[1].streamfile)
- goto fail;
- vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start;
-
- return vgmstream;
-
-
-fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
- return NULL;
-}
-
-
-
-/* dual dsp header with additional "AAAp" header, found in Vexx (NGC) and Turok: Evolution (NGC) */
-VGMSTREAM * init_vgmstream_ngc_dsp_aaap(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- struct dsp_header ch0_header,ch1_header;
- off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start;
- int channel_count;
- int i;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("dsp",filename_extension(filename)))
- goto fail;
-
- /* check header */
- if (read_32bitBE(0x0,streamFile) != 0x41414170) /* AAAp */
- goto fail;
-
- channel_count = (uint16_t)read_16bitBE(0x6,streamFile);
-
- ch1_header_start = 0x08;
- ch2_header_start = 0x68;
- ch1_start = 0xC8;
- ch2_start = ch1_start + (uint16_t)read_16bitBE(0x4,streamFile);
-
- /* get DSP headers */
- if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail;
- if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail;
-
- /* check initial predictor/scale */
- if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile))
- goto fail;
- if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch0_header.format || ch0_header.gain)
- goto fail;
- if (ch1_header.format || ch1_header.gain)
- goto fail;
-
- /* check for agreement */
- if (
- ch0_header.sample_count != ch1_header.sample_count ||
- ch0_header.nibble_count != ch1_header.nibble_count ||
- ch0_header.sample_rate != ch1_header.sample_rate ||
- ch0_header.loop_flag != ch1_header.loop_flag ||
- ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
- ch0_header.loop_end_offset != ch1_header.loop_end_offset
- ) goto fail;
-
- if (ch0_header.loop_flag)
- {
- off_t loop_off;
- /* check loop predictor/scale */
- loop_off = ch0_header.loop_start_offset/16*8;
-
- if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile))
- goto fail;
- if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile))
- goto fail;
- }
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(channel_count,ch0_header.loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch0_header.sample_count;
- vgmstream->sample_rate = ch0_header.sample_rate;
-
- 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;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = ch2_start-ch1_start;
- vgmstream->meta_type = meta_NGC_DSP_AAAP;
-
- /* coeffs */
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
- vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
- vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
- vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
-
- /* open the file for reading */
- vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[0].streamfile)
- goto fail;
- vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start;
-
- vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[1].streamfile)
- goto fail;
- vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start;
-
- return vgmstream;
-
-fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
- return NULL;
-}
-
-
-/* .dspw files, multiple DSP files stuck together */
-/* found in Sengoku Basara 3 Wii */
-VGMSTREAM * init_vgmstream_dsp_dspw(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
-
- off_t streamSize, mrkrOffset, channelSpacing;
- int channel_count, i, j;
- int found_mrkr = 0;
- VARDECL(struct dsp_header, ch_header);
- VARDECL(off_t, channel_start);
-
- channel_count = (unsigned char)read_8bit(0x1B, streamFile);
-
- ALLOC(ch_header, channel_count, struct dsp_header);
- ALLOC(channel_start, channel_count, off_t);
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("dspw",filename_extension(filename))) goto fail;
-
- if (read_32bitBE(0x0,streamFile) != 0x44535057) // DSPW
- goto fail;
-
- streamSize = read_32bitBE(0x8, streamFile);
-
-
- if (read_32bitBE(streamSize - 0x10, streamFile) == 0x74494D45) // tIME
- streamSize -= 0x10;
-
- mrkrOffset = streamSize - 4;
- while ((mrkrOffset > streamSize - 0x1000) && !(found_mrkr)) { // some files have a mrkr section with multiple loop regions at the end
- if (read_32bitBE(mrkrOffset, streamFile) != 0x6D726B72) // mrkr
- mrkrOffset -= 4;
- else {
- streamSize = mrkrOffset;
- found_mrkr++;
- }
- }
- streamSize -= 0x20; // minus the main header
- channelSpacing = streamSize / channel_count;
-
- /* read .dspw header */
- for (i = 0; i < channel_count; i++) {
- channel_start[i] = 0x20 + i*channelSpacing;
-
- /* get DSP headers */
- if (read_dsp_header(&ch_header[i], channel_start[i], streamFile)) goto fail;
-
- /* check initial predictor/scale */
- if (ch_header[i].initial_ps !=
- (uint8_t)read_8bit(channel_start[i] + 0x60, streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch_header[i].format || ch_header[i].gain)
- goto fail;
-
- /* check for agreement */
- if (i > 0) {
- if (
- ch_header[i].sample_count != ch_header[i-1].sample_count ||
- ch_header[i].nibble_count != ch_header[i-1].nibble_count ||
- ch_header[i].sample_rate != ch_header[i-1].sample_rate ||
- ch_header[i].loop_flag != ch_header[i-1].loop_flag ||
- ch_header[i].loop_start_offset != ch_header[i-1].loop_start_offset ||
- ch_header[i].loop_end_offset != ch_header[i-1].loop_end_offset
- ) goto fail;
- }
-
- if (ch_header[0].loop_flag) {
- off_t loop_off;
- /* check loop predictor/scale */
- loop_off = ch_header[0].loop_start_offset/16*8;
- if (ch_header[i].loop_ps !=
- (uint8_t)read_8bit(channel_start[i]+0x60+loop_off,streamFile))
- goto fail;
- }
- }
- /* build the VGMSTREAM */
-
- vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch_header[0].sample_count;
- vgmstream->sample_rate = ch_header[0].sample_rate;
-
- vgmstream->loop_start_sample = dsp_nibbles_to_samples(
- ch_header[0].loop_start_offset);
- vgmstream->loop_end_sample = dsp_nibbles_to_samples(
- ch_header[0].loop_end_offset)+1;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_none;
- // vgmstream->layout_type = layout_interleave;
- // vgmstream->interleave_block_size = channelSpacing;
- vgmstream->meta_type = meta_DSP_DSPW;
-
- /* coeffs */
- for (i=0;ich[i].adpcm_coef[j] = ch_header[i].coef[j];
- }
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[i].adpcm_history1_16 = ch_header[i].initial_hist1;
- vgmstream->ch[i].adpcm_history2_16 = ch_header[i].initial_hist2;
- }
-
-
-
- /* open the file for reading */
-
- for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[i].streamfile) goto fail;
-
- vgmstream->ch[i].channel_start_offset =
- vgmstream->ch[i].offset=channel_start[i]+0x60;
- }
-
- return vgmstream;
-
- /* clean up anything we may have opened */
-fail:
- if (vgmstream) close_vgmstream(vgmstream);
- return NULL;
-}
-
-
-/* dual dsp header with additional "iadp" header, found in Dr. Muto (NGC) */
-VGMSTREAM * init_vgmstream_ngc_dsp_iadp(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- struct dsp_header ch0_header,ch1_header;
- off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start;
- int channel_count;
- int i;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("iadp",filename_extension(filename)))
- goto fail;
-
- /* check header */
- if (read_32bitBE(0x0,streamFile) != 0x69616470) /* iadp */
- goto fail;
-
- channel_count = read_32bitBE(0x4,streamFile);
-
- if (channel_count != 0x2)
+ /* checks */
+ if (!check_extensions(streamFile, "dsp"))
+ goto fail;
+ /* has extra stuff in the reserved data, without it this meta may catch other DSPs it shouldn't */
+ if (read_32bitBE(0x50,streamFile) == 0 || read_32bitBE(0x54,streamFile) == 0)
goto fail;
-
- ch1_header_start = 0x20;
- ch2_header_start = 0x80;
- ch1_start = read_32bitBE(0x1C,streamFile);
- ch2_start = ch1_start + read_32bitBE(0x8,streamFile);
+ /* sfx are mono, but standard dsp will catch them tho */
+ dspm.channel_count = read_32bitBE(0x00,streamFile) == read_32bitBE(0x60,streamFile) ? 2 : 1;
+ dspm.max_channels = 2;
+ dspm.force_loop = (dspm.channel_count > 1);
- /* get DSP headers */
- if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail;
- if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail;
-
- /* check initial predictor/scale */
- if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile))
- goto fail;
- if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile))
- goto fail;
-
- /* check type==0 and gain==0 */
- if (ch0_header.format || ch0_header.gain)
- goto fail;
- if (ch1_header.format || ch1_header.gain)
- goto fail;
-
- /* check for agreement */
- if (
- ch0_header.sample_count != ch1_header.sample_count ||
- ch0_header.nibble_count != ch1_header.nibble_count ||
- ch0_header.sample_rate != ch1_header.sample_rate ||
- ch0_header.loop_flag != ch1_header.loop_flag ||
- ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
- ch0_header.loop_end_offset != ch1_header.loop_end_offset
- ) goto fail;
-
- if (ch0_header.loop_flag)
- {
- off_t loop_off;
- /* check loop predictor/scale */
- loop_off = ch0_header.loop_start_offset/16*8;
-
- if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile))
- goto fail;
- if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile))
- goto fail;
- }
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(channel_count,ch0_header.loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->num_samples = ch0_header.sample_count;
- vgmstream->sample_rate = ch0_header.sample_rate;
-
- 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;
-
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->interleave_block_size = read_32bitBE(0x8,streamFile);
- vgmstream->layout_type = layout_interleave;
- vgmstream->meta_type = meta_NGC_DSP_IADP;
-
- /* coeffs */
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
- vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
- }
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
- vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
- vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
- vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
- vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
-
- /* open the file for reading */
- vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[0].streamfile)
- goto fail;
- vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start;
-
- vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!vgmstream->ch[1].streamfile)
- goto fail;
- vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start;
-
- return vgmstream;
+ dspm.header_offset = 0x00;
+ dspm.header_spacing = 0x60;
+ dspm.start_offset = dspm.header_offset + dspm.channel_count*dspm.header_spacing;
+ dspm.interleave = 0x10;
+ dspm.meta_type = meta_DSP_CABELAS;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
-/* the csmp format from Metroid Prime 3 and DKCR */
+/* AAAp - Acclaim Austin Audio header + interleaved dsp [Vexx (GC), Turok: Evolution (GC)] */
+VGMSTREAM * init_vgmstream_ngc_dsp_aaap(STREAMFILE *streamFile) {
+ dsp_meta dspm = {0};
-#define CSMP_MAGIC 0x43534D50
-#define CSMP_DATA 0x44415441
+ /* checks */
+ if (!check_extensions(streamFile, "dsp"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x41414170) /* "AAAp" */
+ goto fail;
-struct csmp_chunk {
- uint32_t id;
- uint32_t length;
-};
+ dspm.channel_count = read_16bitBE(0x06,streamFile);
+ dspm.max_channels = 2;
+ dspm.header_offset = 0x08;
+ dspm.header_spacing = 0x60;
+ dspm.start_offset = dspm.header_offset + dspm.channel_count*dspm.header_spacing;
+ dspm.interleave = (uint16_t)read_16bitBE(0x04,streamFile);
+
+ dspm.meta_type = meta_NGC_DSP_AAAP;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
+fail:
+ return NULL;
+}
+
+/* DSPW - Capcom header + full interleaved DSP [Sengoku Basara 3 (Wii), Monster Hunter 3 Ultimate (WiiU)] */
+VGMSTREAM * init_vgmstream_dsp_dspw(STREAMFILE *streamFile) {
+ dsp_meta dspm = {0};
+ size_t data_size;
+
+ /* check extension */
+ if (!check_extensions(streamFile, "dspw"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x44535057) /* "DSPW" */
+ goto fail;
+
+ /* ignore time marker */
+ data_size = read_32bitBE(0x08, streamFile);
+ if (read_32bitBE(data_size - 0x10, streamFile) == 0x74494D45) /* "tIME" */
+ data_size -= 0x10; /* (ignore, 2 ints in YYYYMMDD hhmmss00) */
+
+ /* some files have a mrkr section with multiple loop regions added at the end (variable size) */
+ {
+ off_t mrkr_offset = data_size - 0x04;
+ off_t max_offset = data_size - 0x1000;
+ while (mrkr_offset > max_offset) {
+ if (read_32bitBE(mrkr_offset, streamFile) != 0x6D726B72) { /* "mrkr" */
+ mrkr_offset -= 0x04;
+ } else {
+ data_size = mrkr_offset;
+ break;
+ }
+ }
+ }
+ data_size -= 0x20; /* header size */
+ /* 0x10: loop start, 0x14: loop end, 0x1c: num_samples */
+
+ dspm.channel_count = read_32bitBE(0x18, streamFile);
+ dspm.max_channels = 6; /* 6ch in Monster Hunter 3 Ultimate */
+
+ dspm.header_offset = 0x20;
+ dspm.header_spacing = data_size / dspm.channel_count;
+ dspm.start_offset = dspm.header_offset + 0x60;
+ dspm.interleave = data_size / dspm.channel_count;
+
+ dspm.meta_type = meta_DSP_DSPW;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
+fail:
+ return NULL;
+}
+
+/* iadp - custom header + interleaved dsp [Dr. Muto (GC)] */
+VGMSTREAM * init_vgmstream_ngc_dsp_iadp(STREAMFILE *streamFile) {
+ dsp_meta dspm = {0};
+
+ /* checks */
+ /* .adp: actual extension, .iadp: header id */
+ if (!check_extensions(streamFile, "adp,iadp"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x69616470) /* "iadp" */
+ goto fail;
+
+ dspm.channel_count = read_32bitBE(0x04,streamFile);
+ dspm.max_channels = 2;
+
+ dspm.header_offset = 0x20;
+ dspm.header_spacing = 0x60;
+ dspm.start_offset = read_32bitBE(0x1C,streamFile);
+ dspm.interleave = read_32bitBE(0x08,streamFile);
+
+ dspm.meta_type = meta_NGC_DSP_IADP;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
+fail:
+ return NULL;
+}
+
+//todo might be only part of a full header?
+/* CSMP - Retro Studios header + interleaved DSPs [Metroid Prime 3 (Wii), Donkey Kong Country Returns (Wii)] */
VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
char filename[PATH_LIMIT];
long current_offset;
int tries;
-
struct dsp_header header;
- const off_t start_offset = 0x60;
- int i;
- int csmp_magic;
- int csmp_version;
+ int chanel_count, i;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("csmp",filename_extension(filename))) goto fail;
- current_offset = 0;
+ if (read_32bitBE(0x00, streamFile) != 0x43534D50) /* "CSMP" */
+ goto fail;
+ if (read_32bitBE(0x04, streamFile) != 1) /* version? */
+ goto fail;
- csmp_magic = read_32bitBE(current_offset, streamFile);
- if (csmp_magic != CSMP_MAGIC) goto fail;
+ chanel_count = 1;
+ start_offset = 0x60;
- current_offset += 4;
-
- csmp_version = read_32bitBE(current_offset, streamFile);
- if (csmp_version != 1) goto fail;
-
- current_offset += 4;
-
- tries =0;
- while (1)
- {
- struct csmp_chunk chunk;
+ current_offset = 0x08;
+ tries = 0;
+ while (1) {
+ uint32_t chunk_id, chunk_size;
if (tries > 4)
goto fail;
-
- chunk.id = read_32bitBE(current_offset, streamFile);
- chunk.length = read_32bitBE(current_offset + 4, streamFile);
- current_offset += 8;
- if (chunk.id != CSMP_DATA)
- {
- current_offset += chunk.length;
+
+ chunk_id = read_32bitBE(current_offset + 0x00, streamFile);
+ chunk_size = read_32bitBE(current_offset + 0x04, streamFile);
+ current_offset += 0x08;
+ if (chunk_id != 0x44415441) { /* "DATA" */
+ current_offset += chunk_size;
tries++;
continue;
}
@@ -2632,10 +1257,12 @@ VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) {
break;
}
- if (read_dsp_header(&header, current_offset, streamFile)) goto fail;
+ if (read_dsp_header(&header, current_offset, streamFile)) goto fail;
+
+
/* check initial predictor/scale */
- /* Retro doesn't seem to abide by this */
+ /* Retro doesn't seem to abide by this */
//if (header.initial_ps != (uint8_t)read_8bit(current_offset + start_offset,streamFile))
// goto fail;
@@ -2643,35 +1270,22 @@ VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) {
if (header.format || header.gain)
goto fail;
+ /* Retro doesn't seem to abide by this */
+ /* check loop predictor/scale */
if (header.loop_flag) {
-// off_t loop_off;
- /* check loop predictor/scale */
-// loop_off = header.loop_start_offset/16*8;
- /* Retro doesn't seem to abide by this */
+// off_t loop_off = header.loop_start_offset/16*8;
// if (header.loop_ps != (uint8_t)read_8bit(current_offset + start_offset+loop_off,streamFile))
// goto fail;
}
- /* compare num_samples with nibble count */
- /*
- fprintf(stderr,"num samples (literal): %d\n",read_32bitBE(0,streamFile));
- fprintf(stderr,"num samples (nibbles): %d\n",dsp_nibbles_to_samples(read_32bitBE(4,streamFile)));
- */
-
/* build the VGMSTREAM */
-
-
- vgmstream = allocate_vgmstream(1,header.loop_flag);
+ vgmstream = allocate_vgmstream(chanel_count,header.loop_flag);
if (!vgmstream) goto fail;
- /* fill in the vital statistics */
- vgmstream->num_samples = header.sample_count;
vgmstream->sample_rate = header.sample_rate;
-
- vgmstream->loop_start_sample = dsp_nibbles_to_samples(
- header.loop_start_offset);
- vgmstream->loop_end_sample = dsp_nibbles_to_samples(
- header.loop_end_offset)+1;
+ vgmstream->num_samples = header.sample_count;
+ vgmstream->loop_start_sample = dsp_nibbles_to_samples(header.loop_start_offset);
+ vgmstream->loop_end_sample = dsp_nibbles_to_samples(header.loop_end_offset)+1;
/* don't know why, but it does happen*/
if (vgmstream->loop_end_sample > vgmstream->num_samples)
@@ -2684,25 +1298,73 @@ VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) {
/* coeffs */
for (i=0;i<16;i++)
vgmstream->ch[0].adpcm_coef[i] = header.coef[i];
-
- /* initial history */
- /* always 0 that I've ever seen, but for completeness... */
vgmstream->ch[0].adpcm_history1_16 = header.initial_hist1;
vgmstream->ch[0].adpcm_history2_16 = header.initial_hist2;
/* open the file for reading */
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
-
if (!vgmstream->ch[0].streamfile) goto fail;
-
vgmstream->ch[0].channel_start_offset=
- vgmstream->ch[0].offset=current_offset + start_offset;
+ vgmstream->ch[0].offset=current_offset + start_offset;
return vgmstream;
fail:
- /* clean up anything we may have opened */
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
+/* .mcadpcm - Custom header + full interleaved dsp [Skyrim (Switch)] */
+VGMSTREAM * init_vgmstream_dsp_mcadpcm(STREAMFILE *streamFile) {
+ dsp_meta dspm = {0};
+
+ /* checks */
+ if (!check_extensions(streamFile, "mcadpcm"))
+ goto fail;
+ /* could validate dsp sizes but only for +1ch, check_dsp_samples will do it anyway */
+ //if (read_32bitLE(0x08,streamFile) != read_32bitLE(0x10,streamFile))
+ // goto fail;
+
+ dspm.channel_count = read_32bitLE(0x00,streamFile);
+ dspm.max_channels = 2;
+ dspm.little_endian = 1;
+
+ dspm.header_offset = read_32bitLE(0x04,streamFile);
+ dspm.header_spacing = dspm.channel_count == 1 ? 0 :
+ read_32bitLE(0x0c,streamFile) - dspm.header_offset; /* channel 2 start, only with Nch */
+ dspm.start_offset = dspm.header_offset + 0x60;
+ dspm.interleave = dspm.header_spacing;
+
+ dspm.meta_type = meta_DSP_MCADPCM;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
+fail:
+ return NULL;
+}
+
+/* .switch_audio - UE4 standard LE header + full interleaved dsp [Gal Gun 2 (Switch)] */
+VGMSTREAM * init_vgmstream_dsp_switch_audio(STREAMFILE *streamFile) {
+ dsp_meta dspm = {0};
+
+ /* checks */
+ /* .switch_audio: possibly UE4 class name rather than extension, .dsp: assumed */
+ if (!check_extensions(streamFile, "switch_audio,dsp"))
+ goto fail;
+
+ /* manual double header test */
+ if (read_32bitLE(0x00, streamFile) == read_32bitLE(get_streamfile_size(streamFile) / 2, streamFile))
+ dspm.channel_count = 2;
+ else
+ dspm.channel_count = 1;
+ dspm.max_channels = 2;
+ dspm.little_endian = 1;
+
+ dspm.header_offset = 0x00;
+ dspm.header_spacing = get_streamfile_size(streamFile) / dspm.channel_count;
+ dspm.start_offset = dspm.header_offset + 0x60;
+ dspm.interleave = dspm.header_spacing;
+
+ dspm.meta_type = meta_DSP_SWITCH_AUDIO;
+ return init_vgmstream_dsp_common(streamFile, &dspm);
+fail:
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ngc_pdt.c b/Frameworks/vgmstream/vgmstream/src/meta/ngc_pdt.c
index 8417c74d3..71c0556fb 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ngc_pdt.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ngc_pdt.c
@@ -1,101 +1,213 @@
#include "meta.h"
-#include "../util.h"
+#include "../coding/coding.h"
-/* PDT - Custom Generated File (Mario Party) */
+/* PDT - Hudson's stream container [Adventure Island (GC), Muscle Champion (GC), Mario Party series (GC)] */
VGMSTREAM * init_vgmstream_ngc_pdt(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- int loop_flag;
- int channel_count;
+ int loop_flag, channel_count, sample_rate;
+ size_t entries, nibble_size, loop_start;
+ off_t entries_offset, coefs_offset, header_offset;
+ off_t channel1_offset = 0, channel2_offset = 0, coef_offset = 0;
+ int total_subsongs, target_subsong = streamFile->stream_index;
+
+
+ /* checks */
+ if (!check_extensions(streamFile, "pdt"))
+ goto fail;
+
+ if (read_16bitBE(0x00,streamFile) != 0x01) /* version? */
+ goto fail;
+ if (read_32bitBE(0x04,streamFile) != 0x04) /* entry size? */
+ goto fail;
+ if (read_32bitBE(0x08,streamFile) != 0x7d00) /* not-sample rate? */
+ goto fail;
+ if (read_32bitBE(0x0c,streamFile) != 0x02 && /* not-channels? */
+ read_32bitBE(0x0c,streamFile) != 0x04)
+ goto fail;
+
+ entries = read_16bitBE(0x02,streamFile);
+ entries_offset = read_32bitBE(0x10,streamFile);
+ coefs_offset = read_32bitBE(0x14,streamFile);
+ //headers_offset = read_32bitBE(0x18,streamFile); /* we'll have pointers to those two */
+ //streams_offset = read_32bitBE(0x1c,streamFile);
+
+ /* find subsongs and target header, as entries can be empty/repeated */
+ {
+ /* tables to cache reads as it can be kinda slow with so many loops */
+ uint32_t data_offsets[0x2000];
+ uint32_t entry_offset, data_offset;
+ int i,j;
+
+ if (entries > 0x2000)
+ goto fail;
+
+ total_subsongs = 0;
+ if (target_subsong == 0) target_subsong = 1;
+
+ header_offset = 0;
+ for (i = 0; i < entries; i++) {
+ int is_unique = 1;
+
+ entry_offset = read_32bitBE(entries_offset + i*0x04,streamFile);
+ if (entry_offset == 0x00)
+ continue;
+ data_offset = read_32bitBE(entry_offset+0x10,streamFile);
+
+ /* check if current entry header was repeated (same file offset, difference in flags only) */
+ for (j = 0; j < total_subsongs; j++) {
+ if (data_offsets[j] == data_offset) {
+ is_unique = 0;
+ break;
+ }
+ }
+ if (!is_unique)
+ continue;
+
+ data_offsets[total_subsongs] = data_offset;
+ total_subsongs++;
+
+ /* target GET, but keep going to count subsongs */
+ if (!header_offset && target_subsong == total_subsongs) {
+ header_offset = entry_offset;
+ }
+ }
+ }
+
+ /* parse header */
+ {
+ uint8_t flags;
+ size_t coef1_entry;
+ off_t coef1_offset;
+
+ flags = read_8bit(header_offset+0x00,streamFile);
+ sample_rate = read_32bitBE(header_offset+0x04,streamFile);
+ /* 0x01: unknown + 0x4000 */
+ sample_rate = read_32bitBE(header_offset+0x04,streamFile);
+ nibble_size = read_32bitBE(header_offset+0x08,streamFile);
+ loop_start = read_32bitBE(header_offset+0x0c,streamFile);
+
+ channel1_offset = read_32bitBE(header_offset+0x10,streamFile);
+ coef1_entry = read_16bitBE(header_offset+0x14,streamFile);
+ coef1_offset = coefs_offset + coef1_entry*0x20;
+
+ if (flags & 0x01) {
+ //size_t coef2_entry;
+ //off_t coef2_offset;
+
+ channel2_offset = read_32bitBE(header_offset+0x18,streamFile);
+ /* always after coef1 in practice */
+ //coef2_entry = read_16bitBE(header_offset+0x1c,streamFile);
+ //coef2_offset = coefs_offset + coef2_entry*0x20;
+ //if (coef1_offset + 0x20 != coef2_offset)
+ // goto fail;
+ }
+
+ coef_offset = coef1_offset;
+ loop_flag = (flags & 0x02);
+ channel_count = (flags & 0x01) ? 2 : 1;
+ }
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count, loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = sample_rate;
+ //vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);//todo remove
+ vgmstream->num_samples = dsp_nibbles_to_samples(nibble_size);
+ //vgmstream->loop_start_sample = dsp_bytes_to_samples(loop_start, channel_count);//todo remove
+ vgmstream->loop_start_sample = dsp_nibbles_to_samples(loop_start);
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+
+ vgmstream->meta_type = meta_NGC_PDT;
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = layout_none;
+ dsp_read_coefs_be(vgmstream, streamFile, coef_offset, 0x20);
+
+ vgmstream->num_streams = total_subsongs;
+ vgmstream->stream_size = nibble_size / 2 * channel_count;
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,channel1_offset))
+ goto fail;
+
+ /* channels may start at slightly separated offsets */
+ if (channel_count == 2) {
+ vgmstream->ch[1].channel_start_offset =
+ vgmstream->ch[1].offset = channel2_offset;
+ }
+
+
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+
+/* PDT - custom fake header for split (PDTExt) .ptd [Mario Party (GC)] */
+VGMSTREAM * init_vgmstream_ngc_pdt_split(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
off_t start_offset;
- int second_channel_start = -1;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("pdt",filename_extension(filename))) goto fail;
+ int loop_flag, channel_count;
- /* check header */
- if (read_32bitBE(0x00,streamFile) != 0x50445420) /* "PDT " */
- goto fail;
- if (read_32bitBE(0x04,streamFile) != 0x44535020) /* "DSP " */
- goto fail;
- if (read_32bitBE(0x08,streamFile) != 0x48454144) /* "HEAD " */
- goto fail;
- if (read_16bitBE(0x0C,streamFile) != 0x4552) /* "ER " */
+
+ /* checks */
+ if (!check_extensions(streamFile, "pdt"))
goto fail;
- loop_flag = (read_32bitBE(0x1C,streamFile)!=2);
+ /* 0x10 fake header + chunks of the original header / data pasted together */
+ if (read_32bitBE(0x00,streamFile) != 0x50445420 && /* "PDT " */
+ read_32bitBE(0x04,streamFile) != 0x44535020 && /* "DSP " */
+ read_32bitBE(0x08,streamFile) != 0x48454144 && /* "HEAD " */
+ read_16bitBE(0x0C,streamFile) != 0x4552) /* "ER " */
+ goto fail;
+
+ start_offset = 0x800;
channel_count = (uint16_t)(read_16bitLE(0x0E,streamFile));
+ loop_flag = (read_32bitBE(0x1C,streamFile) != 2);
- /* build the VGMSTREAM */
+
+ /* 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(0x14,streamFile);
- vgmstream->coding_type = coding_NGC_DSP;
- if (channel_count == 1)
- {
- vgmstream->num_samples = read_32bitBE(0x18,streamFile)*14/8/channel_count/2;
+ if (channel_count == 1) {
+ vgmstream->num_samples = read_32bitBE(0x18,streamFile)*14/8/channel_count/2;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitBE(0x1C,streamFile)*14/8/channel_count/2;
vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile)*14/8/channel_count/2;
}
}
- else if (channel_count == 2)
- {
- vgmstream->num_samples = read_32bitBE(0x18,streamFile)*14/8/channel_count;
+ else if (channel_count == 2) {
+ vgmstream->num_samples = read_32bitBE(0x18,streamFile)*14/8/channel_count;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitBE(0x1C,streamFile)*14/8/channel_count;
vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile)*14/8/channel_count;
}
- second_channel_start = (get_streamfile_size(streamFile)+start_offset)/2;
}
- else
- {
- goto fail;
+ else {
+ goto fail;
}
- vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_NGC_PDT;
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = layout_none;
+ dsp_read_coefs_be(vgmstream, streamFile, 0x50, 0x20);
- if (vgmstream->coding_type == coding_NGC_DSP) {
- int i;
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x50+i*2,streamFile);
- }
- if (vgmstream->channels == 2) {
- for (i=0;i<16;i++) {
- vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x70+i*2,streamFile);
- }
- }
- }
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
- /* 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[0].channel_start_offset=start_offset;
- if (channel_count == 2) {
- if (second_channel_start == -1) goto fail;
- vgmstream->ch[1].channel_start_offset=second_channel_start;
- }
- vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset;
- }
+ if (channel_count == 2) {
+ vgmstream->ch[1].channel_start_offset =
+ vgmstream->ch[1].offset = ((get_streamfile_size(streamFile)+start_offset) / channel_count);
}
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ngc_str_cauldron.c b/Frameworks/vgmstream/vgmstream/src/meta/ngc_str_cauldron.c
new file mode 100644
index 000000000..7ef70aeba
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ngc_str_cauldron.c
@@ -0,0 +1,46 @@
+#include "meta.h"
+#include "../coding/coding.h"
+
+/* .str - Cauldron/Conan mini-header + interleaved dsp data [Conan (GC)] */
+VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ int channel_count, loop_flag;
+
+
+ /* checks */
+ if (!check_extensions(streamFile, "str"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0xFAAF0001) /* header id */
+ goto fail;
+
+ channel_count = 2; /* always loop & stereo */
+ loop_flag = 1;
+ start_offset = 0x60;
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = read_32bitBE(0x04,streamFile);
+ vgmstream->num_samples = read_32bitBE(0x08,streamFile);
+ vgmstream->loop_start_sample = 0;
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+
+ vgmstream->meta_type = meta_DSP_STR;
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = read_32bitBE(0x0C,streamFile);
+
+ dsp_read_coefs_be(vgmstream, streamFile, 0x10, 0x20);
+
+
+ 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/ngc_ulw.c b/Frameworks/vgmstream/vgmstream/src/meta/ngc_ulw.c
index 662bdcf57..e873ac1d6 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ngc_ulw.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ngc_ulw.c
@@ -14,29 +14,20 @@ VGMSTREAM * init_vgmstream_ngc_ulw(STREAMFILE *streamFile) {
/* raw data, the info is in the filename (really!) */
{
- char* path;
- char basename[PATH_LIMIT];
- char filename[PATH_LIMIT];
+ char filename[PATH_LIMIT] = {0};
- /* get base name */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- path = strrchr(filename,DIR_SEPARATOR);
- if (path!=NULL)
- path = path+1;
- else
- path = filename;
- strcpy(basename,path);
+ get_streamfile_filename(streamFile, filename,PATH_LIMIT);
/* first letter gives the channels */
- if (basename[0]=='M') /* Mono */
+ if (filename[0]=='M') /* Mono */
channel_count = 1;
- else if (basename[0]=='S' || basename[0]=='D') /* Stereo/Dolby */
+ else if (filename[0]=='S' || filename[0]=='D') /* Stereo/Dolby */
channel_count = 2;
else
goto fail;
/* not very robust but meh (other tracks don't loop) */
- if (strcmp(basename,"MMenu.ulw")==0 || strcmp(basename,"DMenu.ulw")==0) {
+ if (strcmp(filename,"MMenu.ulw")==0 || strcmp(filename,"DMenu.ulw")==0) {
loop_flag = 1;
}
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/nsw_opus.c b/Frameworks/vgmstream/vgmstream/src/meta/nsw_opus.c
deleted file mode 100644
index 7794f77b1..000000000
--- a/Frameworks/vgmstream/vgmstream/src/meta/nsw_opus.c
+++ /dev/null
@@ -1,119 +0,0 @@
-#include "meta.h"
-#include "../util.h"
-#include "../coding/coding.h"
-
-/* .OPUS - from Switch games (Lego City Undercover, Ultra SF II, Disgaea 5) */
-VGMSTREAM * init_vgmstream_nsw_opus(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- off_t start_offset;
- int loop_flag = 0, channel_count;
- int num_samples = 0, loop_start = 0, loop_end = 0;
- off_t offset = 0, data_offset;
- size_t data_size, skip = 0;
-
- /* check extension, case insensitive */
- if ( !check_extensions(streamFile,"opus,lopus,nop")) /* no relation to Ogg Opus */
- goto fail;
-
- /* variations, maybe custom */
- if (read_32bitBE(0x00,streamFile) == 0x01000080) { /* Lego City Undercover */
- offset = 0x00;
- }
- else if ((read_32bitBE(0x04,streamFile) == 0x00000000 && read_32bitBE(0x0c,streamFile) == 0x00000000) ||
- (read_32bitBE(0x04,streamFile) == 0xFFFFFFFF && read_32bitBE(0x0c,streamFile) == 0xFFFFFFFF)) { /* Disgaea 5 */
- offset = 0x10;
-
- loop_start = read_32bitLE(0x00,streamFile);
- loop_end = read_32bitLE(0x08,streamFile);
- }
- else if (read_32bitLE(0x04,streamFile) == 0x02) { /* Ultra Street Fighter II */
- offset = read_32bitLE(0x1c,streamFile);
-
- num_samples = read_32bitLE(0x00,streamFile);
- loop_start = read_32bitLE(0x08,streamFile);
- loop_end = read_32bitLE(0x0c,streamFile);
- }
- else if (read_32bitBE(0x00, streamFile) == 0x73616466 && read_32bitBE(0x08, streamFile) == 0x6f707573) { /* Xenoblade Chronicles 2 */
- offset = read_32bitLE(0x1c, streamFile);
-
- num_samples = read_32bitLE(0x28, streamFile);
- loop_flag = read_8bit(0x19, streamFile);
- if (loop_flag) {
- loop_start = read_32bitLE(0x2c, streamFile);
- loop_end = read_32bitLE(0x30, streamFile);
- }
- }
- else {
- offset = 0x00;
- }
-
- if ((uint32_t)read_32bitLE(offset + 0x00,streamFile) != 0x80000001)
- goto fail;
-
- channel_count = read_8bit(offset + 0x09, streamFile);
- /* 0x0a: packet size if CBR, 0 if VBR */
- data_offset = offset + read_32bitLE(offset + 0x10, streamFile);
- skip = read_32bitLE(offset + 0x1c, streamFile);
-
- if ((uint32_t)read_32bitLE(data_offset, streamFile) != 0x80000004)
- goto fail;
-
- data_size = read_32bitLE(data_offset + 0x04, streamFile);
-
- start_offset = data_offset + 0x08;
- loop_flag = (loop_end > 0); /* -1 when not set */
-
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(channel_count,loop_flag);
- if (!vgmstream) goto fail;
-
- vgmstream->sample_rate = read_32bitLE(offset + 0x0c,streamFile);
- vgmstream->meta_type = meta_NSW_OPUS;
-
- vgmstream->num_samples = num_samples;
- vgmstream->loop_start_sample = loop_start;
- vgmstream->loop_end_sample = loop_end;
-
-#ifdef VGM_USE_FFMPEG
- {
- uint8_t buf[0x100];
- size_t bytes;
- ffmpeg_custom_config cfg;
- ffmpeg_codec_data *ffmpeg_data;
-
- bytes = ffmpeg_make_opus_header(buf,0x100, vgmstream->channels, skip, vgmstream->sample_rate);
- if (bytes <= 0) goto fail;
-
- memset(&cfg, 0, sizeof(ffmpeg_custom_config));
- cfg.type = FFMPEG_SWITCH_OPUS;
-
- ffmpeg_data = init_ffmpeg_config(streamFile, buf,bytes, start_offset,data_size, &cfg);
- if (!ffmpeg_data) goto fail;
-
- vgmstream->codec_data = ffmpeg_data;
- vgmstream->coding_type = coding_FFmpeg;
- vgmstream->layout_type = layout_none;
-
- if (ffmpeg_data->skipSamples <= 0) {
- ffmpeg_set_skip_samples(ffmpeg_data, skip);
- }
-
- if (vgmstream->num_samples == 0) {
- vgmstream->num_samples = switch_opus_get_samples(start_offset, data_size,
- vgmstream->sample_rate, streamFile) - skip;
- }
- }
-#else
- goto fail;
-#endif
-
- /* open the file for reading */
- if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
- goto fail;
- return vgmstream;
-
-fail:
- close_vgmstream(vgmstream);
- return NULL;
-}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/nwa.c b/Frameworks/vgmstream/vgmstream/src/meta/nwa.c
index d4743a5c1..26003fbbd 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/nwa.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/nwa.c
@@ -4,306 +4,88 @@
#include
#include
-#ifdef WIN32
-#define DIRSEP '\\'
-#else
-#define DIRSEP '/'
-#endif
-/* NWA - Visual Art's streams */
+static int get_loops_nwainfo_ini(STREAMFILE *streamFile, int *out_loop_flag, int32_t *out_loop_start);
+static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int32_t *out_loop_start, int32_t *out_loop_end);
+static nwa_codec_data *open_nwa_vgmstream(STREAMFILE *streamFile);
+static void free_nwa_vgmstream(nwa_codec_data *data);
+/* NWA - Visual Art's streams [Air (PC), Clannad (PC)] */
VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- int i;
- int channel_count;
- int loop_flag = 0;
- int32_t loop_start_sample = 0;
- int32_t loop_end_sample = 0;
- int nwainfo_ini_found = 0;
- int gameexe_ini_found = 0;
- int just_pcm = 0;
- int comp_level = -2;
- nwa_codec_data *data = NULL;
+ off_t start_offset;
+ int channel_count, loop_flag = 0;
+ int32_t loop_start_sample = 0, loop_end_sample = 0;
+ int nwainfo_ini_found = 0, gameexe_ini_found = 0;
+ int compression_level;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("nwa",filename_extension(filename))) goto fail;
+
+ /* checks */
+ if (!check_extensions(streamFile, "nwa"))
+ goto fail;
channel_count = read_16bitLE(0x00,streamFile);
if (channel_count != 1 && channel_count != 2) goto fail;
/* check if we're using raw pcm */
- if (
- read_32bitLE(0x08,streamFile)==-1 || /* compression level */
- read_32bitLE(0x10,streamFile)==0 || /* block count */
- read_32bitLE(0x18,streamFile)==0 || /* compressed data size */
- read_32bitLE(0x20,streamFile)==0 || /* block size */
- read_32bitLE(0x24,streamFile)==0 /* restsize */
- )
- {
- just_pcm = 1;
- }
- else
- {
- comp_level = read_32bitLE(0x08,streamFile);
-
- data = malloc(sizeof(nwa_codec_data));
- if (!data) goto fail;
-
- data->nwa = open_nwa(streamFile,filename);
- if (!data->nwa) goto fail;
+ if ( read_32bitLE(0x08,streamFile)==-1 || /* compression level */
+ read_32bitLE(0x10,streamFile)==0 || /* block count */
+ read_32bitLE(0x18,streamFile)==0 || /* compressed data size */
+ read_32bitLE(0x20,streamFile)==0 || /* block size */
+ read_32bitLE(0x24,streamFile)==0 ) { /* restsize */
+ compression_level = -1;
+ } else {
+ compression_level = read_32bitLE(0x08,streamFile);
}
- /* try to locate NWAINFO.INI in the same directory */
- {
- char ininame[PATH_LIMIT];
- char * ini_lastslash;
- char namebase_array[PATH_LIMIT];
- char *namebase;
- STREAMFILE *inistreamfile;
+ /* loop points come from external files */
+ nwainfo_ini_found = get_loops_nwainfo_ini(streamFile, &loop_flag, &loop_start_sample);
+ gameexe_ini_found = !nwainfo_ini_found && get_loops_gameexe_ini(streamFile, &loop_flag, &loop_start_sample, &loop_end_sample);
- /* here we assume that the "special encoding" does not affect
- * the directory separator */
- strncpy(ininame,filename,sizeof(ininame));
- ininame[sizeof(ininame)-1]='\0'; /* a pox on the stdlib! */
-
- streamFile->get_realname(streamFile,namebase_array,sizeof(namebase_array));
-
- ini_lastslash = strrchr(ininame,DIRSEP);
- if (!ini_lastslash) {
- strncpy(ininame,"NWAINFO.INI",sizeof(ininame));
- namebase = namebase_array;
- } else {
- strncpy(ini_lastslash+1,"NWAINFO.INI",
- sizeof(ininame)-(ini_lastslash+1-ininame));
- namebase = strrchr(namebase_array,DIRSEP)+1;
- }
- ininame[sizeof(ininame)-1]='\0'; /* curse you, strncpy! */
-
- inistreamfile = streamFile->open(streamFile,ininame,4096);
-
- if (inistreamfile) {
- /* ini found, try to find our name */
- const char * ext;
- int length;
- int found;
- off_t offset;
- off_t file_size;
- off_t found_off = -1;
-
- nwainfo_ini_found = 1;
-
- ext = filename_extension(namebase);
- length = ext-1-namebase;
- file_size = get_streamfile_size(inistreamfile);
-
- for (found = 0, offset = 0; !found && offset 0) loop_flag = 1;
- }
- } /* if found file name in INI */
-
- close_streamfile(inistreamfile);
- } /* if opened INI ok */
- } /* INI block */
-
- /* try to locate Gameexe.ini in the same directory */
- {
- char ininame[PATH_LIMIT];
- char * ini_lastslash;
- char namebase_array[PATH_LIMIT];
- char * namebase;
- STREAMFILE *inistreamfile;
-
- strncpy(ininame,filename,sizeof(ininame));
- ininame[sizeof(ininame)-1]='\0'; /* a pox on the stdlib! */
-
- streamFile->get_realname(streamFile,namebase_array,sizeof(namebase_array));
-
- ini_lastslash = strrchr(ininame,DIRSEP);
- if (!ini_lastslash) {
- strncpy(ininame,"Gameexe.ini",sizeof(ininame));
- namebase = namebase_array;
- } else {
- strncpy(ini_lastslash+1,"Gameexe.ini",
- sizeof(ininame)-(ini_lastslash+1-ininame));
- namebase = strrchr(namebase_array,DIRSEP)+1;
- }
- ininame[sizeof(ininame)-1]='\0'; /* curse you, strncpy! */
-
- inistreamfile = streamFile->open(streamFile,ininame,4096);
-
- if (inistreamfile) {
- /* ini found, try to find our name */
- const char * ext;
- int length;
- int found;
- off_t offset;
- off_t file_size;
- off_t found_off = -1;
-
- gameexe_ini_found = 1;
-
- ext = filename_extension(namebase);
- length = ext-1-namebase;
- file_size = get_streamfile_size(inistreamfile);
-
- /* format of line is:
- * #DSTRACK = 00000000 - eeeeeeee - ssssssss = "name" = "name2?"
- * ^22 ^33 ^45 ^57
- */
-
- for (found = 0, offset = 0; !found && offsetchannels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
+ vgmstream->num_samples = read_32bitLE(0x1c,streamFile) / channel_count;
- vgmstream->num_samples = read_32bitLE(0x1c,streamFile)/channel_count;
-
- if (just_pcm) {
- switch (read_16bitLE(0x02,streamFile)) {
- case 8:
- vgmstream->coding_type = coding_PCM8;
- vgmstream->interleave_block_size = 1;
- break;
- case 16:
- vgmstream->coding_type = coding_PCM16LE;
- vgmstream->interleave_block_size = 2;
- break;
- default:
- goto fail;
- }
- if (channel_count > 1) {
+ switch(compression_level) {
+ case -1:
+ switch (read_16bitLE(0x02,streamFile)) {
+ case 8:
+ vgmstream->coding_type = coding_PCM8;
+ vgmstream->interleave_block_size = 0x01;
+ break;
+ case 16:
+ vgmstream->coding_type = coding_PCM16LE;
+ vgmstream->interleave_block_size = 0x02;
+ break;
+ default:
+ goto fail;
+ }
vgmstream->layout_type = layout_interleave;
- } else {
+ break;
+
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ vgmstream->coding_type = coding_NWA;
vgmstream->layout_type = layout_none;
- }
- }
- else
- {
- switch (comp_level)
- {
- case 0:
- vgmstream->coding_type = coding_NWA0;
- break;
- case 1:
- vgmstream->coding_type = coding_NWA1;
- break;
- case 2:
- vgmstream->coding_type = coding_NWA2;
- break;
- case 3:
- vgmstream->coding_type = coding_NWA3;
- break;
- case 4:
- vgmstream->coding_type = coding_NWA4;
- break;
- case 5:
- vgmstream->coding_type = coding_NWA5;
- break;
- default:
- goto fail;
- break;
- }
- vgmstream->layout_type = layout_none;
+ vgmstream->codec_data = open_nwa_vgmstream(streamFile);
+ if (!vgmstream->codec_data) goto fail;
+ break;
+
+ default:
+ goto fail;
+ break;
}
+
if (nwainfo_ini_found) {
vgmstream->meta_type = meta_NWA_NWAINFOINI;
if (loop_flag) {
@@ -321,38 +103,205 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) {
}
- if (just_pcm) {
- /* open the file for reading by each channel */
- STREAMFILE *chstreamfile;
-
- /* have both channels use the same buffer, as interleave is so small */
- chstreamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
-
- if (!chstreamfile) goto fail;
-
- for (i=0;ich[i].streamfile = chstreamfile;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=0x2c+(off_t)(i*vgmstream->interleave_block_size);
- }
- }
- else
- {
- vgmstream->codec_data = data;
- }
-
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
- if (data) {
- if (data->nwa)
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+
+/* try to locate NWAINFO.INI in the same directory */
+static int get_loops_nwainfo_ini(STREAMFILE *streamFile, int *out_loop_flag, int32_t *out_loop_start) {
+ STREAMFILE *streamLoops;
+ char namebase[PATH_LIMIT];
+ const char * ext;
+ int length;
+ int found;
+ off_t offset;
+ size_t file_size;
+ off_t found_off = -1;
+ int loop_flag = 0;
+ int32_t loop_start_sample = 0;
+
+
+ streamLoops = open_streamfile_by_filename(streamFile, "NWAINFO.INI");
+ if (!streamLoops) goto fail;
+
+ get_streamfile_filename(streamFile,namebase,PATH_LIMIT);
+
+ /* ini found, try to find our name */
+ ext = filename_extension(namebase);
+ length = ext - 1 - namebase;
+ file_size = get_streamfile_size(streamLoops);
+
+ for (found = 0, offset = 0; !found && offset < file_size; offset++) {
+ off_t suboffset;
+ /* Go for an n*m search 'cause it's easier than building an
+ * FSA for the search string. Just wanted to make the point that
+ * I'm not ignorant, just lazy. */
+ for (suboffset = offset;
+ suboffset < file_size &&
+ suboffset-offset < length &&
+ read_8bit(suboffset,streamLoops) == namebase[suboffset-offset];
+ suboffset++) {
+ /* skip */
+ }
+
+ if (suboffset-offset==length && read_8bit(suboffset,streamLoops)==0x09) { /* tab */
+ found = 1;
+ found_off = suboffset+1;
+ }
+ }
+
+ /* if found file name in INI */
+ if (found) {
+ char loopstring[9] = {0};
+
+ if (read_streamfile((uint8_t*)loopstring,found_off,8,streamLoops) == 8) {
+ loop_start_sample = atol(loopstring);
+ if (loop_start_sample > 0)
+ loop_flag = 1;
+ }
+ }
+
+
+ *out_loop_flag = loop_flag;
+ *out_loop_start = loop_start_sample;
+
+ close_streamfile(streamLoops);
+ return 1;
+
+fail:
+ close_streamfile(streamLoops);
+ return 0;
+}
+
+/* try to locate Gameexe.ini in the same directory */
+static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int32_t *out_loop_start, int32_t *out_loop_end) {
+ STREAMFILE *streamLoops;
+ char namebase[PATH_LIMIT];
+ const char * ext;
+ int length;
+ int found;
+ off_t offset;
+ off_t file_size;
+ off_t found_off = -1;
+ int loop_flag = 0;
+ int32_t loop_start_sample = 0, loop_end_sample = 0;
+
+
+ streamLoops = open_streamfile_by_filename(streamFile, "Gameexe.ini");
+ if (!streamLoops) goto fail;
+
+ get_streamfile_filename(streamFile,namebase,PATH_LIMIT);
+
+ /* ini found, try to find our name */
+ ext = filename_extension(namebase);
+ length = ext-1-namebase;
+ file_size = get_streamfile_size(streamLoops);
+
+ /* format of line is:
+ * #DSTRACK = 00000000 - eeeeeeee - ssssssss = "name" = "name2?"
+ * ^22 ^33 ^45 ^57
+ */
+
+ for (found = 0, offset = 0; !found && offsetget_name(streamFile,filename,sizeof(filename));
+
+ data = malloc(sizeof(nwa_codec_data));
+ if (!data) goto fail;
+
+ data->nwa = open_nwa(streamFile,filename);
+ if (!data->nwa) goto fail;
+
+ return data;
+
+fail:
+ free_nwa_vgmstream(data);
+ return NULL;
+}
+
+static void free_nwa_vgmstream(nwa_codec_data *data) {
+ if (data) {
+ if (data->nwa) {
close_nwa(data->nwa);
}
free(data);
}
- return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/nxap.c b/Frameworks/vgmstream/vgmstream/src/meta/nxap.c
new file mode 100644
index 000000000..813ec164e
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/nxap.c
@@ -0,0 +1,49 @@
+#include "meta.h"
+#include "../coding/coding.h"
+
+/* NXAP - Nex Entertainment header [Time Crisis 4 (PS3), Time Crisis Razing Storm (PS3)] */
+VGMSTREAM * init_vgmstream_nxap(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ int loop_flag, channel_count;
+
+
+ /* checks */
+ if (!check_extensions(streamFile, "adp"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x4E584150) /* "NXAP" */
+ goto fail;
+ if (read_32bitLE(0x14,streamFile) != 0x40 || /* expected frame size? */
+ read_32bitLE(0x18,streamFile) != 0x40) /* expected interleave? */
+ goto fail;
+
+ start_offset = read_32bitLE(0x04,streamFile);
+ channel_count = read_32bitLE(0x0c,streamFile);
+ loop_flag = 0; //(read_32bitLE(0x24,streamFile) > 0); //todo
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count, loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = read_32bitLE(0x10, streamFile);
+ vgmstream->num_samples = read_32bitLE(0x1c,streamFile) * (0x40-0x04)*2 / channel_count; /* number of frames */
+
+ /* unknown loop format, also 0x28/2c values seem related */
+ //vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile) * (0x40-0x04)*2 / channel_count;
+ //vgmstream->loop_end_sample = read_32bitLE(0x24,streamFile) * (0x40-0x04)*2 / channel_count;
+ //vgmstream->loop_end_sample = vgmstream->loop_start_sample + vgmstream->loop_end_sample;
+
+ vgmstream->meta_type = meta_NXAP;
+ vgmstream->coding_type = coding_YAMAHA_NXAP;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x40;
+
+ 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/ogg_vorbis.c b/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c
index 79704ec14..67d21149a 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c
@@ -111,8 +111,7 @@ static void psychic_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb
int i;
/* add 0x23 ('#') */
- {
- for (i = 0; i < bytes_read; i++)
+ for (i = 0; i < bytes_read; i++) {
((uint8_t*)ptr)[i] += 0x23;
}
}
@@ -124,19 +123,16 @@ static void sngw_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, v
char *header_id = "OggS";
uint8_t key[4];
- put_32bitBE(key, ov_streamfile->sngw_xor);
+ put_32bitBE(key, ov_streamfile->xor_value);
- /* bytes are xor'd with key and nibble-swapped */
- {
- for (i = 0; i < bytes_read; i++) {
- if (ov_streamfile->offset+i < 0x04) {
- /* replace key in the first 4 bytes with "OggS" */
- ((uint8_t*)ptr)[i] = (uint8_t)header_id[(ov_streamfile->offset + i) % 4];
- }
- else {
- uint8_t val = ((uint8_t*)ptr)[i] ^ key[(ov_streamfile->offset + i) % 4];
- ((uint8_t*)ptr)[i] = ((val << 4) & 0xf0) | ((val >> 4) & 0x0f);
- }
+ /* bytes are xor'd with key and nibble-swapped, first "OggS" is changed */
+ for (i = 0; i < bytes_read; i++) {
+ if (ov_streamfile->offset+i < 0x04) {
+ ((uint8_t*)ptr)[i] = (uint8_t)header_id[(ov_streamfile->offset + i) % 4];
+ }
+ else {
+ uint8_t val = ((uint8_t*)ptr)[i] ^ key[(ov_streamfile->offset + i) % 4];
+ ((uint8_t*)ptr)[i] = ((val << 4) & 0xf0) | ((val >> 4) & 0x0f);
}
}
}
@@ -150,9 +146,8 @@ static void isd_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, vo
int i;
/* bytes are xor'd with key */
- {
- for (i = 0; i < bytes_read; i++)
- ((uint8_t*)ptr)[i] ^= key[(ov_streamfile->offset + i) % 16];
+ for (i = 0; i < bytes_read; i++) {
+ ((uint8_t*)ptr)[i] ^= key[(ov_streamfile->offset + i) % 16];
}
}
@@ -162,25 +157,67 @@ static void l2sd_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, v
int i;
char *header_id = "OggS";
- /* First "OggS" is changed */
- {
- for (i = 0; i < bytes_read; i++) {
- if (ov_streamfile->offset+i < 0x04) {
- /* replace key in the first 4 bytes with "OggS" */
- ((uint8_t*)ptr)[i] = (uint8_t)header_id[(ov_streamfile->offset + i) % 4];
- }
- else {
- break;
- }
+ /* first "OggS" is changed */
+ for (i = 0; i < bytes_read; i++) {
+ if (ov_streamfile->offset+i < 0x04) {
+ /* replace key in the first 4 bytes with "OggS" */
+ ((uint8_t*)ptr)[i] = (uint8_t)header_id[(ov_streamfile->offset + i) % 4];
+ }
+ else {
+ break;
}
}
}
+static void rpgmvo_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
+ static const uint8_t header[16] = { /* OggS, packet type, granule, stream id(empty) */
+ 0x4F,0x67,0x67,0x53,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ };
+ size_t bytes_read = size*nmemb;
+ ogg_vorbis_streamfile * const ov_streamfile = datasource;
+ int i;
+
+ /* first 0x10 are xor'd with a key, but the header can be easily reconstructed
+ * (key is also in (game)/www/data/System.json "encryptionKey") */
+ for (i = 0; i < bytes_read; i++) {
+ if (ov_streamfile->offset+i < 0x10) {
+ ((uint8_t*)ptr)[i] = header[(ov_streamfile->offset + i) % 16];
+
+ /* last two bytes are the stream id, get from next OggS */
+ if (ov_streamfile->offset+i == 0x0e)
+ ((uint8_t*)ptr)[i] = read_8bit(0x58, ov_streamfile->streamfile);
+ if (ov_streamfile->offset+i == 0x0f)
+ ((uint8_t*)ptr)[i] = read_8bit(0x59, ov_streamfile->streamfile);
+ }
+ }
+}
+
+static void eno_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
+ size_t bytes_read = size*nmemb;
+ ogg_vorbis_streamfile * const ov_streamfile = datasource;
+ int i;
+
+ /* bytes are xor'd with key */
+ for (i = 0; i < bytes_read; i++) {
+ ((uint8_t*)ptr)[i] ^= (uint8_t)ov_streamfile->xor_value;
+ }
+}
+
+static void ys8_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
+ size_t bytes_read = size*nmemb;
+ ogg_vorbis_streamfile * const ov_streamfile = datasource;
+ int i;
+
+ /* bytes are xor'd with key and nibble-swapped */
+ for (i = 0; i < bytes_read; i++) {
+ uint8_t val = ((uint8_t*)ptr)[i] ^ ov_streamfile->xor_value;
+ ((uint8_t*)ptr)[i] = ((val << 4) & 0xf0) | ((val >> 4) & 0x0f);
+ }
+}
/* Ogg Vorbis, by way of libvorbisfile; may contain loop comments */
VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
- char filename[PATH_LIMIT];
- vgm_vorbis_info_t inf = {0};
+ ogg_vorbis_meta_info_t ovmi = {0};
off_t start_offset = 0;
int is_ogg = 0;
@@ -190,45 +227,57 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
int is_sngw = 0;
int is_isd = 0;
int is_l2sd = 0;
+ int is_rpgmvo = 0;
+ int is_eno = 0;
+ int is_ys8 = 0;
/* check extension */
- if (check_extensions(streamFile,"ogg,logg")) { /* .ogg: standard/psychic, .logg: renamed for plugins */
+ /* .ogg: standard/psychic, .logg: renamed for plugins,
+ * .adx: KID [Remember11 (PC)],
+ * .rof: The Rhythm of Fighters (Mobile)
+ * .acm: Planescape Torment Enhanced Edition (PC) */
+ if (check_extensions(streamFile,"ogg,logg,adx,rof,acm")) {
is_ogg = 1;
} else if (check_extensions(streamFile,"um3")) {
is_um3 = 1;
} else if (check_extensions(streamFile,"kvs,kovs")) { /* .kvs: Atelier Sophie (PC), kovs: header id only? */
is_kovs = 1;
- } else if (check_extensions(streamFile,"sngw")) { /* .sngw: Devil May Cry 4 SE (PC), Biohazard 6 (PC) */
+ } else if (check_extensions(streamFile,"sngw")) { /* .sngw: Capcom [Devil May Cry 4 SE (PC), Biohazard 6 (PC)] */
is_sngw = 1;
} else if (check_extensions(streamFile,"isd")) { /* .isd: Azure Striker Gunvolt (PC) */
is_isd = 1;
+ } else if (check_extensions(streamFile,"rpgmvo")) { /* .rpgmvo: RPG Maker MV games (PC) */
+ is_rpgmvo = 1;
+ } else if (check_extensions(streamFile,"eno")) { /* .eno: Metronomicon (PC) */
+ is_eno = 1;
} else {
goto fail;
}
- streamFile->get_name(streamFile,filename,sizeof(filename));
/* check standard Ogg Vorbis */
if (is_ogg) {
-
- /* check Psychic Software obfuscation (Darkwind: War on Wheels PC) */
- if (read_32bitBE(0x00,streamFile) == 0x2c444430) {
+ if (read_32bitBE(0x00,streamFile) == 0x2c444430) { /* Psychic Software obfuscation [Darkwind: War on Wheels (PC)] */
is_psychic = 1;
- inf.decryption_callback = psychic_ogg_decryption_callback;
+ ovmi.decryption_callback = psychic_ogg_decryption_callback;
}
else if (read_32bitBE(0x00,streamFile) == 0x4C325344) { /* "L2SD" [Lineage II Chronicle 4 (PC)] */
is_l2sd = 1;
- inf.decryption_callback = l2sd_ogg_decryption_callback;
+ ovmi.decryption_callback = l2sd_ogg_decryption_callback;
+ }
+ else if (read_32bitBE(0x00,streamFile) == 0x048686C5) { /* XOR'ed + bitswapped "OggS" [Ys VIII (PC)] */
+ is_ys8 = 1;
+ ovmi.decryption_callback = ys8_ogg_decryption_callback;
}
else if (read_32bitBE(0x00,streamFile) != 0x4f676753) { /* "OggS" */
- goto fail; /* not known (ex. Wwise) */
+ goto fail; /* unknown/not ogg (ex. Wwise) */
}
}
/* check "Ultramarine3" (???), may be encrypted */
if (is_um3) {
if (read_32bitBE(0x00,streamFile) != 0x4f676753) { /* "OggS" */
- inf.decryption_callback = um3_ogg_decryption_callback;
+ ovmi.decryption_callback = um3_ogg_decryption_callback;
}
}
@@ -237,9 +286,9 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
if (read_32bitBE(0x00,streamFile) != 0x4b4f5653) { /* "KOVS" */
goto fail;
}
- inf.loop_start = read_32bitLE(0x08,streamFile);
- inf.loop_flag = (inf.loop_start != 0);
- inf.decryption_callback = kovs_ogg_decryption_callback;
+ ovmi.loop_start = read_32bitLE(0x08,streamFile);
+ ovmi.loop_flag = (ovmi.loop_start != 0);
+ ovmi.decryption_callback = kovs_ogg_decryption_callback;
start_offset = 0x20;
}
@@ -247,14 +296,14 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
/* check SNGW (Capcom's MT Framework PC games), may be encrypted */
if (is_sngw) {
if (read_32bitBE(0x00,streamFile) != 0x4f676753) { /* "OggS" */
- inf.sngw_xor = read_32bitBE(0x00,streamFile);
- inf.decryption_callback = sngw_ogg_decryption_callback;
+ ovmi.xor_value = read_32bitBE(0x00,streamFile);
+ ovmi.decryption_callback = sngw_ogg_decryption_callback;
}
}
/* check ISD (Gunvolt PC) */
if (is_isd) {
- inf.decryption_callback = isd_ogg_decryption_callback;
+ ovmi.decryption_callback = isd_ogg_decryption_callback;
//todo looping unknown, not in Ogg comments
// game has sound/GV_steam.* files with info about sound/stream/*.isd
@@ -265,44 +314,73 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
// 0x0c(2): PCM block size, 0x0e(2): PCM bps, 0x10: null, 0x18: samples (in PCM bytes)
}
+ /* check RPGMKVO (RPG Maker MV), header + minor encryption */
+ if (is_rpgmvo) {
+ if (read_32bitBE(0x00,streamFile) != 0x5250474D && /* "RPGM" */
+ read_32bitBE(0x00,streamFile) != 0x56000000) { /* "V\0\0\0" */
+ goto fail;
+ }
+ ovmi.decryption_callback = rpgmvo_ogg_decryption_callback;
+
+ start_offset = 0x10;
+ }
+
+ /* check ENO [Metronomicon (PC)] */
+ if (is_eno) {
+ /* first byte probably derives into xor key, but this works too */
+ ovmi.xor_value = read_8bit(0x05,streamFile); /* always zero = easy key */
+ ovmi.decryption_callback = eno_ogg_decryption_callback;
+ start_offset = 0x01;
+ }
+
+ /* check Ys VIII (PC) */
+ if (is_ys8) {
+ ovmi.xor_value = 0xF0;
+ ovmi.decryption_callback = ys8_ogg_decryption_callback;
+ }
if (is_um3) {
- inf.meta_type = meta_OGG_UM3;
+ ovmi.meta_type = meta_OGG_UM3;
} else if (is_kovs) {
- inf.meta_type = meta_OGG_KOVS;
+ ovmi.meta_type = meta_OGG_KOVS;
} else if (is_psychic) {
- inf.meta_type = meta_OGG_PSYCHIC;
+ ovmi.meta_type = meta_OGG_PSYCHIC;
} else if (is_sngw) {
- inf.meta_type = meta_OGG_SNGW;
+ ovmi.meta_type = meta_OGG_SNGW;
} else if (is_isd) {
- inf.meta_type = meta_OGG_ISD;
+ ovmi.meta_type = meta_OGG_ISD;
} else if (is_l2sd) {
- inf.meta_type = meta_OGG_L2SD;
+ ovmi.meta_type = meta_OGG_L2SD;
+ } else if (is_rpgmvo) {
+ ovmi.meta_type = meta_OGG_RPGMV;
+ } else if (is_eno) {
+ ovmi.meta_type = meta_OGG_ENO;
+ } else if (is_ys8) {
+ ovmi.meta_type = meta_OGG_YS8;
} else {
- inf.meta_type = meta_OGG_VORBIS;
+ ovmi.meta_type = meta_OGG_VORBIS;
}
- inf.layout_type = layout_ogg_vorbis;
- return init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf);
+ return init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
fail:
return NULL;
}
-VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const char * filename, ov_callbacks *callbacks_p, off_t start, const vgm_vorbis_info_t *vgm_inf) {
+VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callbacks *callbacks_p, off_t start, const ogg_vorbis_meta_info_t *ovmi) {
VGMSTREAM * vgmstream = NULL;
ogg_vorbis_codec_data * data = NULL;
OggVorbis_File *ovf = NULL;
vorbis_info *vi;
- int loop_flag = vgm_inf->loop_flag;
- int32_t loop_start = vgm_inf->loop_start;
- int loop_length_found = vgm_inf->loop_length_found;
- int32_t loop_length = vgm_inf->loop_length;
- int loop_end_found = vgm_inf->loop_end_found;
- int32_t loop_end = vgm_inf->loop_end;
- size_t stream_size = vgm_inf->stream_size ?
- vgm_inf->stream_size :
+ int loop_flag = ovmi->loop_flag;
+ int32_t loop_start = ovmi->loop_start;
+ int loop_length_found = ovmi->loop_length_found;
+ int32_t loop_length = ovmi->loop_length;
+ int loop_end_found = ovmi->loop_end_found;
+ int32_t loop_end = ovmi->loop_end;
+ size_t stream_size = ovmi->stream_size ?
+ ovmi->stream_size :
get_streamfile_size(streamFile) - start;
ov_callbacks default_callbacks;
@@ -327,10 +405,10 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch
temp_streamfile.offset = 0;
temp_streamfile.size = stream_size;
- temp_streamfile.decryption_callback = vgm_inf->decryption_callback;
- temp_streamfile.scd_xor = vgm_inf->scd_xor;
- temp_streamfile.scd_xor_length = vgm_inf->scd_xor_length;
- temp_streamfile.sngw_xor = vgm_inf->sngw_xor;
+ temp_streamfile.decryption_callback = ovmi->decryption_callback;
+ temp_streamfile.scd_xor = ovmi->scd_xor;
+ temp_streamfile.scd_xor_length = ovmi->scd_xor_length;
+ temp_streamfile.xor_value = ovmi->xor_value;
/* open the ogg vorbis file for testing */
memset(&temp_ovf, 0, sizeof(temp_ovf));
@@ -344,9 +422,12 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch
/* proceed to init codec_data and reopen a STREAMFILE for this stream */
{
+ char filename[PATH_LIMIT];
+
data = calloc(1,sizeof(ogg_vorbis_codec_data));
if (!data) goto fail;
+ streamFile->get_name(streamFile,filename,sizeof(filename));
data->ov_streamfile.streamfile = streamFile->open(streamFile,filename, STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!data->ov_streamfile.streamfile) goto fail;
@@ -354,10 +435,10 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch
data->ov_streamfile.offset = 0;
data->ov_streamfile.size = stream_size;
- data->ov_streamfile.decryption_callback = vgm_inf->decryption_callback;
- data->ov_streamfile.scd_xor = vgm_inf->scd_xor;
- data->ov_streamfile.scd_xor_length = vgm_inf->scd_xor_length;
- data->ov_streamfile.sngw_xor = vgm_inf->sngw_xor;
+ data->ov_streamfile.decryption_callback = ovmi->decryption_callback;
+ data->ov_streamfile.scd_xor = ovmi->scd_xor;
+ data->ov_streamfile.scd_xor_length = ovmi->scd_xor_length;
+ data->ov_streamfile.xor_value = ovmi->xor_value;
/* open the ogg vorbis file for real */
if (ov_open_callbacks(&data->ov_streamfile, &data->ogg_vorbis_file, NULL, 0, *callbacks_p))
@@ -382,7 +463,8 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch
strstr(user_comment,"LOOPSTART=")==user_comment ||
strstr(user_comment,"um3.stream.looppoint.start=")==user_comment ||
strstr(user_comment,"LOOP_BEGIN=")==user_comment || /* Hatsune Miku: Project Diva F (PS3) */
- strstr(user_comment,"LoopStart=")==user_comment) { /* Devil May Cry 4 (PC) */
+ strstr(user_comment,"LoopStart=")==user_comment || /* Devil May Cry 4 (PC) */
+ strstr(user_comment,"XIPH_CUE_LOOPSTART=")==user_comment) { /* Super Mario Run (Android) */
loop_start = atol(strrchr(user_comment,'=')+1);
loop_flag = (loop_start >= 0);
}
@@ -390,7 +472,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch
loop_length = atol(strrchr(user_comment,'=')+1);
loop_length_found = 1;
}
- else if (strstr(user_comment,"title=-lps")==user_comment) { /* Memories Off #5 (PC) */
+ else if (strstr(user_comment,"title=-lps")==user_comment) { /* KID [Memories Off #5 (PC), Remember11 (PC)] */
loop_start = atol(user_comment+10);
loop_flag = (loop_start >= 0);
}
@@ -426,6 +508,14 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch
loop_flag = 1;
loop_end_found = 1;
}
+ else if (strstr(user_comment, "XIPH_CUE_LOOPEND=") == user_comment) { /* XIPH_CUE_LOOPSTART pair */
+ if (loop_flag) {
+ loop_length = atol(strrchr(user_comment, '=') + 1) - loop_start;
+ loop_length_found = 1;
+ }
+ }
+
+ //;VGM_LOG("OGG: user_comment=%s\n", user_comment);
}
}
@@ -437,7 +527,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch
vgmstream->codec_data = data; /* store our fun extra datas */
vgmstream->channels = vi->channels;
vgmstream->sample_rate = vi->rate;
- vgmstream->num_streams = vgm_inf->total_subsongs;
+ vgmstream->num_streams = ovmi->total_subsongs;
vgmstream->stream_size = stream_size;
vgmstream->num_samples = ov_pcm_total(ovf,-1); /* let libvorbisfile find total samples */
@@ -455,9 +545,9 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch
vgmstream->loop_end_sample = vgmstream->num_samples;
}
- vgmstream->coding_type = coding_ogg_vorbis;
- vgmstream->layout_type = vgm_inf->layout_type;
- vgmstream->meta_type = vgm_inf->meta_type;
+ vgmstream->coding_type = coding_OGG_VORBIS;
+ vgmstream->layout_type = layout_none;
+ vgmstream->meta_type = ovmi->meta_type;
return vgmstream;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/opus.c b/Frameworks/vgmstream/vgmstream/src/meta/opus.c
new file mode 100644
index 000000000..2a4f152b0
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/opus.c
@@ -0,0 +1,235 @@
+#include "meta.h"
+#include "../util.h"
+#include "../coding/coding.h"
+#include "../layout/layout.h"
+#include "opus_interleave_streamfile.h"
+
+/* Nintendo OPUS - from Switch games, including header variations (not the same as Ogg Opus) */
+
+static VGMSTREAM * init_vgmstream_opus(STREAMFILE *streamFile, meta_t meta_type, off_t offset, int32_t num_samples, int32_t loop_start, int32_t loop_end) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ int loop_flag = 0, channel_count;
+ off_t data_offset;
+ size_t data_size, skip = 0;
+
+
+ if ((uint32_t)read_32bitLE(offset + 0x00,streamFile) != 0x80000001)
+ goto fail;
+
+ channel_count = read_8bit(offset + 0x09, streamFile);
+ /* 0x0a: packet size if CBR, 0 if VBR */
+ data_offset = offset + read_32bitLE(offset + 0x10, streamFile);
+ skip = read_32bitLE(offset + 0x1c, streamFile);
+
+ if ((uint32_t)read_32bitLE(data_offset, streamFile) != 0x80000004)
+ goto fail;
+
+ data_size = read_32bitLE(data_offset + 0x04, streamFile);
+
+ start_offset = data_offset + 0x08;
+ loop_flag = (loop_end > 0); /* -1 when not set */
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = read_32bitLE(offset + 0x0c,streamFile);
+ vgmstream->meta_type = meta_OPUS;
+
+ vgmstream->num_samples = num_samples;
+ vgmstream->loop_start_sample = loop_start;
+ vgmstream->loop_end_sample = loop_end;
+
+#ifdef VGM_USE_FFMPEG
+ {
+ uint8_t buf[0x100];
+ size_t bytes;
+ ffmpeg_custom_config cfg;
+ ffmpeg_codec_data *ffmpeg_data;
+
+ bytes = ffmpeg_make_opus_header(buf,0x100, vgmstream->channels, skip, vgmstream->sample_rate);
+ if (bytes <= 0) goto fail;
+
+ memset(&cfg, 0, sizeof(ffmpeg_custom_config));
+ cfg.type = FFMPEG_SWITCH_OPUS;
+
+ ffmpeg_data = init_ffmpeg_config(streamFile, buf,bytes, start_offset,data_size, &cfg);
+ if (!ffmpeg_data) goto fail;
+
+ vgmstream->codec_data = ffmpeg_data;
+ vgmstream->coding_type = coding_FFmpeg;
+ vgmstream->layout_type = layout_none;
+
+ if (ffmpeg_data->skipSamples <= 0) {
+ ffmpeg_set_skip_samples(ffmpeg_data, skip);
+ }
+
+ if (vgmstream->num_samples == 0) {
+ vgmstream->num_samples = switch_opus_get_samples(start_offset, data_size,
+ vgmstream->sample_rate, streamFile) - skip;
+ }
+ }
+#else
+ goto fail;
+#endif
+
+ /* open the file for reading */
+ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
+ goto fail;
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+
+/* standard Switch Opus, Nintendo header + raw data (generated by opus_test.c?) [Lego City Undercover (Switch)] */
+VGMSTREAM * init_vgmstream_opus_std(STREAMFILE *streamFile) {
+ off_t offset = 0;
+ int num_samples = 0, loop_start = 0, loop_end = 0;
+
+ /* checks */
+ if (!check_extensions(streamFile,"opus,lopus"))
+ goto fail;
+
+ offset = 0x00;
+ num_samples = 0;
+ loop_start = 0;
+ loop_end = 0;
+
+ return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples,loop_start,loop_end);
+fail:
+ return NULL;
+}
+
+/* Nippon1 variation [Disgaea 5 (Switch)] */
+VGMSTREAM * init_vgmstream_opus_n1(STREAMFILE *streamFile) {
+ off_t offset = 0;
+ int num_samples = 0, loop_start = 0, loop_end = 0;
+
+ /* checks */
+ if ( !check_extensions(streamFile,"opus,lopus"))
+ goto fail;
+
+ if (!((read_32bitBE(0x04,streamFile) == 0x00000000 && read_32bitBE(0x0c,streamFile) == 0x00000000) ||
+ (read_32bitBE(0x04,streamFile) == 0xFFFFFFFF && read_32bitBE(0x0c,streamFile) == 0xFFFFFFFF)))
+ goto fail;
+
+ offset = 0x10;
+ num_samples = 0;
+ loop_start = read_32bitLE(0x00,streamFile);
+ loop_end = read_32bitLE(0x08,streamFile);
+
+ return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples,loop_start,loop_end);
+fail:
+ return NULL;
+}
+
+/* Capcom variation [Ultra Street Fighter II (Switch), Resident Evil: Revelations (Switch)] */
+VGMSTREAM * init_vgmstream_opus_capcom(STREAMFILE *streamFile) {
+ VGMSTREAM *vgmstream = NULL;
+ off_t offset = 0;
+ int num_samples = 0, loop_start = 0, loop_end = 0;
+ int channel_count;
+
+ /* checks */
+ if ( !check_extensions(streamFile,"opus,lopus"))
+ goto fail;
+
+ channel_count = read_32bitLE(0x04,streamFile);
+ if (channel_count != 1 && channel_count != 2 && channel_count != 6)
+ goto fail; /* unknown stream layout */
+
+ num_samples = read_32bitLE(0x00,streamFile);
+ /* 0x04: channels, >2 uses interleaved streams (2ch+2ch+2ch) */
+ loop_start = read_32bitLE(0x08,streamFile);
+ loop_end = read_32bitLE(0x0c,streamFile);
+ /* 0x10: frame size (with extra data) */
+ /* 0x14: extra chunk count */
+ /* 0x18: null */
+ offset = read_32bitLE(0x1c,streamFile);
+ /* 0x20-8: config? (0x0077C102 04000000 E107070C) */
+ /* 0x2c: some size? */
+ /* 0x30+: extra chunks (0x00: 0x7f, 0x04: num_sample), alt loop starts/regions? */
+
+ if (channel_count == 6) {
+ /* 2ch multistream hacky-hacks, don't try this at home. We'll end up with:
+ * main vgmstream > N vgmstream layers > substream IO deinterleaver > opus meta > Opus IO transmogrifier (phew) */
+ //todo deinterleave has some problems with reading after total_size
+ layered_layout_data* data = NULL;
+ int layers = channel_count / 2;
+ int i;
+ int loop_flag = (loop_end > 0);
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->layout_type = layout_layered;
+
+ /* init layout */
+ data = init_layout_layered(layers);
+ if (!data) goto fail;
+ vgmstream->layout_data = data;
+
+ /* open each layer subfile */
+ for (i = 0; i < layers; i++) {
+ STREAMFILE* temp_streamFile = setup_opus_interleave_streamfile(streamFile, offset+0x28*i, layers);
+ if (!temp_streamFile) goto fail;
+
+ data->layers[i] = init_vgmstream_opus(temp_streamFile, meta_OPUS, 0x00, num_samples,loop_start,loop_end);
+ close_streamfile(temp_streamFile);
+ if (!data->layers[i]) goto fail;
+ }
+
+ /* setup layered VGMSTREAMs */
+ if (!setup_layout_layered(data))
+ goto fail;
+
+ vgmstream->sample_rate = data->layers[0]->sample_rate;
+ vgmstream->num_samples = data->layers[0]->num_samples;
+ vgmstream->loop_start_sample = data->layers[0]->loop_start_sample;
+ vgmstream->loop_end_sample = data->layers[0]->loop_end_sample;
+ vgmstream->meta_type = meta_OPUS;
+ vgmstream->coding_type = data->layers[0]->coding_type;
+
+ return vgmstream;
+ }
+ else {
+ return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples,loop_start,loop_end);
+ }
+
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+/* Procyon Studio variation [Xenoblade Chronicles 2 (Switch)] */
+VGMSTREAM * init_vgmstream_opus_nop(STREAMFILE *streamFile) {
+ off_t offset = 0;
+ int num_samples = 0, loop_start = 0, loop_end = 0, loop_flag;
+
+ /* checks */
+ if (!check_extensions(streamFile,"nop"))
+ goto fail;
+ if (read_32bitBE(0x00, streamFile) != 0x73616466 || /* "sadf" */
+ read_32bitBE(0x08, streamFile) != 0x6f707573) /* "opus" */
+ goto fail;
+
+ offset = read_32bitLE(0x1c, streamFile);
+ num_samples = read_32bitLE(0x28, streamFile);
+ loop_flag = read_8bit(0x19, streamFile);
+ if (loop_flag) {
+ loop_start = read_32bitLE(0x2c, streamFile);
+ loop_end = read_32bitLE(0x30, streamFile);
+ }
+
+ return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples,loop_start,loop_end);
+fail:
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/opus_interleave_streamfile.h b/Frameworks/vgmstream/vgmstream/src/meta/opus_interleave_streamfile.h
new file mode 100644
index 000000000..f4680f07e
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/opus_interleave_streamfile.h
@@ -0,0 +1,146 @@
+#ifndef _OPUS_CAPCOM_STREAMFILE_H_
+#define _OPUS_CAPCOM_STREAMFILE_H_
+#include "../streamfile.h"
+
+
+typedef struct {
+ /* state */
+ off_t logical_offset; /* offset that corresponds to physical_offset */
+ off_t physical_offset; /* actual file offset */
+ int skip_frames; /* frames to skip from other streams at points */
+
+ /* config */
+ int version;
+ int streams;
+ off_t start_offset; /* pointing to the stream's beginning */
+ size_t total_size; /* size of the resulting substream */
+} opus_interleave_io_data;
+
+
+/* Reads skipping other streams */
+static size_t opus_interleave_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, opus_interleave_io_data* data) {
+ size_t total_read = 0;
+
+ /* ignore bad reads */
+ if (offset < 0 || offset > data->total_size) {
+ return total_read;
+ }
+
+ /* previous offset: re-start as we can't map logical<>physical offsets, since it may be VBR
+ * (kinda slow as it trashes buffers, but shouldn't happen often) */
+ if (offset < data->logical_offset) {
+ data->physical_offset = data->start_offset;
+ data->logical_offset = 0x00;
+ }
+
+ /* read doing one frame at a time */
+ while (length > 0) {
+ size_t to_read, bytes_read;
+ off_t intrablock_offset, intradata_offset;
+ uint32_t data_size;
+
+ data_size = read_32bitBE(data->physical_offset+0x00,streamfile);
+
+ //if (offset >= data->total_size) //todo fix
+ // return total_read;
+
+ /* Nintendo Opus header rather than a frame */
+ if ((uint32_t)data_size == 0x01000080) {
+ data_size = read_32bitLE(data->physical_offset+0x10,streamfile);
+ data_size += 0x08;
+ }
+ else {
+ data_size += 0x08;
+ }
+
+ /* skip frames from other streams */
+ if (data->skip_frames) {
+ data->physical_offset += data_size;
+ data->skip_frames--;
+ continue;
+ }
+
+ /* requested offset is outside current block, try next */
+ if (offset >= data->logical_offset + data_size) {
+ data->physical_offset += data_size;
+ data->logical_offset += data_size;
+ data->skip_frames = data->streams - 1;
+ continue;
+ }
+
+ /* reads could fall in the middle of the block */
+ intradata_offset = offset - data->logical_offset;
+ intrablock_offset = intradata_offset;
+
+ /* clamp reads up to this block's end */
+ to_read = (data_size - intradata_offset);
+ if (to_read > length)
+ to_read = length;
+ if (to_read == 0)
+ return total_read; /* should never happen... */
+
+ /* finally read and move buffer/offsets */
+ bytes_read = read_streamfile(dest, data->physical_offset + intrablock_offset, to_read, streamfile);
+ total_read += bytes_read;
+ if (bytes_read != to_read)
+ return total_read; /* couldn't read fully */
+
+ dest += bytes_read;
+ offset += bytes_read;
+ length -= bytes_read;
+
+ /* block fully read, go next */
+ if (intradata_offset + bytes_read == data_size) {
+ data->physical_offset += data_size;
+ data->logical_offset += data_size;
+ data->skip_frames = data->streams - 1;
+ }
+ }
+
+ return total_read;
+}
+
+static size_t opus_interleave_io_size(STREAMFILE *streamfile, opus_interleave_io_data* data) {
+ off_t info_offset;
+
+ if (data->total_size)
+ return data->total_size;
+
+ info_offset = read_32bitLE(data->start_offset+0x10,streamfile);
+ return read_32bitLE(data->start_offset + info_offset+0x04,streamfile);
+}
+
+
+/* Prepares custom IO for multistream Opus, interleaves 1 packet per stream */
+static STREAMFILE* setup_opus_interleave_streamfile(STREAMFILE *streamFile, off_t start_offset, int streams) {
+ STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
+ opus_interleave_io_data io_data = {0};
+ size_t io_data_size = sizeof(opus_interleave_io_data);
+
+ io_data.start_offset = start_offset;
+ io_data.streams = streams;
+ io_data.physical_offset = start_offset;
+ io_data.total_size = opus_interleave_io_size(streamFile, &io_data); /* force init */
+
+
+ /* setup subfile */
+ new_streamFile = open_wrap_streamfile(streamFile);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, opus_interleave_io_read,opus_interleave_io_size);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_buffer_streamfile(new_streamFile,0);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ return temp_streamFile;
+
+fail:
+ close_streamfile(temp_streamFile);
+ return NULL;
+}
+
+#endif /* _OPUS_CAPCOM_STREAMFILE_H_ */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/opus_ppp.c b/Frameworks/vgmstream/vgmstream/src/meta/opus_ppp.c
new file mode 100644
index 000000000..6c69b05b6
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/opus_ppp.c
@@ -0,0 +1,120 @@
+#include "meta.h"
+#include "../coding/coding.h"
+#include "../layout/layout.h"
+
+static STREAMFILE* setup_opus_ppp_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext);
+
+/* .AT9 Opus - from Penny-Punching Princess (Switch) */
+VGMSTREAM * init_vgmstream_opus_ppp(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t segment_offset;
+ int loop_flag, channel_count;
+ int i;
+
+ segmented_layout_data *data = NULL;
+ int segment_count, loop_start_segment = 0, loop_end_segment = 0;
+ int num_samples = 0, loop_start_sample = 0, loop_end_sample = 0;
+
+
+ /* checks */
+ if (!check_extensions(streamFile, "at9"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x09000000) /* file type? DSPs had 08 */
+ goto fail;
+ if (read_32bitLE(0x04,streamFile) + 0x1c != get_streamfile_size(streamFile))
+ goto fail;
+ /* 0x08(2): sample rate, 0x0a(2): loop flag?, 0x0c: num_samples (slightly smaller than added samples) */
+
+ segment_count = 3; /* intro/loop/end */
+ loop_start_segment = 1;
+ loop_end_segment = 1;
+ loop_flag = (segment_count > 0);
+
+ /* init layout */
+ data = init_layout_segmented(segment_count);
+ if (!data) goto fail;
+
+ /* open each segment subfile */
+ segment_offset = 0x1c;
+ for (i = 0; i < segment_count; i++) {
+ STREAMFILE* temp_streamFile;
+ size_t segment_size = read_32bitLE(0x10+0x04*i,streamFile);
+
+ if (!segment_size)
+ goto fail;
+
+ temp_streamFile = setup_opus_ppp_streamfile(streamFile, segment_offset,segment_size, "opus");
+ if (!temp_streamFile) goto fail;
+
+ data->segments[i] = init_vgmstream_opus_std(temp_streamFile);
+ close_streamfile(temp_streamFile);
+ if (!data->segments[i]) goto fail;
+
+ segment_offset += segment_size;
+
+ //todo there are some trailing samples that must be removed for smooth loops, start skip seems ok
+ data->segments[i]->num_samples -= 374; //not correct for all files, no idea how to calculate
+
+ /* get looping and samples */
+ if (loop_flag && loop_start_segment == i)
+ loop_start_sample = num_samples;
+
+ num_samples += data->segments[i]->num_samples;
+
+ if (loop_flag && loop_end_segment == i)
+ loop_end_sample = num_samples;
+ }
+
+ /* setup segmented VGMSTREAMs */
+ if (!setup_layout_segmented(data))
+ goto fail;
+
+
+ channel_count = data->segments[0]->channels;
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = (uint16_t)read_16bitLE(0x08,streamFile);
+ vgmstream->num_samples = num_samples;
+ vgmstream->loop_start_sample = loop_start_sample;
+ vgmstream->loop_end_sample = loop_end_sample;
+
+ vgmstream->meta_type = meta_OPUS_PPP;
+ vgmstream->coding_type = data->segments[0]->coding_type;
+ vgmstream->layout_type = layout_segmented;
+
+ vgmstream->layout_data = data;
+ data->loop_segment = loop_start_segment;
+
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ free_layout_segmented(data);
+ return NULL;
+}
+
+static STREAMFILE* setup_opus_ppp_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext) {
+ STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
+
+ /* setup subfile */
+ new_streamFile = open_wrap_streamfile(streamFile);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,fake_ext);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ return temp_streamFile;
+
+fail:
+ close_streamfile(temp_streamFile);
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/p3d.c b/Frameworks/vgmstream/vgmstream/src/meta/p3d.c
index 7e5350a79..d03e44587 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/p3d.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/p3d.c
@@ -119,7 +119,7 @@ VGMSTREAM * init_vgmstream_p3d(STREAMFILE *streamFile) {
break;
default:
- VGM_LOG("unknown codec 0x%04x\n", codec);
+ VGM_LOG("P3D: unknown codec 0x%04x\n", codec);
goto fail;
}
@@ -175,7 +175,7 @@ VGMSTREAM * init_vgmstream_p3d(STREAMFILE *streamFile) {
#endif
default:
- VGM_LOG("unknown codec 0x%04x\n", codec);
+ VGM_LOG("P3D: unknown codec 0x%04x\n", codec);
goto fail;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/pc_mxst.c b/Frameworks/vgmstream/vgmstream/src/meta/pc_mxst.c
index 2e79f0f13..c33cfc268 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/pc_mxst.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/pc_mxst.c
@@ -179,7 +179,7 @@ VGMSTREAM * init_vgmstream_pc_mxst(STREAMFILE *streamFile) {
/* fill in the vital statistics */
vgmstream->channels = channel_count;
vgmstream->sample_rate = sample_rate;
- vgmstream->layout_type = layout_mxch_blocked;
+ vgmstream->layout_type = layout_blocked_mxch;
vgmstream->meta_type = meta_PC_MXST;
if(bits_per_sample == 8)
@@ -207,7 +207,7 @@ VGMSTREAM * init_vgmstream_pc_mxst(STREAMFILE *streamFile) {
}
}
- mxch_block_update(start_offset, vgmstream);
+ block_update_mxch(start_offset, vgmstream);
return vgmstream;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/pc_xa30.c b/Frameworks/vgmstream/vgmstream/src/meta/pc_xa30.c
index f6662cb1e..7b615bcd2 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/pc_xa30.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/pc_xa30.c
@@ -1,37 +1,36 @@
#include "meta.h"
#include "../coding/coding.h"
-/* XA30 - found in Driver: Parallel Lines (PC) */
+/* XA30 - found in Reflections games [Driver: Parallel Lines (PC), Driver 3 (PC)] */
VGMSTREAM * init_vgmstream_pc_xa30(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, codec;
- size_t file_size, data_size;
+ size_t stream_size;
+ int total_subsongs, target_subsong = streamFile->stream_index;
/* check extension, case insensitive */
- /* ".xa30" is just the ID, the real filename should be .XA */
- if (!check_extensions(streamFile,"xa,xa30"))
+ /* ".xa30/e4x" is just the ID, the real filename should be .XA */
+ if (!check_extensions(streamFile,"xa,xa30,e4x"))
goto fail;
/* check header */
- if (read_32bitBE(0x00,streamFile) != 0x58413330) /* "XA30" */
+ if (read_32bitBE(0x00,streamFile) != 0x58413330 && /* "XA30" [Driver: Parallel Lines (PC)]*/
+ read_32bitBE(0x00,streamFile) != 0x65347892) /* "e4x\92" [Driver 3 (PC)]*/
+ goto fail;
+ if (read_32bitLE(0x04,streamFile) != 2) /* channels?, also extra check to avoid PS2/PC XA30 mixup */
goto fail;
- if (read_32bitLE(0x04,streamFile) > 2) goto fail; /* extra check to avoid PS2/PC XA30 mixup */
-
- /* reportedly from XA2WAV those are offset+data from a second stream (not seen) */
- if (read_32bitLE(0x14,streamFile) != 0 || read_32bitLE(0x1c,streamFile) != 0) goto fail;
+ total_subsongs = read_32bitLE(0x14,streamFile) != 0 ? 2 : 1; /* second stream offset (only in Driver 3) */
+ if (target_subsong == 0) target_subsong = 1;
+ if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
loop_flag = 0;
channel_count = 2; /* 0x04: channels? (always 2 in practice) */
-
- codec = read_32bitLE(0x0c,streamFile); /* reportedly from XA2WAV (not seen) */
- start_offset = read_32bitLE(0x10,streamFile);
-
- file_size = get_streamfile_size(streamFile);
- data_size = read_32bitLE(0x18,streamFile);
- if (data_size+start_offset != file_size) goto fail;
+ 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);
/* build the VGMSTREAM */
@@ -39,19 +38,26 @@ VGMSTREAM * init_vgmstream_pc_xa30(STREAMFILE *streamFile) {
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
- /* 0x20: always 00016000?, rest of the header is null */
-
+ /* 0x20: always IMA=00016000, PCM=00056000 PCM?, rest of the header is null */
+ vgmstream->num_streams = total_subsongs;
+ vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_PC_XA30;
switch(codec) {
+ 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->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->num_samples = ms_ima_bytes_to_samples(data_size, vgmstream->interleave_block_size, channel_count);
+ vgmstream->num_samples = ms_ima_bytes_to_samples(stream_size, vgmstream->interleave_block_size, channel_count);
break;
- case 0x00: /* PCM? */
default:
goto fail;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/pcm_sre.c b/Frameworks/vgmstream/vgmstream/src/meta/pcm_sre.c
new file mode 100644
index 000000000..3a51c1fc3
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/pcm_sre.c
@@ -0,0 +1,76 @@
+#include "meta.h"
+#include "../coding/coding.h"
+
+/* .PCM+SRE. - Capcom's header+data container thing [Viewtiful Joe (PS2)] */
+VGMSTREAM * init_vgmstream_pcm_sre(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ STREAMFILE * streamHeader = NULL;
+ off_t start_offset;
+ int loop_flag, channel_count;
+ size_t table1_entries, table2_entries;
+ off_t table1_offset, table2_offset, header_offset;
+ int total_subsongs, target_subsong = streamFile->stream_index;
+
+
+ /* checks */
+ /* .pcm=data, .sre=header */
+ if (!check_extensions(streamFile, "pcm"))
+ goto fail;
+
+ /* first PS-ADPCM frame should be is null */
+ if (read_32bitBE(0x00,streamFile) != 0x00020000 ||
+ read_32bitBE(0x04,streamFile) != 0x00000000 ||
+ read_32bitBE(0x08,streamFile) != 0x00000000 ||
+ read_32bitBE(0x0c,streamFile) != 0x00000000)
+ goto fail;
+
+ streamHeader = open_streamfile_by_ext(streamFile, "sre");
+ if (!streamHeader) goto fail;
+
+ table1_entries = read_32bitLE(0x00, streamHeader);
+ table1_offset = read_32bitLE(0x04, streamHeader);
+ table2_entries = read_32bitLE(0x08, streamHeader);
+ table2_offset = read_32bitLE(0x0c, streamHeader);
+ if (table1_entries*0x60 + table1_offset != table2_offset)
+ goto fail; /* just in case */
+
+ total_subsongs = table2_entries;
+ if (target_subsong == 0) target_subsong = 1;
+ if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
+
+ header_offset = table2_offset + (target_subsong-1)*0x20;
+
+ channel_count = read_32bitLE(header_offset+0x00,streamHeader);
+ loop_flag = read_32bitLE(header_offset+0x18,streamHeader);
+ start_offset = read_32bitLE(header_offset+0x08,streamHeader);
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count, loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = read_16bitLE(header_offset+0x04,streamHeader);
+ vgmstream->meta_type = meta_PCM_SRE;
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x1000;
+
+ vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(header_offset+0x0c,streamHeader), channel_count);
+ vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(header_offset+0x10,streamHeader)*channel_count, channel_count);
+ vgmstream->loop_end_sample = ps_bytes_to_samples(read_32bitLE(header_offset+0x14,streamHeader)*channel_count, channel_count);
+
+ vgmstream->num_streams = total_subsongs;
+ vgmstream->stream_size = read_32bitLE(header_offset+0x0c,streamHeader);
+
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
+
+ close_streamfile(streamHeader);
+ return vgmstream;
+
+fail:
+ close_streamfile(streamHeader);
+ close_vgmstream(vgmstream);
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ppst.c b/Frameworks/vgmstream/vgmstream/src/meta/ppst.c
new file mode 100644
index 000000000..3802b662b
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ppst.c
@@ -0,0 +1,60 @@
+#include "meta.h"
+#include "../coding/coding.h"
+#include "ppst_streamfile.h"
+
+
+/* PPST - ParaPpa STream (maybe), extracted from .img bigfile [Parappa the Rapper (PSP)] */
+VGMSTREAM * init_vgmstream_ppst(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ int total_subsongs, target_subsong = streamFile->stream_index;
+
+
+ /* checks */
+ if (!check_extensions(streamFile, "sng"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x50505354) /* "PPST" */
+ goto fail;
+
+ /* header has some control and comment fields then interleaved RIFF .at3 */
+
+ /* count subsongs (mainly 4, rarely 1) */
+ {
+ off_t offset = 0xa0;
+
+ total_subsongs = 0;
+ while (offset < 0x800) {
+ if (read_32bitLE(offset + 0x04, streamFile) == 0) /* subsong size */
+ break;
+ total_subsongs++;
+ offset += 0x08;
+ }
+
+ if (target_subsong == 0) target_subsong = 1;
+ if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
+ }
+
+ {
+ off_t start_offset = 0x800;
+ size_t interleave_size = 0x4000;
+ size_t stride_size = 0x4000*total_subsongs;
+ /* subsong header at 0xa0, 0x00(1): id, 0x01(3): blocks of interleave */
+ size_t stream_size = read_32bitLE(0xA0+0x08*(target_subsong-1)+0x04, streamFile);
+
+ STREAMFILE* temp_streamFile = setup_ppst_streamfile(streamFile, start_offset+interleave_size*(target_subsong-1), interleave_size, stride_size, stream_size);
+ if (!temp_streamFile) goto fail;
+
+ vgmstream = init_vgmstream_riff(temp_streamFile);
+ close_streamfile(temp_streamFile);
+ if (!vgmstream) goto fail;
+
+ vgmstream->num_streams = total_subsongs;
+ vgmstream->stream_size = stream_size;
+ vgmstream->meta_type = meta_PPST;
+ }
+
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ppst_streamfile.h b/Frameworks/vgmstream/vgmstream/src/meta/ppst_streamfile.h
new file mode 100644
index 000000000..c3965e11e
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ppst_streamfile.h
@@ -0,0 +1,101 @@
+#ifndef _PPST_STREAMFILE_H_
+#define _PPST_STREAMFILE_H_
+#include "../streamfile.h"
+
+
+typedef struct {
+ off_t start_physical_offset; /* interleaved data start, for this substream */
+ size_t interleave_block_size; /* max size that can be read before encountering other substreams */
+ size_t stride_size; /* step size between interleave blocks (interleave*channels) */
+ size_t stream_size; /* final size of the deinterleaved substream */
+} ppst_io_data;
+
+
+/* Handles deinterleaving of complete files, skipping portions or other substreams. */
+static size_t ppst_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, ppst_io_data* data) {
+ size_t total_read = 0;
+
+
+ while (length > 0) {
+ size_t to_read;
+ size_t length_available;
+ off_t block_num;
+ off_t intrablock_offset;
+ off_t physical_offset;
+
+ if (offset >= data->stream_size)
+ return total_read;
+
+ block_num = offset / data->interleave_block_size;
+ intrablock_offset = offset % data->interleave_block_size;
+ physical_offset = data->start_physical_offset + block_num*data->stride_size + intrablock_offset;
+ length_available = data->interleave_block_size - intrablock_offset;
+ if (length_available > data->stream_size - offset)
+ length_available = data->stream_size - offset;
+
+ if (length < length_available) {
+ to_read = length;
+ }
+ else {
+ to_read = length_available;
+ }
+
+ if (to_read > 0) {
+ size_t bytes_read;
+
+ bytes_read = read_streamfile(dest, physical_offset, to_read, streamfile);
+ total_read += bytes_read;
+
+ if (bytes_read != to_read) {
+ return total_read;
+ }
+
+ dest += bytes_read;
+ offset += bytes_read;
+ length -= bytes_read;
+ }
+ }
+
+ return total_read;
+}
+
+static size_t ppst_io_size(STREAMFILE *streamfile, ppst_io_data* data) {
+ return data->stream_size;
+}
+
+
+static STREAMFILE* setup_ppst_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t interleave_block_size, size_t stride_size, size_t stream_size) {
+ STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
+ ppst_io_data io_data = {0};
+ size_t io_data_size = sizeof(ppst_io_data);
+
+ io_data.start_physical_offset = start_offset;
+ io_data.interleave_block_size = interleave_block_size;
+ io_data.stride_size = stride_size;
+ io_data.stream_size = stream_size;
+
+ /* setup subfile */
+ new_streamFile = open_wrap_streamfile(streamFile);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, ppst_io_read,ppst_io_size);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_buffer_streamfile(new_streamFile,0);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"at3");
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ return temp_streamFile;
+
+fail:
+ close_streamfile(temp_streamFile);
+ return NULL;
+}
+
+#endif /* _SCD_STREAMFILE_H_ */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_adm.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_adm.c
index 82e2f51bc..b1c6d3dbc 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_adm.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_adm.c
@@ -1,75 +1,107 @@
#include "meta.h"
#include "../layout/layout.h"
-#include "../util.h"
+#include "../coding/coding.h"
+#include
-/* WAD (from The golden Compass) */
+static int get_adm_loop_info(STREAMFILE *streamFile, off_t *loop_start_offset);
+
+/* .adm - from Dragon Quest V (PS2) */
VGMSTREAM * init_vgmstream_ps2_adm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- int loop_flag = 0;
- int channel_count;
- int i;
- off_t start_offset;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("adm",filename_extension(filename))) goto fail;
+ int channel_count, loop_flag = 0;
+ off_t start_offset, loop_start_offset = 0;
- loop_flag = 0;
- channel_count = 2;
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(channel_count,loop_flag);
- if (!vgmstream) goto fail;
+ /* checks */
+ if (!check_extensions(streamFile,"adm"))
+ goto fail;
- /* fill in the vital statistics */
- start_offset = 0x0;
- vgmstream->channels = channel_count;
- vgmstream->sample_rate = 44100;
- vgmstream->coding_type = coding_PSX;
-
-#if 0
- 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;
- }
-#endif
-
- vgmstream->layout_type = layout_ps2_adm_blocked;
- vgmstream->interleave_block_size = 0x400;
-
-
- vgmstream->meta_type = meta_PS2_ADM;
-
- /* open the file for reading by each channel */
+ /* raw data, but test some .ADM blocks as they always start with PS-ADPCM flag 0x06 every 0x1000 */
{
- for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size);
-
- if (!vgmstream->ch[i].streamfile) goto fail;
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=i*vgmstream->interleave_block_size;
+ int i;
+ for (i = 0; i < 10; i++) {
+ if (read_8bit(0x1000*i + 0x01, streamFile) != 0x06)
+ goto fail;
}
}
+ start_offset = 0x00;
+ loop_flag = get_adm_loop_info(streamFile, &loop_start_offset);
+ channel_count = 2;
- /* Calc num_samples */
- ps2_adm_block_update(start_offset,vgmstream);
- vgmstream->num_samples=0; //(get_streamfile_size(streamFile)/0x1000*0xFE0)/32*28;
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
- do {
-
- vgmstream->num_samples += 0xFE0*14/16;
- ps2_adm_block_update(vgmstream->next_block_offset,vgmstream);
- } while (vgmstream->next_block_offsetsample_rate = 44100;
+ vgmstream->meta_type = meta_PS2_ADM;
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = layout_blocked_adm;
- ps2_adm_block_update(start_offset,vgmstream);
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
+ /* calc num_samples as playable data size varies between files/blocks */
+ {
+ vgmstream->next_block_offset = start_offset;
+ do {
+ block_update_adm(vgmstream->next_block_offset,vgmstream);
+
+ if (loop_flag && vgmstream->current_block_offset == loop_start_offset)
+ vgmstream->loop_start_sample = vgmstream->num_samples;
+ vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
+ }
+ while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
+
+ if (loop_flag)
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+ }
+
+ block_update_adm(start_offset,vgmstream);
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
+
+/* loops are not in the .ADM or .DAT bigfile containing them but in the exe; manually get them (a bit meh but whatevs) */
+static int get_adm_loop_info(STREAMFILE *streamFile, off_t *loop_start_offset) {
+ char file_name[PATH_LIMIT];
+ char index_name[PATH_LIMIT];
+ STREAMFILE *streamExe = NULL;
+ int i, name_index = -1, loop_flag;
+ off_t offset;
+
+ streamExe = open_streamfile_by_filename(streamFile, "SLPM_655.55");
+ if (!streamExe) goto fail;
+
+ get_streamfile_filename(streamFile, file_name, PATH_LIMIT);
+
+ /* get file index from name list (file_name == index_name = index number */
+ offset = 0x23B3c0;
+ for (i = 0; i < 51; i++) {
+ read_string(index_name,0x20+1, offset,streamExe);
+
+ if (strcmp(index_name, file_name)==0) {
+ name_index = i;
+ break;
+ }
+ offset += 0x20;
+ }
+ if (name_index < 0)
+ goto fail;
+
+ /* get file info using index */
+ offset = 0x23BAEC + 0x1c*name_index;
+ loop_flag = (read_32bitLE(offset + 0x10, streamExe) == 0); /* 1: don't loop, 0: loop */
+ if (loop_flag) { /* loop flag */
+ *loop_start_offset = read_32bitLE(offset + 0x04, streamExe);
+ }
+ /* 0x08: num_samples/loop_end, 0x0c: sample rate (always 44100), 0x14/18: some size? */
+
+ close_streamfile(streamExe);
+ return loop_flag;
+fail:
+ close_streamfile(streamExe);
+ return 0;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_bmdx.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_bmdx.c
index a1e735af3..229b7332f 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_bmdx.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_bmdx.c
@@ -1,92 +1,116 @@
#include "meta.h"
-#include "../util.h"
+#include "../coding/coding.h"
+static STREAMFILE* setup_bmdx_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t data_size);
+
+
+/* .bmdx - from Beatmania IIDX (PS2) games */
VGMSTREAM * init_vgmstream_ps2_bmdx(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- int loop_flag=0;
- int channel_count;
+ STREAMFILE *temp_streamFile = NULL;
off_t start_offset;
- int i;
+ size_t data_size;
+ int loop_flag, channel_count, encryption;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("bmdx",filename_extension(filename))) goto fail;
- /* check NPSF Header */
+ /* checks */
+ if (!check_extensions(streamFile, "bmdx"))
+ goto fail;
if (read_32bitBE(0x00,streamFile) != 0x01006408 ||
- read_32bitBE(0x04,streamFile) != 0)
+ read_32bitBE(0x04,streamFile) != 0x00)
goto fail;
- /* check loop */
- loop_flag = (read_32bitLE(0x10,streamFile)!=0);
- channel_count=read_32bitLE(0x1C,streamFile);
-
+ start_offset = read_32bitLE(0x08,streamFile);
+ data_size = read_32bitLE(0x0c,streamFile);
+ loop_flag = (read_32bitLE(0x10,streamFile) != 0x00);
+ channel_count = read_32bitLE(0x1C,streamFile);
+ encryption = (read_32bitLE(0x20,streamFile) == 1);
+
/* 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_32bitLE(0x18,streamFile);
- /* Check for Compression Scheme */
- if (read_32bitLE(0x20,streamFile) == 1)
- vgmstream->coding_type = coding_PSX_bmdx;
- else
- vgmstream->coding_type = coding_PSX;
- vgmstream->num_samples = read_32bitLE(0x0c,streamFile)*28/16/channel_count;
-
- /* Get loop point values */
- if(vgmstream->loop_flag) {
- vgmstream->loop_start_sample = read_32bitLE(0x10,streamFile)*28/16/channel_count;
- vgmstream->loop_end_sample = vgmstream->num_samples;
- }
-
- if (channel_count == 1) {
- vgmstream->layout_type = layout_none;
- } else if (channel_count > 1) {
- vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile);
- vgmstream->layout_type = layout_interleave;
- }
+ vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
+ vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(0x10,streamFile), channel_count);
+ vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->meta_type = meta_PS2_BMDX;
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
+ vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile);
- start_offset = read_32bitLE(0x08,streamFile);
-
- if (vgmstream->coding_type == coding_PSX_bmdx)
- {
- uint8_t xor = read_8bit(start_offset,streamFile);
- uint8_t add = (~(uint8_t)read_8bit(start_offset+2,streamFile))+1;
- int c;
- for (c=0;cch[c].bmdx_xor = xor;
- vgmstream->ch[c].bmdx_add = add;
- }
+ /* later games are encrypted [beatmaniaIIDX 14 GOLD (PS2)] */
+ if (encryption) {
+ temp_streamFile = setup_bmdx_streamfile(streamFile, start_offset, data_size);
+ if (!temp_streamFile) goto fail;
}
- /* open the file for reading by each channel */
- {
- for (i=0;ich[0].streamfile) {
- vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,0x8000);
- }
- vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile;
+ if (!vgmstream_open_stream(vgmstream,encryption ? temp_streamFile : streamFile,start_offset))
+ goto fail;
- if (!vgmstream->ch[i].streamfile) goto fail;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=
- (off_t)(start_offset+vgmstream->interleave_block_size*i);
- }
- }
-
+ close_streamfile(temp_streamFile);
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_streamfile(temp_streamFile);
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+
+typedef struct {
+ uint8_t xor;
+ uint8_t add;
+ off_t start_offset;
+ size_t data_size;
+} bmdx_decryption_data;
+
+static size_t bmdx_decryption_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, bmdx_decryption_data* data) {
+ size_t bytes_read;
+ int i;
+
+ bytes_read = streamfile->read(streamfile, dest, offset, length);
+
+ /* decrypt data (xor) */
+ for (i = 0; i < bytes_read; i++) {
+ if (offset+i >= data->start_offset && offset+i < data->start_offset + data->data_size) {
+ if (((offset+i) % 0x10) == 0) /* XOR header byte per frame */
+ dest[i] = dest[i] ^ data->xor;
+ else if (((offset+i) % 0x10) == 2) /* ADD first data byte per frame */
+ dest[i] = (uint8_t)(dest[i] + data->add);
+ }
+ }
+
+ return bytes_read;
+}
+
+static STREAMFILE* setup_bmdx_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t data_size) {
+ STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
+ bmdx_decryption_data io_data = {0};
+ size_t io_data_size = sizeof(bmdx_decryption_data);
+
+ /* setup decryption (usually xor=0xFF and add=0x02) */
+ io_data.xor = read_8bit(start_offset,streamFile);
+ io_data.add = (~(uint8_t)read_8bit(start_offset+2,streamFile)) + 0x01;
+ io_data.start_offset = start_offset;
+ io_data.data_size = data_size;
+
+
+ /* setup custom streamfile */
+ new_streamFile = open_wrap_streamfile(streamFile);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, bmdx_decryption_read,NULL);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ return temp_streamFile;
+
+fail:
+ close_streamfile(temp_streamFile);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_filp.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_filp.c
index ec5d6757f..967cf2cc7 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_filp.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_filp.c
@@ -37,7 +37,7 @@ VGMSTREAM * init_vgmstream_filp(STREAMFILE *streamFile) {
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x110,streamFile);
vgmstream->coding_type = coding_PSX;
- vgmstream->layout_type = layout_filp_blocked;
+ vgmstream->layout_type = layout_blocked_filp;
vgmstream->meta_type = meta_FILP;
/* open the file for reading */
@@ -50,7 +50,7 @@ VGMSTREAM * init_vgmstream_filp(STREAMFILE *streamFile) {
}
}
- filp_block_update(start_offset,vgmstream);
+ block_update_filp(start_offset,vgmstream);
vgmstream->num_samples = read_32bitLE(0x10C,streamFile)/16*28;
if (loop_flag) {
vgmstream->loop_start_sample = 0;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_iab.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_iab.c
index 0d9fdb782..593cb4f89 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_iab.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_iab.c
@@ -1,70 +1,55 @@
#include "meta.h"
#include "../layout/layout.h"
+#include "../coding/coding.h"
#include "../util.h"
-/* IAB: Ueki no Housoku - Taosu ze Robert Juudan!! (PS2) */
+/* .IAB - from Runtime(?) games [Ueki no Housoku - Taosu ze Robert Juudan!! (PS2), RPG Maker 3 (PS2)] */
VGMSTREAM * init_vgmstream_ps2_iab(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- int loop_flag = 0;
- int channel_count;
- int i;
- off_t start_offset;
+ off_t start_offset;
+ int loop_flag, channel_count;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("iab",filename_extension(filename))) goto fail;
- /* check header */
+ /* checks */
+ if (!check_extensions(streamFile,"iab"))
+ goto fail;
+
if (read_32bitBE(0x00,streamFile) != 0x10000000)
goto fail;
-
- /* check file size */
if (read_32bitLE(0x1C,streamFile) != get_streamfile_size(streamFile))
goto fail;
loop_flag = 0;
channel_count = 2;
-
+ start_offset = 0x40;
+
/* 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(0x4,streamFile);
- vgmstream->coding_type = coding_PSX;
-
- vgmstream->layout_type = layout_ps2_iab_blocked;
- vgmstream->interleave_block_size = read_32bitLE(0xC, streamFile);
+ vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
vgmstream->meta_type = meta_PS2_IAB;
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = layout_blocked_ps2_iab;
+ //vgmstream->interleave_block_size = read_32bitLE(0x0C, streamFile); /* unneeded */
- /* open the file for reading by each channel */
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
+
+ /* calc num_samples */
{
- for (i=0;ich[i].streamfile = streamFile->open(streamFile, filename, vgmstream->interleave_block_size);
- if (!vgmstream->ch[i].streamfile) goto fail;
+ vgmstream->next_block_offset = start_offset;
+ do {
+ block_update_ps2_iab(vgmstream->next_block_offset, vgmstream);
+ vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
}
+ while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
}
- /* Calc num_samples */
- ps2_iab_block_update(start_offset, vgmstream);
- vgmstream->num_samples=0;
-
- do
- {
- vgmstream->num_samples += 0x4000 * 14 / 16;
- ps2_iab_block_update(vgmstream->next_block_offset, vgmstream);
- } while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
-
- ps2_iab_block_update(start_offset, vgmstream);
-
+ block_update_ps2_iab(start_offset, vgmstream);
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_jstm.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_jstm.c
index bb7399958..9f78093c3 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_jstm.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_jstm.c
@@ -1,63 +1,103 @@
#include "meta.h"
-#include "../util.h"
+#include "../coding/coding.h"
-/* JSTM (.STM (renamed .JSTM) from Tantei Jinguji Saburo - Kind of Blue) */
+static STREAMFILE* setup_jstm_streamfile(STREAMFILE *streamFile, off_t start_offset);
+
+/* JSTM - from Tantei Jinguji Saburo - Kind of Blue (PS2) */
VGMSTREAM * init_vgmstream_ps2_jstm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- off_t start_offset = 0x20;
- int loop_flag;
- int channel_count;
- char filename[PATH_LIMIT];
+ STREAMFILE *temp_streamFile = NULL;
+ off_t start_offset;
+ int loop_flag, channel_count;
- /* check extension */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("stm",filename_extension(filename)) &&
- strcasecmp("jstm",filename_extension(filename))) goto fail;
- /* check header (JSTM) */
- if (read_32bitBE(0x0,streamFile) != 0x4A53544D) goto fail;
+ /* checks */
+ /* .stm: original, .jstm: header id */
+ if (!check_extensions(streamFile, "stm,jstm"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x4A53544D) /* "JSTM" */
+ goto fail;
- loop_flag = (read_32bitLE(0x14,streamFile) != 0);
- channel_count = read_16bitLE(0x4,streamFile);
-
- // hmm, don't know what 6 is, one is probably bytes per sample and the
- // other is channels, but who can say?
- if (channel_count != read_16bitLE(0x6,streamFile)) goto fail;
+ start_offset = 0x20;
+ channel_count = read_16bitLE(0x04,streamFile);
+ if (channel_count != read_16bitLE(0x06,streamFile)) /* 0x02, interleave? */
+ goto fail;
+ loop_flag = (read_32bitLE(0x14,streamFile) != -1);
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- /* fill in the statistics vitale */
- vgmstream->sample_rate = read_32bitLE(0x8,streamFile);
- vgmstream->coding_type = coding_PCM16LE_XOR_int;
- vgmstream->num_samples = read_32bitLE(0xC,streamFile)/2/channel_count;
- vgmstream->layout_type = layout_none;
+ vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
+ vgmstream->num_samples = pcm_bytes_to_samples(read_32bitLE(0x0C,streamFile),channel_count,16);
+ if (loop_flag) {
+ vgmstream->loop_start_sample = pcm_bytes_to_samples(read_32bitLE(0x14,streamFile),channel_count,16);
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+ }
vgmstream->meta_type = meta_PS2_JSTM;
+ vgmstream->coding_type = coding_PCM16LE;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x02;
- if (loop_flag) {
- vgmstream->loop_start_sample=read_32bitLE(0x14,streamFile)/2/channel_count;
- vgmstream->loop_end_sample=vgmstream->num_samples;
- }
-
- /* 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; i < channel_count; i++) {
- vgmstream->ch[i].streamfile = file;
- vgmstream->ch[i].channel_start_offset =
- vgmstream->ch[i].offset = start_offset + 2*i;
- vgmstream->ch[i].key_xor = 0x5A5A;
- }
- }
+ temp_streamFile = setup_jstm_streamfile(streamFile, start_offset);
+ if (!temp_streamFile) goto fail;
+ if (!vgmstream_open_stream(vgmstream,temp_streamFile,start_offset))
+ goto fail;
+
+ close_streamfile(temp_streamFile);
+
return vgmstream;
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_streamfile(temp_streamFile);
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+
+typedef struct {
+ off_t start_offset;
+} jstm_decryption_data;
+
+static size_t jstm_decryption_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, jstm_decryption_data* data) {
+ size_t bytes_read;
+ int i;
+
+ bytes_read = streamfile->read(streamfile, dest, offset, length);
+
+ /* decrypt data (xor) */
+ for (i = 0; i < bytes_read; i++) {
+ if (offset+i >= data->start_offset) {
+ dest[i] = dest[i] ^ 0x5A;
+ }
+ }
+
+ return bytes_read;
+}
+
+static STREAMFILE* setup_jstm_streamfile(STREAMFILE *streamFile, off_t start_offset) {
+ STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
+ jstm_decryption_data io_data = {0};
+ size_t io_data_size = sizeof(jstm_decryption_data);
+
+ /* setup decryption */
+ io_data.start_offset = start_offset;
+
+
+ /* setup custom streamfile */
+ new_streamFile = open_wrap_streamfile(streamFile);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, jstm_decryption_read,NULL);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ return temp_streamFile;
+
+fail:
+ close_streamfile(temp_streamFile);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_mib.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_mib.c
index 3e4fff1f8..dfb23f4f9 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_mib.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_mib.c
@@ -1,353 +1,338 @@
#include "meta.h"
#include "../util.h"
-/* MIB
+static int check_psadpcm(STREAMFILE *streamFile);
- PS2 MIB format is a headerless format.
- The interleave value can be found by checking the body of the data.
-
- The interleave start allways at offset 0 with a int value (which can have
- many values : 0x0000, 0x0002, 0x0006 etc...) follow by 12 empty (zero) values.
-
- The interleave value is the offset where you found the same 16 bytes.
-
- The n° of channels can be found by checking each time you found this 16 bytes.
-
- The interleave value can be very "large" (up to 0x20000 found so far) and is allways
- a 0x10 multiply value.
-
- The loop values can be found by checking the 'tags' offset (found @ 0x02 each 0x10 bytes).
- 06 = start of the loop point (can be found for each channel)
- 03 - end of the loop point (can be found for each channel)
-
- The .MIH header contains all informations about frequency, numbers of channels, interleave
- but has, afaik, no loop values.
-
- known extensions : MIB (MIH for the header) MIC (concatenation of MIB+MIH)
- Nota : the MIC stuff is not supported here as there is
- another MIC format which can be found in Koei Games.
-
- 2008-05-14 - Fastelbja : First version ...
- 2008-05-20 - Fastelbja : Fix loop value when loopEnd==0
-*/
+/* MIB+MIH - from namCollection: Ace Combat 2 (PS2), Rampage - Total Destruction (PS2) */
+/* headerless PS-ADPCM - from Katamary Damacy (PS2), Air (PS2), Aladdin: Nasira's Revenge (PS1)
+ * (guesses interleave and channels by testing data and using the file extension, and finds
+ * loops in PS-ADPCM flags; this is a crutch for convenience, consider using GENH/TXTH instead). */
VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile) {
-
- VGMSTREAM * vgmstream = NULL;
+ VGMSTREAM * vgmstream = NULL;
STREAMFILE * streamFileMIH = NULL;
+ off_t start_offset = 0x00;
char filename[PATH_LIMIT];
-
- uint8_t mibBuffer[0x10];
- uint8_t testBuffer[0x10];
- uint8_t doChannelUpdate=1;
- uint8_t bDoUpdateInterleave=1;
- size_t fileLength;
-
- off_t loopStart = 0;
- off_t loopEnd = 0;
+ uint8_t mibBuffer[0x10];
+ uint8_t testBuffer[0x10];
- off_t interleave = 0;
+ size_t fileLength;
+ off_t loopStart = 0;
+ off_t loopEnd = 0;
+ off_t interleave = 0;
- off_t readOffset = 0;
+ off_t readOffset = 0;
- char filenameMIH[PATH_LIMIT];
- off_t loopStartPoints[0x10];
- int loopStartPointsCount=0;
+ off_t loopStartPoints[0x10] = {0};
+ int loopStartPointsCount=0;
+ off_t loopEndPoints[0x10] = {0};
+ int loopEndPointsCount=0;
+ int loopToEnd=0;
+ int forceNoLoop=0;
+ int gotEmptyLine=0;
- off_t loopEndPoints[0x10];
- int loopEndPointsCount=0;
+ uint8_t gotMIH=0;
- int loopToEnd=0;
- int forceNoLoop=0;
- int gotEmptyLine=0;
+ int i, channel_count=0;
- uint8_t gotMIH=0;
- int i, channel_count=0;
-
- // Initialize loop point to 0
- for(i=0; i<0x10; i++) {
- loopStartPoints[i]=0;
- loopEndPoints[i]=0;
- }
-
- /* check extension, case insensitive */
+ /* checks
+ * .mib: common, but many ext-less files are renamed to this.
+ * .mi4: fake .mib to force another sample rate
+ * .cvs: Aladdin - Nasira's Revenge (PS1)
+ * .snds: The Incredibles (PS2)
+ * .vb: Tantei Jinguuji Saburo - Mikan no Rupo (PS1)
+ * .xag: Hagane no Renkinjutsushi - Dream Carnival (PS2)
+ * */
streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("mib",filename_extension(filename)) &&
- strcasecmp("mi4",filename_extension(filename)) &&
- strcasecmp("vb",filename_extension(filename)) &&
- strcasecmp("xag",filename_extension(filename))) goto fail;
+ if (strcasecmp("cvs",filename_extension(filename)) &&
+ strcasecmp("mib",filename_extension(filename)) &&
+ strcasecmp("mi4",filename_extension(filename)) &&
+ strcasecmp("snds",filename_extension(filename))&&
+ strcasecmp("vb",filename_extension(filename)) &&
+ strcasecmp("xag",filename_extension(filename)))
+ goto fail;
- /* check for .MIH file */
- strcpy(filenameMIH,filename);
- strcpy(filenameMIH+strlen(filenameMIH)-3,"MIH");
+ /* test if raw PS-ADPCM */
+ if (!check_psadpcm(streamFile))
+ goto fail;
- streamFileMIH = streamFile->open(streamFile,filenameMIH,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (streamFileMIH) gotMIH = 1;
- /* Search for interleave value & loop points */
- /* Get the first 16 values */
- fileLength = get_streamfile_size(streamFile);
-
- readOffset+=(off_t)read_streamfile(mibBuffer,0,0x10,streamFile);
- readOffset=0;
- mibBuffer[0]=0;
+ /* .MIB may come with a .MIH header file */
+ if (strcasecmp("mib",filename_extension(filename))==0) {
+ streamFileMIH = open_streamfile_by_ext(streamFile,"mih");
+ if (streamFileMIH)
+ gotMIH = 1;
+ }
- do {
- readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile);
- // be sure to point to an interleave value
- if(readOffset<(int32_t)(fileLength*0.5)) {
- if(memcmp(testBuffer+2, mibBuffer+2,0x0e)) {
- if(doChannelUpdate) {
- doChannelUpdate=0;
- channel_count++;
- }
- if(channel_count<2)
- bDoUpdateInterleave=1;
- }
+ fileLength = get_streamfile_size(streamFile);
- testBuffer[0]=0;
- if(!memcmp(testBuffer,mibBuffer,0x10)) {
-
- gotEmptyLine=1;
-
- if(bDoUpdateInterleave) {
- bDoUpdateInterleave=0;
- interleave=readOffset-0x10;
- }
- if(((readOffset-0x10)==(channel_count*interleave))) {
- doChannelUpdate=1;
- }
- }
- }
-
- // Loop Start ...
- if(testBuffer[0x01]==0x06)
- {
- if(loopStartPointsCount<0x10)
- {
- loopStartPoints[loopStartPointsCount] = readOffset-0x10;
- loopStartPointsCount++;
- }
- }
-
- // Loop End ...
- if((testBuffer[0x01]==0x03) && (testBuffer[0x03]!=0x77)) {
- if(loopEndPointsCount<0x10)
- {
- loopEndPoints[loopEndPointsCount] = readOffset;
- loopEndPointsCount++;
- }
- }
-
- if(testBuffer[0x01]==0x04)
- {
- // 0x04 loop points flag can't be with a 0x03 loop points flag
- if(loopStartPointsCount<0x10)
- {
- loopStartPoints[loopStartPointsCount] = readOffset-0x10;
- loopStartPointsCount++;
-
- // Loop end value is not set by flags ...
- // go until end of file
- loopToEnd=1;
- }
- }
-
- } while (streamFile->get_offset(streamFile)<((int32_t)fileLength));
-
- if((testBuffer[0]==0x0c) && (testBuffer[1]==0))
- forceNoLoop=1;
-
- if(channel_count==0)
- channel_count=1;
-
- if(gotMIH)
- channel_count=read_32bitLE(0x08,streamFileMIH);
-
- // force no loop
- if(!strcasecmp("vb",filename_extension(filename)))
- loopStart=0;
-
- if(!strcasecmp("xag",filename_extension(filename)))
- channel_count=2;
-
- // Calc Loop Points & Interleave ...
- if(loopStartPointsCount>=2)
- {
- // can't get more then 0x10 loop point !
- if(loopStartPointsCount<=0x0F) {
- // Always took the first 2 loop points
- interleave=loopStartPoints[1]-loopStartPoints[0];
- loopStart=loopStartPoints[1];
-
- // Can't be one channel .mib with interleave values
- if((interleave>0) && (channel_count==1))
- channel_count=2;
- } else
- loopStart=0;
- }
-
- if(loopEndPointsCount>=2)
- {
- // can't get more then 0x10 loop point !
- if(loopEndPointsCount<=0x0F) {
- // No need to recalculate interleave value ...
- loopEnd=loopEndPoints[loopEndPointsCount-1];
-
- // Can't be one channel .mib with interleave values
- if(channel_count==1) channel_count=2;
- } else {
- loopToEnd=0;
- loopEnd=0;
- }
- }
-
- if (loopToEnd)
- loopEnd=fileLength;
-
- // force no loop
- if(forceNoLoop)
- loopEnd=0;
-
- if((interleave>0x10) && (channel_count==1))
- channel_count=2;
-
- if(interleave==0) interleave=0x10;
-
- // further check on channel_count ...
- if(gotEmptyLine)
- {
- int newChannelCount = 0;
-
- readOffset=0;
-
- do
- {
- newChannelCount++;
- read_streamfile(testBuffer,readOffset,0x10,streamFile);
- readOffset+=interleave;
- } while(!memcmp(testBuffer,mibBuffer,16));
-
- newChannelCount--;
-
- if(newChannelCount>channel_count)
- channel_count=newChannelCount;
- }
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(channel_count,(loopEnd!=0));
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- vgmstream->coding_type = coding_PSX;
- vgmstream->layout_type = layout_interleave;
-
- if(gotMIH) {
- // Read stuff from the MIH file
- vgmstream->channels = read_32bitLE(0x08,streamFileMIH);
- vgmstream->sample_rate = read_32bitLE(0x0C,streamFileMIH);
- vgmstream->interleave_block_size = read_32bitLE(0x10,streamFileMIH);
- vgmstream->num_samples=((read_32bitLE(0x10,streamFileMIH)*
- (read_32bitLE(0x14,streamFileMIH)-1)*2)+
- ((read_32bitLE(0x04,streamFileMIH)>>8)*2))/16*28/2;
- } else {
- vgmstream->channels = channel_count;
- vgmstream->interleave_block_size = interleave;
-
- if(!strcasecmp("mib",filename_extension(filename)))
- vgmstream->sample_rate = 44100;
-
- if(!strcasecmp("mi4",filename_extension(filename)))
- vgmstream->sample_rate = 48000;
-
- if(!strcasecmp("xag",filename_extension(filename))) {
- vgmstream->channels=2;
- vgmstream->sample_rate = 44100;
- }
-
- if(!strcasecmp("vb",filename_extension(filename)))
- {
- vgmstream->layout_type = layout_none;
- vgmstream->interleave_block_size=0;
- vgmstream->sample_rate = 22050;
- vgmstream->channels = 1;
- }
-
- vgmstream->num_samples = (int32_t)(fileLength/16/channel_count*28);
- }
-
- if(loopEnd!=0) {
- if(vgmstream->channels==1) {
- vgmstream->loop_start_sample = loopStart/16*18;
- vgmstream->loop_end_sample = loopEnd/16*28;
- } else {
- vgmstream->loop_start_sample = ((((loopStart/vgmstream->interleave_block_size)-1)*vgmstream->interleave_block_size)/16*14*channel_count)/channel_count;
- if(loopStart%vgmstream->interleave_block_size) {
- vgmstream->loop_start_sample += (((loopStart%vgmstream->interleave_block_size)-1)/16*14*channel_count);
- }
-
- if(loopEnd==fileLength)
- {
- vgmstream->loop_end_sample=(loopEnd/16*28)/channel_count;
- } else {
- vgmstream->loop_end_sample = ((((loopEnd/vgmstream->interleave_block_size)-1)*vgmstream->interleave_block_size)/16*14*channel_count)/channel_count;
-
- if(loopEnd%vgmstream->interleave_block_size) {
- vgmstream->loop_end_sample += (((loopEnd%vgmstream->interleave_block_size)-1)/16*14*channel_count);
- }
- }
- }
- }
-
- if(loopToEnd)
- {
- // try to find if there's no empty line ...
- int emptySamples=0;
-
- for(i=0; i<16;i++) {
- mibBuffer[i]=0;
- }
-
- readOffset=fileLength-0x10;
-
- do {
- read_streamfile(testBuffer,readOffset,0x10,streamFile);
- if(!memcmp(mibBuffer,testBuffer,16))
- {
- emptySamples+=28;
- }
- readOffset-=0x10;
- } while(!memcmp(testBuffer,mibBuffer,16));
-
- vgmstream->loop_end_sample-=(emptySamples*channel_count);
- }
- vgmstream->meta_type = meta_PS2_MIB;
-
- if (gotMIH) {
- vgmstream->meta_type = meta_PS2_MIB_MIH;
- close_streamfile(streamFileMIH); streamFileMIH=NULL;
- }
-
- /* open the file for reading by each channel */
+ /* Search for interleave value (checking channel starts) and loop points (using PS-ADPCM flags).
+ * Channel start will by 0x0000, 0x0002, 0x0006 followed by 12 zero values.
+ * Interleave value is the offset where those repeat, and channels the number of times.
+ * Loop flags in second byte are: 0x06 = start, 0x03 = end (per channel).
+ * Interleave can be large (up to 0x20000 found so far) and is always a 0x10 multiple value. */
+ readOffset+=(off_t)read_streamfile(mibBuffer,0,0x10,streamFile);
+ mibBuffer[0]=0;
{
- for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,0x8000);
+ uint8_t doChannelUpdate=1;
+ uint8_t bDoUpdateInterleave=1;
- if (!vgmstream->ch[i].streamfile) goto fail;
+ readOffset=0;
+ do {
+ readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile);
+ // be sure to point to an interleave value
+ if(readOffset<(int32_t)(fileLength*0.5)) {
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=i*vgmstream->interleave_block_size;
+ if(memcmp(testBuffer+2, mibBuffer+2,0x0e)) {
+ if(doChannelUpdate) {
+ doChannelUpdate=0;
+ channel_count++;
+ }
+ if(channel_count<2)
+ bDoUpdateInterleave=1;
+ }
+
+ testBuffer[0]=0;
+ if(!memcmp(testBuffer,mibBuffer,0x10)) {
+ gotEmptyLine=1;
+
+ if(bDoUpdateInterleave) {
+ bDoUpdateInterleave=0;
+ interleave=readOffset-0x10;
+ }
+ if(readOffset-0x10 == channel_count*interleave) {
+ doChannelUpdate=1;
+ }
+ }
+ }
+
+ // Loop Start ...
+ if(testBuffer[0x01]==0x06) {
+ if(loopStartPointsCount<0x10) {
+ loopStartPoints[loopStartPointsCount] = readOffset-0x10;
+ loopStartPointsCount++;
+ }
+ }
+
+ // Loop End ...
+ if(testBuffer[0x01]==0x03 && testBuffer[0x03]!=0x77) {
+ if(loopEndPointsCount<0x10) {
+ loopEndPoints[loopEndPointsCount] = readOffset;
+ loopEndPointsCount++;
+ }
+ }
+
+ if(testBuffer[0x01]==0x04) {
+ // 0x04 loop points flag can't be with a 0x03 loop points flag
+ if(loopStartPointsCount<0x10) {
+ loopStartPoints[loopStartPointsCount] = readOffset-0x10;
+ loopStartPointsCount++;
+
+ // Loop end value is not set by flags ...
+ // go until end of file
+ loopToEnd=1;
+ }
+ }
+
+ } while (streamFile->get_offset(streamFile)<((int32_t)fileLength));
+ }
+
+ if(testBuffer[0]==0x0c && testBuffer[1]==0)
+ forceNoLoop=1;
+
+ if(channel_count==0)
+ channel_count=1;
+
+ if(gotMIH)
+ channel_count=read_32bitLE(0x08,streamFileMIH);
+
+ // force no loop
+ if(!strcasecmp("vb",filename_extension(filename)))
+ loopStart=0;
+
+ if(!strcasecmp("xag",filename_extension(filename)))
+ channel_count=2;
+
+ // Calc Loop Points & Interleave ...
+ if(loopStartPointsCount>=2) {
+ // can't get more then 0x10 loop point !
+ if(loopStartPointsCount<=0x0F) {
+ // Always took the first 2 loop points
+ interleave=loopStartPoints[1]-loopStartPoints[0];
+ loopStart=loopStartPoints[1];
+
+ // Can't be one channel .mib with interleave values
+ if(interleave>0 && channel_count==1)
+ channel_count=2;
+ } else {
+ loopStart=0;
}
}
+ if(loopEndPointsCount>=2) {
+ // can't get more then 0x10 loop point !
+ if(loopEndPointsCount<=0x0F) {
+ // No need to recalculate interleave value ...
+ loopEnd=loopEndPoints[loopEndPointsCount-1];
+
+ // Can't be one channel .mib with interleave values
+ if(channel_count==1)
+ channel_count=2;
+ } else {
+ loopToEnd=0;
+ loopEnd=0;
+ }
+ }
+
+ if (loopToEnd)
+ loopEnd=fileLength;
+
+ if(forceNoLoop)
+ loopEnd=0;
+
+ if(interleave>0x10 && channel_count==1)
+ channel_count=2;
+
+ if(interleave==0)
+ interleave=0x10;
+
+ // further check on channel_count ...
+ if(gotEmptyLine) {
+ int newChannelCount = 0;
+
+ readOffset=0;
+
+ /* count empty lines at interleave = channels */
+ do {
+ newChannelCount++;
+ read_streamfile(testBuffer,readOffset,0x10,streamFile);
+ readOffset+=interleave;
+ } while(!memcmp(testBuffer,mibBuffer,16));
+
+ newChannelCount--;
+ if(newChannelCount>channel_count)
+ channel_count=newChannelCount;
+ }
+
+ if (!strcasecmp("cvs", filename_extension(filename)) ||
+ !strcasecmp("vb",filename_extension(filename)))
+ channel_count=1;
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,(loopEnd!=0));
+ if (!vgmstream) goto fail;
+
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
+
+ if(gotMIH) {
+ // Read stuff from the MIH file
+ vgmstream->sample_rate = read_32bitLE(0x0C,streamFileMIH);
+ vgmstream->interleave_block_size = read_32bitLE(0x10,streamFileMIH);
+ vgmstream->num_samples=((read_32bitLE(0x10,streamFileMIH)*
+ (read_32bitLE(0x14,streamFileMIH)-1)*2)+
+ ((read_32bitLE(0x04,streamFileMIH)>>8)*2))/16*28/2;
+ } else {
+ vgmstream->interleave_block_size = interleave;
+
+ if(!strcasecmp("mib",filename_extension(filename)))
+ vgmstream->sample_rate = 44100;
+
+ if(!strcasecmp("mi4",filename_extension(filename)))
+ vgmstream->sample_rate = 48000;
+
+ if(!strcasecmp("snds", filename_extension(filename)))
+ vgmstream->sample_rate = 48000;
+
+ if(!strcasecmp("xag",filename_extension(filename)))
+ vgmstream->sample_rate = 44100;
+
+ if (!strcasecmp("cvs", filename_extension(filename)) ||
+ !strcasecmp("vb",filename_extension(filename)))
+ vgmstream->sample_rate = 22050;
+
+ vgmstream->num_samples = (int32_t)(fileLength/16/channel_count*28);
+ }
+
+ if(loopEnd!=0) {
+ if(vgmstream->channels==1) {
+ vgmstream->loop_start_sample = loopStart/16*18; //todo 18 instead of 28 probably a bug
+ vgmstream->loop_end_sample = loopEnd/16*28;
+ } else {
+ vgmstream->loop_start_sample = ((((loopStart/vgmstream->interleave_block_size)-1)*vgmstream->interleave_block_size)/16*14*channel_count)/channel_count;
+ if(loopStart%vgmstream->interleave_block_size) {
+ vgmstream->loop_start_sample += (((loopStart%vgmstream->interleave_block_size)-1)/16*14*channel_count);
+ }
+
+ if(loopEnd==fileLength) {
+ vgmstream->loop_end_sample=(loopEnd/16*28)/channel_count;
+ } else {
+ vgmstream->loop_end_sample = ((((loopEnd/vgmstream->interleave_block_size)-1)*vgmstream->interleave_block_size)/16*14*channel_count)/channel_count;
+ if(loopEnd%vgmstream->interleave_block_size) {
+ vgmstream->loop_end_sample += (((loopEnd%vgmstream->interleave_block_size)-1)/16*14*channel_count);
+ }
+ }
+ }
+ }
+
+ if(loopToEnd) {
+ // try to find if there's no empty line ...
+ int emptySamples=0;
+
+ for(i=0; i<16;i++) {
+ mibBuffer[i]=0; //memset
+ }
+
+ readOffset=fileLength-0x10;
+ do {
+ read_streamfile(testBuffer,readOffset,0x10,streamFile);
+ if(!memcmp(mibBuffer,testBuffer,16)) {
+ emptySamples+=28;
+ }
+ readOffset-=0x10;
+ } while(!memcmp(testBuffer,mibBuffer,16));
+
+ vgmstream->loop_end_sample-=(emptySamples*channel_count);
+ }
+
+ vgmstream->meta_type = gotMIH ? meta_PS2_MIB_MIH : meta_PS2_MIB;
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
+
+
+ close_streamfile(streamFileMIH);
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (streamFileMIH) close_streamfile(streamFileMIH);
- if (vgmstream) close_vgmstream(vgmstream);
+ close_streamfile(streamFileMIH);
+ close_vgmstream(vgmstream);
return NULL;
}
+
+/* tests some PS-ADPCM frames */
+static int check_psadpcm(STREAMFILE *streamFile) {
+ off_t offset, max_offset;
+
+ max_offset = get_streamfile_size(streamFile);
+ if (max_offset > 0x2000)
+ max_offset = 0x2000;
+
+ offset = 0x00;
+ while (offset < max_offset) {
+ uint8_t predictor = (read_8bit(offset+0x00,streamFile) >> 4) & 0x0f;
+ uint8_t flags = read_8bit(offset+0x01,streamFile);
+
+ if (predictor > 5 || flags > 7)
+ goto fail;
+ offset += 0x10;
+ }
+
+ return 1;
+fail:
+ return 0;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_mihb.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_mihb.c
index 826d1d5c4..9f3118db7 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_mihb.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_mihb.c
@@ -1,72 +1,53 @@
#include "meta.h"
-#include "../util.h"
+#include "../coding/coding.h"
-/* MIHB (Merged MIH+MIB) */
+/* MIC/MIHB - Merged MIH+MIB [Rogue Trooper (PS2), The Sims 2 (PS2)] */
VGMSTREAM * init_vgmstream_ps2_mihb(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
off_t start_offset;
- int mib_blocks;
- int loop_flag = 0;
- int channel_count;
+ size_t data_size, frame_size, frame_last, frame_count;
+ int channel_count, loop_flag;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("mihb",filename_extension(filename))) goto fail;
-
- /* check header */
- if (read_32bitBE(0x00,streamFile) != 0x40000000)
+ /* check extension */
+ /* .mic: Rebellion Dev. games, .mihb: assumed? */
+ if (!check_extensions(streamFile, "mic,mihb"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x40000000) /* header size */
goto fail;
- mib_blocks = read_32bitLE(0x14,streamFile);
loop_flag = 0;
channel_count = read_32bitLE(0x08,streamFile);
-
+ start_offset = 0x40;
+
+ /* frame_size * frame_count * channels = data_size, but last frame has less usable data */
+ {
+ /* 0x04(1): 0x20? */
+ frame_last = (uint16_t)read_16bitLE(0x05,streamFile);
+ frame_size = read_32bitLE(0x10,streamFile);
+ frame_count = read_32bitLE(0x14,streamFile);
+
+ data_size = frame_count * frame_size;
+ data_size -= frame_last ? (frame_size-frame_last) : 0;
+ data_size *= channel_count;
+ }
+
/* 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(0x0C,streamFile);
+ vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
+
+ vgmstream->meta_type = meta_PS2_MIHB;
vgmstream->coding_type = coding_PSX;
- vgmstream->num_samples = ((read_32bitLE(0x10,streamFile))*mib_blocks)*28/16;
- if (loop_flag) {
- vgmstream->loop_start_sample = 0;
- vgmstream->loop_end_sample = ((read_32bitLE(0x10,streamFile))*mib_blocks)*28/16;
- }
-
-
- if (vgmstream->channels > 1) {
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile);
- } else {
- vgmstream->layout_type = layout_none;
- }
-
- vgmstream->meta_type = meta_PS2_MIHB;
-
- /* 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->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = frame_size;
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_msa.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_msa.c
index 197726aa8..22a184e11 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_msa.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_msa.c
@@ -1,47 +1,46 @@
#include "meta.h"
-#include "../util.h"
+#include "../coding/coding.h"
-/* MSA (from Psyvariar -Complete Edition-) */
+/* MSA - from Psyvariar -Complete Edition- (PS2) */
VGMSTREAM * init_vgmstream_ps2_msa(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- off_t start_offset, datasize, filesize;
+ off_t start_offset, data_size, file_size;
int loop_flag, channel_count;
- /* check extension, case insensitive */
- if (!check_extensions(streamFile, "msa")) goto fail;
-
- /* check header */
+ /* checks */
+ if (!check_extensions(streamFile, "msa"))
+ goto fail;
if (read_32bitBE(0x00,streamFile) != 0x00000000)
goto fail;
loop_flag = 0;
channel_count = 2;
+ start_offset = 0x14;
+ data_size = read_32bitLE(0x4,streamFile);
+ file_size = get_streamfile_size(streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- start_offset = 0x14;
- datasize = read_32bitLE(0x4,streamFile);
- filesize = get_streamfile_size(streamFile);
- vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
- vgmstream->num_samples = datasize*28/(16*channel_count);
+ if (vgmstream->sample_rate == 0) /* ex. AME.MSA */
+ vgmstream->sample_rate = 44100;
+
+ vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);//data_size*28/(0x10*channel_count);
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x4000;
vgmstream->meta_type = meta_PS2_MSA;
- /* MSAs are strangely truncated, so manually calculate samples
- * data after last usable block is always silence or garbage */
- if (datasize > filesize) {
- off_t usable_size = filesize - start_offset;
+ /* MSAs are strangely truncated, so manually calculate samples.
+ * Data after last usable block is always silence or garbage. */
+ if (data_size > file_size) {
+ off_t usable_size = file_size - start_offset;
usable_size -= usable_size % (vgmstream->interleave_block_size*channel_count);/* block-aligned */
- vgmstream->num_samples = usable_size * 28 / (16*channel_count);
+ vgmstream->num_samples = ps_bytes_to_samples(usable_size, channel_count);//usable_size * 28 / (16*channel_count);
}
-
- /* open the file for reading */
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
goto fail;
return vgmstream;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_psh.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_psh.c
index e502a1ee6..cb9d3a1b7 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_psh.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_psh.c
@@ -1,11 +1,10 @@
#include "meta.h"
#include "../util.h"
-/* PSH (from Dawn of Mana - Seiken Densetsu 4) */
+/* PSH (from Dawn of Mana - Seiken Densetsu 4, Kingdom Hearts Re:Chain of Memories) */
/* probably Square Vag Stream */
VGMSTREAM * init_vgmstream_ps2_psh(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
off_t start_offset;
uint8_t testBuffer[0x10];
off_t loopEnd = 0;
@@ -16,8 +15,8 @@ VGMSTREAM * init_vgmstream_ps2_psh(STREAMFILE *streamFile) {
int channel_count;
/* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("psh",filename_extension(filename))) goto fail;
+ if (!check_extensions(streamFile, "psh,vsv")) // vsv seems to be official extension
+ goto fail;
/* check header */
if (read_16bitBE(0x02,streamFile) != 0x6400)
@@ -65,25 +64,12 @@ VGMSTREAM * init_vgmstream_ps2_psh(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_PS2_PSH;
/* open the file for reading */
- {
- int i;
- STREAMFILE * file;
- file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!file) goto fail;
- for (i=0;ich[i].streamfile = file;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=start_offset+
- vgmstream->interleave_block_size*i;
-
- }
- }
-
+ if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
+ goto fail;
return vgmstream;
/* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_psw.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_psw.c
deleted file mode 100644
index 6ac4ffa2b..000000000
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_psw.c
+++ /dev/null
@@ -1,88 +0,0 @@
-#include "meta.h"
-#include "../util.h"
-
-/* PSW (from Rayman Raving Rabbids)
-...coefs are missing for the dsp type... */
-VGMSTREAM * init_vgmstream_ps2_psw(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("psw",filename_extension(filename))) goto fail;
-
- /* check header */
- if (read_32bitBE(0x00,streamFile) != 0x52494646 && /* "RIFF" */
- read_32bitBE(0x08,streamFile) != 0x57415645 && /* "WAVE" */
- read_32bitBE(0x26,streamFile) != 0x64617461) /* "data" */
- goto fail;
-
- loop_flag = 0;
- channel_count = read_16bitLE(0x16,streamFile);
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(channel_count,loop_flag);
- if (!vgmstream) goto fail;
-
- /* fill in the vital statistics */
- switch ((uint16_t)read_16bitBE(0x14,streamFile)) {
- case 0xFFFF:
- start_offset = 0x2E;
- vgmstream->channels = channel_count;
- vgmstream->sample_rate = read_16bitLE(0x1C,streamFile);
- vgmstream->coding_type = coding_PSX;
- vgmstream->num_samples = read_32bitLE(0x2A,streamFile)*28/16/channel_count;
- if (loop_flag) {
- vgmstream->loop_start_sample = loop_flag;
- vgmstream->loop_end_sample = read_32bitLE(0x2A,streamFile)*28/16/channel_count;
- }
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = 0x6400;
- vgmstream->meta_type = meta_PS2_PSW;
-
- break;
- case 0xFEFF:
- start_offset = 0x2E;
- vgmstream->channels = channel_count;
- vgmstream->sample_rate = read_16bitLE(0x1C,streamFile);
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->num_samples = read_32bitLE(0x2A,streamFile)*28/16/channel_count;
- if (loop_flag) {
- vgmstream->loop_start_sample = loop_flag;
- vgmstream->loop_end_sample = read_32bitLE(0x2A,streamFile)*28/16/channel_count;
- }
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = 0x12C00;
- vgmstream->meta_type = meta_PS2_PSW;
-
- break;
-default:
- goto fail;
-}
-
- /* 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_rxws.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_rxws.c
index d32b69e03..2cffb9946 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_rxws.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_rxws.c
@@ -24,7 +24,7 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
(read_32bitBE(0x00,streamFile) == 0x444E4257)) /* "DNBW" (BE) */
goto fail;
- streamHeader = open_stream_ext(streamFile, "xwh");
+ streamHeader = open_streamfile_by_ext(streamFile, "xwh");
if (!streamHeader) goto fail;
} else {
streamHeader = streamFile;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_sl3.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_sl3.c
index b145cc506..69fc81d38 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_sl3.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_sl3.c
@@ -1,65 +1,45 @@
#include "meta.h"
-#include "../util.h"
+#include "../coding/coding.h"
-/* SL3 (from Test Drive Unlimited, Transformers) */
+/* SL3 - Atari Melbourne House games [ Test Drive Unlimited (PS2), Transformers (PS2)] */
VGMSTREAM * init_vgmstream_sl3(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
off_t start_offset;
+ int loop_flag = 0, channel_count;
- int loop_flag = 0;
- int channel_count;
-
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("sl3",filename_extension(filename))) goto fail;
-
- /* check header */
+ /* 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;
- /* fill in the vital statistics */
- start_offset = 0x8000;
- vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x18,streamFile);
- vgmstream->coding_type = coding_PSX;
- vgmstream->num_samples = (get_streamfile_size(streamFile)-0x8000)*28/16/channel_count;
+ 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;
- /* open the file for reading */
- {
- int i;
- STREAMFILE * file;
- file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!file) goto fail;
- for (i=0;ich[i].streamfile = file;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=start_offset+
- vgmstream->interleave_block_size*i;
-
- }
- }
-
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_snd.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_snd.c
index e1be6525f..42378f97d 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_snd.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_snd.c
@@ -1,79 +1,53 @@
#include "meta.h"
#include "../util.h"
-/* SND (Warriors of Might and Magic Heroes of M&M:Dragonbone Staff) */
+/* SND - Might and Magic games [Warriors of M&M (PS2), Heroes of M&M: Quest for the DragonBone Staff (PS2)] */
VGMSTREAM * init_vgmstream_ps2_snd(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ size_t data_size;
+ int loop_flag, channel_count;
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- off_t start_offset;
+ /* checks */
+ if (!check_extensions(streamFile, "snd"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x53534E44) /* "SSND" */
+ goto fail;
- int loop_flag;
- int channel_count;
+ start_offset = read_32bitLE(0x04,streamFile)+0x08;
+ data_size = get_streamfile_size(streamFile) - start_offset;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("snd",filename_extension(filename))) goto fail;
-
- /* check header */
- if (read_32bitBE(0x0,streamFile) !=0x53534e44) goto fail;
-
- /* Force Loop 0->end */
- loop_flag = 1;
+ loop_flag = 1; /* force full Loop */
channel_count = read_16bitLE(0x0a,streamFile);
-
+
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- /* fill in the vital statistics */
- start_offset = read_32bitLE(0x04,streamFile)+8;
- vgmstream->sample_rate = (uint16_t)read_16bitLE(0xe,streamFile);
-
- if(read_8bit(0x08,streamFile)==1) {
- vgmstream->coding_type = coding_DVI_IMA_int;
- }
- else
- vgmstream->coding_type = coding_PCM16LE;
-
+ vgmstream->sample_rate = (uint16_t)read_16bitLE(0x0e,streamFile);
vgmstream->num_samples = read_32bitLE(0x16,streamFile);
+ vgmstream->loop_start_sample = 0;
+ vgmstream->loop_end_sample = vgmstream->num_samples;
- vgmstream->interleave_block_size = (uint16_t)read_16bitLE(0x12,streamFile);
-
- if((get_streamfile_size(streamFile)-start_offset)%vgmstream->interleave_block_size)
- {
- /* not sure if this is right ... */
- vgmstream->layout_type = layout_interleave_shortblock;
- vgmstream->interleave_smallblock_size = ((get_streamfile_size(streamFile)-start_offset)%vgmstream->interleave_block_size)/vgmstream->channels;
- } else {
- vgmstream->layout_type = layout_interleave;
- }
vgmstream->meta_type = meta_PS2_SND;
- if(loop_flag) {
- vgmstream->loop_start_sample=0;
- vgmstream->loop_end_sample=vgmstream->num_samples;
- }
+ if (read_8bit(0x08,streamFile)==1) {
+ vgmstream->coding_type = coding_DVI_IMA_int; /* Warriors of M&M DragonBone */
+ }
+ else {
+ vgmstream->coding_type = coding_PCM16LE; /* Heroes of M&M */
+ }
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = (uint16_t)read_16bitLE(0x12,streamFile);
+ if (vgmstream->interleave_block_size)
+ vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->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;
- }
- }
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
+ return vgmstream;
- return vgmstream;
-
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
- return NULL;
+ close_vgmstream(vgmstream);
+ return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_strlr.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_strlr.c
index 0ef63ea59..2003f3795 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_strlr.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_strlr.c
@@ -46,7 +46,7 @@ VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE *streamFile) {
vgmstream->sample_rate = 48000;
vgmstream->coding_type = coding_PSX;
- vgmstream->layout_type = layout_ps2_strlr_blocked;
+ vgmstream->layout_type = layout_blocked_ps2_strlr;
//vgmstream->interleave_block_size = read_32bitLE(0xC, streamFile);
vgmstream->meta_type = meta_PS2_STRLR;
@@ -60,16 +60,16 @@ VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE *streamFile) {
}
/* Calc num_samples */
- ps2_strlr_block_update(start_offset, vgmstream);
+ block_update_ps2_strlr(start_offset, vgmstream);
vgmstream->num_samples=0;
do
{
vgmstream->num_samples += vgmstream->current_block_size * 14 / 16;
- ps2_strlr_block_update(vgmstream->next_block_offset, vgmstream);
+ block_update_ps2_strlr(vgmstream->next_block_offset, vgmstream);
} while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
- ps2_strlr_block_update(start_offset, vgmstream);
+ block_update_ps2_strlr(start_offset, vgmstream);
return vgmstream;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_svag.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_svag.c
index ee9204180..beae5882e 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_svag.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_svag.c
@@ -1,85 +1,53 @@
#include "meta.h"
-#include "../util.h"
-
-/* SVAG
-
- PS2 SVAG format is an interleaved format found in many konami Games
- The header start with a Svag id and have the sentence :
- "ALL RIGHTS RESERVED.KONAMITYO Sound Design Dept. "
- or "ALL RIGHTS RESERVED.KCE-Tokyo Sound Design Dept. "
-
- 2008-05-13 - Fastelbja : First version ...
- Thx to HCS for his awesome work on shortblock interleave
-*/
+#include "../coding/coding.h"
+/* SVAG - from Konami Tokyo games [OZ (PS2), Neo Contra (PS2)]] */
VGMSTREAM * init_vgmstream_ps2_svag(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
+ off_t start_offset;
+ size_t data_size;
+ int loop_flag, channel_count;
- int loop_flag=0;
- int channel_count;
- int i;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("svag",filename_extension(filename))) goto fail;
-
- /* check SVAG Header */
- if (read_32bitBE(0x00,streamFile) != 0x53766167)
+ /* checks */
+ if (!check_extensions(streamFile, "svag"))
goto fail;
- /* check loop */
+ if (read_32bitBE(0x00,streamFile) != 0x53766167) /* "Svag" */
+ goto fail;
+
+ channel_count = read_16bitLE(0x0C,streamFile); /* always 2? ("S"tereo vag?) */
loop_flag = (read_32bitLE(0x14,streamFile)==1);
- channel_count=read_16bitLE(0x0C,streamFile);
+ start_offset = 0x800; /* header repeated at 0x400 too */
+ data_size = read_32bitLE(0x04,streamFile);
+
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- /* fill in the vital statistics */
- vgmstream->channels = read_16bitLE(0x0C,streamFile);
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
- /* Compression Scheme */
- vgmstream->coding_type = coding_PSX;
- vgmstream->num_samples = read_32bitLE(0x04,streamFile)/16*28/vgmstream->channels;
-
- /* Get loop point values */
+ vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x04,streamFile), vgmstream->channels);
if(vgmstream->loop_flag) {
- vgmstream->loop_start_sample = read_32bitLE(0x18,streamFile)/16*28;
- vgmstream->loop_end_sample = read_32bitLE(0x04,streamFile)/16*28/vgmstream->channels;
+ vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(0x18,streamFile)*vgmstream->channels, vgmstream->channels);
+ vgmstream->loop_end_sample = vgmstream->num_samples;
}
- vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile);
- if (channel_count > 1) {
- vgmstream->interleave_smallblock_size = (read_32bitLE(0x04,streamFile)%(vgmstream->channels*vgmstream->interleave_block_size))/vgmstream->channels;
- vgmstream->layout_type = layout_interleave_shortblock;
- } else {
- vgmstream->layout_type = layout_none;
- }
vgmstream->meta_type = meta_PS2_SVAG;
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile);
+ if (vgmstream->interleave_block_size)
+ vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
- /* open the file for reading by each channel */
- {
- for (i=0;i 1)
- vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size);
- else
- vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
-
- if (!vgmstream->ch[i].streamfile) goto fail;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=
- (off_t)(0x800+vgmstream->interleave_block_size*i);
- }
- }
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_tk5.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_tk5.c
index bf7efc3a1..aefb4f8e2 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_tk5.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_tk5.c
@@ -1,6 +1,5 @@
-
#include "meta.h"
-#include "../util.h"
+#include "../coding/coding.h"
/* TK5 (Tekken 5 Streams) */
VGMSTREAM * init_vgmstream_ps2_tk5(STREAMFILE *streamFile) {
@@ -65,65 +64,45 @@ fail:
return NULL;
}
-/* TK1 (Tekken 5 Streams from Tekken (NamCollection)) */
+/* OVB - Tekken 5 Streams from Tekken (NamCollection) */
VGMSTREAM * init_vgmstream_ps2_tk1(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
off_t start_offset;
- int loop_flag = 0;
- int channel_count;
+ int loop_flag = 0, channel_count;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("tk1",filename_extension(filename))) goto fail;
+ /* checks */
+ if (!check_extensions(streamFile, "ovb"))
+ goto fail;
- /* check header */
if (read_32bitBE(0x00,streamFile) != 0x544B3553)
goto fail;
loop_flag = (read_32bitLE(0x0C,streamFile)!=0);
channel_count = 2;
-
+ start_offset = 0x800;
+ /* NamCollection uses 44100 while Tekken 5 48000, no apparent way to tell them apart */
+
/* 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 = 44100;
+ vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x08,streamFile)*channel_count, channel_count);
+ if (vgmstream->loop_flag) {
+ vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile)/16*28;
+ vgmstream->loop_end_sample = vgmstream->loop_start_sample + ps_bytes_to_samples(read_32bitLE(0x0c,streamFile)*channel_count, channel_count);
+ }
+
vgmstream->coding_type = coding_PSX_badflags;
- vgmstream->num_samples = read_32bitLE(0x08,streamFile)/16*28;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
vgmstream->meta_type = meta_PS2_TK1;
- if (vgmstream->loop_flag)
- {
- vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile)/16*28;
- vgmstream->loop_end_sample = vgmstream->loop_start_sample + (read_32bitLE(0x0C,streamFile)/16*28);
- }
-
- /* open the file for reading */
- {
- int i;
- STREAMFILE * file;
- file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!file) goto fail;
- for (i=0;ich[i].streamfile = file;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=start_offset+
- vgmstream->interleave_block_size*i;
-
- }
- }
-
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_vag.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_vag.c
index 9af6a79e1..9d5303c8e 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_vag.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_vag.c
@@ -17,8 +17,9 @@ VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile) {
int channel_count = 0;
int is_swag = 0;
- /* check extension (.swag: Frantix PSP, .str: Ben10 Galactic Racing, .vig: MX vs. ATV Untamed PS2) */
- if ( !check_extensions(streamFile,"vag,swag,str,vig") )
+ /* checks */
+ /* .swag: Frantix (PSP), .str: Ben10 Galactic Racing, .vig: MX vs. ATV Untamed (PS2) .l/r: Crash Nitro Kart (PS2) */
+ if ( !check_extensions(streamFile,"vag,swag,str,vig,l,r") )
goto fail;
/* check VAG Header */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_vds_vdm.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_vds_vdm.c
index dd29f9c87..1b4006a45 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_vds_vdm.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_vds_vdm.c
@@ -1,43 +1,46 @@
#include "meta.h"
+#include "../coding/coding.h"
-/* VDS/VDM - from Grafitti Kingdom / Rakugaki Oukoku 2 */
+/* VDS/VDM - from Procyon Studio games [Grafitti Kingdom / Rakugaki Oukoku 2 (PS2), Tsukiyo ni Saraba (PS2)] */
VGMSTREAM * init_vgmstream_ps2_vds_vdm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
- /* check extension, case insensitive */
+
+ /* checks */
if ( !check_extensions(streamFile,"vds,vdm"))
goto fail;
-
if (read_32bitBE(0x00,streamFile) != 0x56445320 && /* "VDS " (music)*/
read_32bitBE(0x00,streamFile) != 0x56444D20) /* "VDM " (voices) */
goto fail;
loop_flag = read_8bit(0x20,streamFile);
channel_count = read_32bitLE(0x10,streamFile);
+ start_offset = 0x800;
- /* build the VGMSTREAM */
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- vgmstream->coding_type = coding_PSX;
- vgmstream->layout_type = channel_count > 1 ? layout_interleave : layout_none;
- vgmstream->meta_type = meta_PS2_VDS_VDM;
- start_offset = 0x800;
- vgmstream->num_samples = read_32bitLE(0x04,streamFile) * 28 / 16 / channel_count;
- /* 0x08: unknown, always 10 */
+ /* 0x08: unknown, always 0x10 */
vgmstream->sample_rate = read_32bitLE(0x0c,streamFile);
- vgmstream->channels = channel_count; /*0x10*/
- vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile);
- vgmstream->loop_start_sample = (read_32bitLE(0x18,streamFile) - start_offset) * 28 / 16 / channel_count;
- vgmstream->loop_end_sample = (read_32bitLE(0x1c,streamFile) - start_offset) * 28 / 16 / channel_count;
- vgmstream->loop_flag = loop_flag; /*0x20*/
- /*0x21: volume? */
- /*0x22: pan? */
- /*0x23: 02=VDS 04=VDM? */
- /* open the file for reading */
+ /* when looping (or maybe when stereo) data_size at 0x04 is actually smaller than file_size,
+ * sometimes cutting outros with loop disabled; doesn't affect looping though */
+ if (!loop_flag)
+ vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x04,streamFile), channel_count);
+ else
+ vgmstream->num_samples = ps_bytes_to_samples(get_streamfile_size(streamFile) - start_offset, channel_count);
+ vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(0x18,streamFile) - start_offset, channel_count);
+ vgmstream->loop_end_sample = ps_bytes_to_samples(read_32bitLE(0x1c,streamFile) - start_offset, channel_count);
+ /* 0x21: volume?, 0x22: pan?, 0x23: 02=VDS 04=VDM? 02/05=VDM in Tsukiyo ni Saraba? */
+
+ vgmstream->meta_type = meta_PS2_VDS_VDM;
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
+ vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile);
+
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_xa2_rrp.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_xa2_rrp.c
index 2eff2f3ad..64091d17a 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_xa2_rrp.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_xa2_rrp.c
@@ -15,7 +15,7 @@ VGMSTREAM * init_vgmstream_ps2_xa2_rrp(STREAMFILE *streamFile) {
if (strcasecmp("xa2",filename_extension(filename))) goto fail;
/* check header */
- if (read_32bitBE(0xC,streamFile) != 0x00000000)
+ if (read_32bitBE(0x50,streamFile) != 0x00000000)
goto fail;
loop_flag = 0;
@@ -32,6 +32,9 @@ VGMSTREAM * init_vgmstream_ps2_xa2_rrp(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count;
vgmstream->layout_type = layout_interleave;
+ if (channel_count > 2)
+ vgmstream->interleave_block_size = 0x400;
+ else
vgmstream->interleave_block_size = 0x1000;
vgmstream->meta_type = meta_PS2_XA2_RRP;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps3_msf.c b/Frameworks/vgmstream/vgmstream/src/meta/ps3_msf.c
index fc4e3cdba..d76850efc 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ps3_msf.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ps3_msf.c
@@ -1,6 +1,5 @@
#include "meta.h"
#include "../coding/coding.h"
-#include "../util.h"
/* MSF - Sony's PS3 SDK format (MultiStream File) */
VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
@@ -11,10 +10,12 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
int loop_flag = 0, channel_count;
- /* check extension, case insensitive (.at3: Silent Hill HD Collection, .mp3: Darkstalkers Resurrection) */
- if (!check_extensions(streamFile,"msf,at3,mp3")) goto fail;
+ /* checks */
+ /* .msf: standard, .at3: Silent Hill HD Collection, .mp3: Darkstalkers Resurrection */
+ if (!check_extensions(streamFile,"msf,at3,mp3"))
+ goto fail;
- /* "WMSF" variation with a mini header over the MSFC header, same extension */
+ /* "WMSF" variation with a mini header over the MSFC header [Dai-2-Ji Super Robot Generations (PS3)] */
if (read_32bitBE(0x00,streamFile) == 0x574D5346) {
header_offset = 0x10;
}
@@ -35,7 +36,7 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
/* byte flags, not in MSFv1 or v2
* 0x01/02/04/08: loop marker 0/1/2/3
* 0x10: resample options (force 44/48khz)
- * 0x20: VBR MP3
+ * 0x20: VBR MP3 source (changed into simplified 0x1a1 CBR)
* 0x40: joint stereo MP3 (apparently interleaved stereo for other formats)
* 0x80+: (none/reserved) */
flags = read_32bitBE(header_offset+0x14,streamFile);
@@ -57,7 +58,7 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- /* Sample rate hack for strange MSFv1 files that don't have a specified frequency */
+ /* sample rate hack for strange MSFv1 files that don't have it */
vgmstream->sample_rate = read_32bitBE(header_offset+0x10,streamFile);
if (vgmstream->sample_rate == 0x00000000) /* PS ADPCM only? */
vgmstream->sample_rate = 48000;
@@ -65,43 +66,43 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_PS3_MSF;
switch (codec_id) {
- case 0x0: /* PCM (Big Endian) */
- case 0x1: { /* PCM (Little Endian) */
+ case 0x00: /* PCM (Big Endian) */
+ case 0x01: { /* PCM (Little Endian) [Smash Cars (PS3)] */
vgmstream->coding_type = codec_id==0 ? coding_PCM16BE : coding_PCM16LE;
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
vgmstream->interleave_block_size = 2;
- vgmstream->num_samples = data_size/2/channel_count;
+ vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count,16);
if (loop_flag){
- vgmstream->loop_start_sample = loop_start/2/channel_count;
- vgmstream->loop_end_sample = loop_end/2/channel_count;
+ vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, channel_count,16);
+ vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_end, channel_count,16);
}
break;
}
- case 0x2: { /* PCM 32 (Float) */
- goto fail; //probably unused/spec only
+ case 0x02: { /* PCM 32 (Float) */
+ goto fail; /* probably unused/spec only */
}
- case 0x3: { /* PS ADPCM */
+ case 0x03: { /* PS ADPCM [Smash Cars (PS3)] */
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
vgmstream->interleave_block_size = 0x10;
- vgmstream->num_samples = data_size*28/16/channel_count;
+ vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
if (loop_flag) {
- vgmstream->loop_start_sample = loop_start*28/16/channel_count;
- vgmstream->loop_end_sample = loop_end*28/16/channel_count;
+ vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start,channel_count);
+ vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end,channel_count);
}
break;
}
#ifdef VGM_USE_FFMPEG
- case 0x4: /* ATRAC3 low (66 kbps, frame size 96, Joint Stereo) */
- case 0x5: /* ATRAC3 mid (105 kbps, frame size 152) */
- case 0x6: { /* ATRAC3 high (132 kbps, frame size 192) */
+ case 0x04: /* ATRAC3 low (66 kbps, frame size 96, Joint Stereo) [Silent Hill HD (PS3)] */
+ case 0x05: /* ATRAC3 mid (105 kbps, frame size 152) [Atelier Rorona (PS3)] */
+ case 0x06: { /* ATRAC3 high (132 kbps, frame size 192) [Tekken Tag Tournament HD (PS3)] */
ffmpeg_codec_data *ffmpeg_data = NULL;
uint8_t buf[100];
int32_t bytes, block_size, encoder_delay, joint_stereo;
@@ -141,67 +142,55 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
break;
}
#endif
-#ifdef VGM_USE_FFMPEG
- case 0x7: { /* MPEG (LAME MP3 of any quality) */
- /* delegate to FFMpeg, it can parse MSF files */
- ffmpeg_codec_data *ffmpeg_data = init_ffmpeg_offset(streamFile, header_offset, streamFile->get_size(streamFile) );
+#if defined(VGM_USE_FFMPEG) && !defined(VGM_USE_MPEG)
+ case 0x07: { /* MPEG (CBR LAME MP3) [Dengeki Bunko Fighting Climax (PS3)] */
+ ffmpeg_codec_data *ffmpeg_data = NULL;
+
+ ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, streamFile->get_size(streamFile) );
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
- /* vgmstream->num_samples = ffmpeg_data->totalSamples; */ /* duration may not be set/inaccurate */
vgmstream->num_samples = (int64_t)data_size * ffmpeg_data->sampleRate * 8 / ffmpeg_data->bitrate;
if (loop_flag) {
- //todo properly apply encoder delay, which seems to vary between 1152 (1f), 528, 576 or 528+576
- int frame_size = ffmpeg_data->frameSize;
vgmstream->loop_start_sample = (int64_t)loop_start * ffmpeg_data->sampleRate * 8 / ffmpeg_data->bitrate;
- vgmstream->loop_start_sample -= vgmstream->loop_start_sample==frame_size ? frame_size
- : vgmstream->loop_start_sample % frame_size;
vgmstream->loop_end_sample = (int64_t)loop_end * ffmpeg_data->sampleRate * 8 / ffmpeg_data->bitrate;
- vgmstream->loop_end_sample -= vgmstream->loop_end_sample==frame_size ? frame_size
- : vgmstream->loop_end_sample % frame_size;
+ /* loops are always CBR frame beginnings */
}
+ /* encoder delay varies between 1152 (1f), 528, 576, etc; probably not actually skipped */
break;
}
#endif
-#if defined(VGM_USE_MPEG) && !defined(VGM_USE_FFMPEG)
- case 0x7: { /* MPEG (LAME MP3 of any quality) */
- int frame_size = 576; /* todo incorrect looping calcs */
-
+#ifdef VGM_USE_MPEG
+ case 0x07: { /* MPEG (CBR LAME MP3) []Dengeki Bunko Fighting Climax (PS3) */
mpeg_codec_data *mpeg_data = NULL;
- coding_t ct;
- mpeg_data = init_mpeg(streamFile, start_offset, &ct, vgmstream->channels);
+ mpeg_data = init_mpeg(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels);
if (!mpeg_data) goto fail;
vgmstream->codec_data = mpeg_data;
-
- vgmstream->coding_type = ct;
vgmstream->layout_type = layout_none;
+
vgmstream->num_samples = mpeg_bytes_to_samples(data_size, mpeg_data);
- vgmstream->num_samples -= vgmstream->num_samples % frame_size;
if (loop_flag) {
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data);
- vgmstream->loop_start_sample -= vgmstream->loop_start_sample % frame_size;
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data);
- vgmstream->loop_end_sample -= vgmstream->loop_end_sample % frame_size;
+ /* loops are always CBR frame beginnings */
}
- vgmstream->interleave_block_size = 0;
+ /* encoder delay varies between 1152 (1f), 528, 576, etc; probably not actually skipped */
break;
}
#endif
- default: /* 8+: not defined */
+ default: /* 0x08+: not defined */
goto fail;
}
- /* open the file for reading */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
-
return vgmstream;
fail:
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/psx_cdxa.c b/Frameworks/vgmstream/vgmstream/src/meta/psx_cdxa.c
index 1dd04d61d..efdb52f6e 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/psx_cdxa.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/psx_cdxa.c
@@ -105,7 +105,7 @@ VGMSTREAM * init_vgmstream_cdxa(STREAMFILE *streamFile) {
vgmstream->xa_channel = xa_channel;
vgmstream->coding_type = coding_XA;
- vgmstream->layout_type = layout_xa_blocked;
+ vgmstream->layout_type = layout_blocked_xa;
vgmstream->meta_type = meta_PSX_XA;
if (is_blocked)
@@ -115,7 +115,7 @@ VGMSTREAM * init_vgmstream_cdxa(STREAMFILE *streamFile) {
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
- xa_block_update(start_offset,vgmstream);
+ block_update_xa(start_offset,vgmstream);
return vgmstream;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/riff.c b/Frameworks/vgmstream/vgmstream/src/meta/riff.c
index 04d0cc14a..c6a5953b2 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/riff.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/riff.c
@@ -90,7 +90,7 @@ typedef struct {
int interleave;
} riff_fmt_chunk;
-static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk, riff_fmt_chunk * fmt, int sns, int mwv) {
+static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk, riff_fmt_chunk * fmt, int mwv) {
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE;
@@ -106,15 +106,22 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
fmt->codec = (uint16_t)read_16bit(current_chunk+0x8,streamFile);
switch (fmt->codec) {
+ case 0x00: /* Yamaha ADPCM (raw) [Headhunter (DC), Bomber hehhe (DC)] (unofficial) */
+ if (fmt->bps != 4) goto fail;
+ if (fmt->block_size != 0x02*fmt->channel_count) goto fail;
+ fmt->coding_type = coding_AICA_int;
+ fmt->interleave = 0x01;
+ break;
+
case 0x01: /* PCM */
switch (fmt->bps) {
case 16:
fmt->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
- fmt->interleave = 2;
+ fmt->interleave = 0x02;
break;
case 8:
fmt->coding_type = coding_PCM8_U_int;
- fmt->interleave = 1;
+ fmt->interleave = 0x01;
break;
default:
goto fail;
@@ -131,12 +138,17 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
fmt->coding_type = coding_MS_IMA;
break;
- case 0x69: /* XBOX IMA ADPCM [Rayman Raving Rabbids 2 (PC) --maybe waa/wac/wam/wad?] */
+ case 0x20: /* Yamaha ADPCM (raw) [Takuyo/Dynamix/etc DC games] */
+ if (fmt->bps != 4) goto fail;
+ fmt->coding_type = coding_AICA;
+ break;
+
+ case 0x69: /* XBOX IMA ADPCM [Dynasty Warriors 5 (Xbox)] */
if (fmt->bps != 4) goto fail;
fmt->coding_type = coding_XBOX_IMA;
break;
- case 0x007A: /* MS IMA ADPCM [LA Rush (PC), Psi Ops (PC)] */
+ case 0x007A: /* MS IMA ADPCM [LA Rush (PC), Psi Ops (PC)] (unofficial) */
/* 0x007A is apparently "Voxware SC3" but in .MED it's just MS-IMA (0x11) */
if (!check_extensions(streamFile,"med"))
goto fail;
@@ -149,21 +161,15 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
goto fail;
break;
- case 0x0555: /* Level-5 0x555 ADPCM */
+ case 0x0555: /* Level-5 0x555 ADPCM (unofficial) */
if (!mwv) goto fail;
fmt->coding_type = coding_L5_555;
fmt->interleave = 0x12;
break;
- case 0x5050: /* Ubisoft LyN engine's DSP */
- if (!sns) goto fail;
- fmt->coding_type = coding_NGC_DSP;
- fmt->interleave = 0x08;
- break;
-
#ifdef VGM_USE_VORBIS
case 0x6771: /* Ogg Vorbis (mode 3+) */
- fmt->coding_type = coding_ogg_vorbis;
+ fmt->coding_type = coding_OGG_VORBIS;
break;
#else
goto fail;
@@ -192,6 +198,7 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
fmt->block_size = (bztmp & 0x3FF) * 8 + 8; //should match fmt->block_size
#elif defined(VGM_USE_FFMPEG)
fmt->coding_type = coding_FFmpeg;
+ break;
#else
goto fail;
#endif
@@ -204,12 +211,13 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
read_32bitBE(current_chunk+0x2c,streamFile) == 0x4F8C836C) {
#ifdef VGM_USE_ATRAC9
fmt->coding_type = coding_ATRAC9;
+ break;
#else
goto fail;
#endif
}
- break;
+ goto fail; /* unknown GUID */
default:
goto fail;
@@ -232,32 +240,30 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
int fact_sample_skip = 0;
int loop_flag = 0;
- long loop_start_ms = -1;
- long loop_end_ms = -1;
- off_t loop_start_offset = -1;
- off_t loop_end_offset = -1;
+ long loop_start_ms = -1, loop_end_ms = -1;
+ int32_t loop_start_wsmp = -1, loop_end_wsmp = -1;
+ int32_t loop_start_smpl = -1, loop_end_smpl = -1;
int FormatChunkFound = 0, DataChunkFound = 0, JunkFound = 0;
int mwv = 0; /* Level-5 .mwv (Dragon Quest VIII, Rogue Galaxy) */
off_t mwv_pflt_offset = -1;
off_t mwv_ctrl_offset = -1;
- int sns = 0; /* Ubisoft .sns LyN engine (Red Steel 2, Just Dance 3) */
int at3 = 0; /* Sony ATRAC3 / ATRAC3plus */
int at9 = 0; /* Sony ATRAC9 */
/* check extension */
- /* .da: The Great Battle VI (PS), .cd: Exector (PS), .med: Psi Ops (PC), .snd: Layton Brothers (iOS/Android) */
- if ( check_extensions(streamFile, "wav,lwav,da,cd,med,snd") ) {
+ /* .lwav: to avoid hijacking .wav, .xwav: fake for Xbox games (unneded anymore) */
+ /* .da: The Great Battle VI (PS), .cd: Exector (PS), .med: Psi Ops (PC), .snd: Layton Brothers (iOS/Android),
+ * .adx: Remember11 (PC) sfx
+ * .adp: Headhunter (DC) */
+ if ( check_extensions(streamFile, "wav,lwav,xwav,da,cd,med,snd,adx,adp") ) {
;
}
else if ( check_extensions(streamFile, "mwv") ) {
mwv = 1;
}
- else if ( check_extensions(streamFile, "sns") ) {
- sns = 1;
- }
/* .rws: Climax games (Silent Hill Origins PSP, Oblivion PSP), .aud: EA Replay */
else if ( check_extensions(streamFile, "at3,rws,aud") ) {
at3 = 1;
@@ -282,6 +288,14 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
if (riff_size+0x08+0x01 == file_size)
riff_size += 0x01;
+ /* some Xbox games do this [Dynasty Warriors 3 (Xbox), BloodRayne (Xbox)] */
+ if (riff_size == file_size && read_16bitLE(0x14,streamFile)==0x0069)
+ riff_size -= 0x08;
+ /* some Dreamcast/Naomi games do this [Headhunter (DC), Bomber hehhe (DC)] */
+ if (riff_size + 0x04 == file_size && read_16bitLE(0x14,streamFile)==0x0000)
+ riff_size -= 0x04;
+
+
/* check for truncated RIFF */
if (file_size < riff_size+0x08) goto fail;
@@ -296,35 +310,37 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
if (fmt.codec == 0x6771 && chunk_type == 0x64617461) /* Liar-soft again */
chunk_size += (chunk_size%2) ? 0x01 : 0x00;
- if (current_chunk+8+chunk_size > file_size) goto fail;
+ if (current_chunk+0x08+chunk_size > file_size) goto fail;
switch(chunk_type) {
case 0x666d7420: /* "fmt " */
- /* only one per file */
- if (FormatChunkFound) goto fail;
+ if (FormatChunkFound) goto fail; /* only one per file */
FormatChunkFound = 1;
if (-1 == read_fmt(0, /* big endian == false*/
streamFile,
current_chunk,
&fmt,
- sns,
mwv))
goto fail;
+ /* some Dreamcast/Naomi games again [Headhunter (DC), Bomber hehhe (DC)] */
+ if (fmt.codec == 0x0000 && chunk_size == 0x12)
+ chunk_size += 0x02;
break;
- case 0x64617461: /* data */
- /* at most one per file */
- if (DataChunkFound) goto fail;
+
+ case 0x64617461: /* "data" */
+ if (DataChunkFound) goto fail; /* only one per file */
DataChunkFound = 1;
- start_offset = current_chunk + 8;
+ start_offset = current_chunk + 0x08;
data_size = chunk_size;
break;
- case 0x4C495354: /* LIST */
+
+ case 0x4C495354: /* "LIST" */
/* what lurks within?? */
- switch (read_32bitBE(current_chunk + 8, streamFile)) {
- case 0x6164746C: /* adtl */
+ switch (read_32bitBE(current_chunk+0x08, streamFile)) {
+ case 0x6164746C: /* "adtl" */
/* yay, atdl is its own little world */
parse_adtl(current_chunk + 8, chunk_size,
streamFile,
@@ -334,32 +350,44 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
break;
}
break;
- case 0x736D706C: /* smpl */
- /* check loop count and loop info */
- if (read_32bitLE(current_chunk+0x24, streamFile)==1) {
- if (read_32bitLE(current_chunk+0x2c+4, streamFile)==0) {
+
+ case 0x736D706C: /* "smpl" (RIFFMIDISample + MIDILoop chunk) */
+ /* check loop count/loop info (most common) *///todo double check values
+ /* 0x00: manufacturer id, 0x04: product id, 0x08: sample period, 0x0c: unity node,
+ * 0x10: pitch fraction, 0x14: SMPTE format, 0x18: SMPTE offset, 0x1c: loop count, 0x20: sampler data */
+ if (read_32bitLE(current_chunk+0x08+0x1c, streamFile)==1) {
+ /* 0x24: cue point id, 0x28: type (0=forward, 1=alternating, 2=backward)
+ * 0x2c: start, 0x30: end, 0x34: fraction, 0x38: play count */
+ if (read_32bitLE(current_chunk+0x08+0x28, streamFile)==0) {
loop_flag = 1;
- loop_start_offset = read_32bitLE(current_chunk+0x2c+8, streamFile);
- loop_end_offset = read_32bitLE(current_chunk+0x2c+0xc,streamFile);
+ loop_start_smpl = read_32bitLE(current_chunk+0x08+0x2c, streamFile);
+ loop_end_smpl = read_32bitLE(current_chunk+0x08+0x30, streamFile);
}
}
break;
- case 0x70666c74: /* pflt */
- if (!mwv) break; /* ignore if not in an mwv */
- mwv_pflt_offset = current_chunk; /* predictor filters */
+ case 0x77736D70: /* "wsmp" (RIFFDLSSample + DLSLoop chunk) */
+ /* check loop count/info (found in some Xbox games: Halo (non-looping), Dynasty Warriors 3, Crimson Sea) */
+ /* 0x00: size, 0x04: unity note, 0x06: fine tune, 0x08: gain, 0x10: loop count */
+ if (chunk_size >= 0x24
+ && read_32bitLE(current_chunk+0x08+0x00, streamFile) == 0x14
+ && read_32bitLE(current_chunk+0x08+0x10, streamFile) > 0
+ && read_32bitLE(current_chunk+0x08+0x14, streamFile) == 0x10) {
+ /* 0x14: size, 0x18: loop type (0=forward, 1=release), 0x1c: loop start, 0x20: loop length */
+ if (read_32bitLE(current_chunk+0x08+0x18, streamFile)==0) {
+ loop_flag = 1;
+ loop_start_wsmp = read_32bitLE(current_chunk+0x08+0x1c, streamFile);
+ loop_end_wsmp = read_32bitLE(current_chunk+0x08+0x20, streamFile);
+ loop_end_wsmp += loop_start_wsmp;
+ }
+ }
break;
- case 0x6374726c: /* ctrl */
- if (!mwv) break;
- loop_flag = read_32bitLE(current_chunk+0x08, streamFile);
- mwv_ctrl_offset = current_chunk;
- break;
- case 0x66616374: /* fact */
+ case 0x66616374: /* "fact" */
if (chunk_size == 0x04) { /* standard, usually found with ADPCM */
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
- } else if (sns && chunk_size == 0x10) {
- fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
+ } else if (chunk_size == 0x10 && read_32bitBE(current_chunk+0x08+0x04, streamFile) == 0x4C794E20) { /* "LyN " */
+ goto fail; /* parsed elsewhere */
} else if ((at3 || at9) && chunk_size == 0x08) {
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
fact_sample_skip = read_32bitLE(current_chunk+0x0c, streamFile);
@@ -367,11 +395,22 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
fact_sample_skip = read_32bitLE(current_chunk+0x10, streamFile);
}
-
break;
- case 0x4A554E4B: /* JUNK */
+
+ case 0x70666c74: /* "pflt" (.mwv extension) */
+ if (!mwv) break; /* ignore if not in an mwv */
+ mwv_pflt_offset = current_chunk; /* predictor filters */
+ break;
+ case 0x6374726c: /* "ctrl" (.mwv extension) */
+ if (!mwv) break;
+ loop_flag = read_32bitLE(current_chunk+0x08, streamFile);
+ mwv_ctrl_offset = current_chunk;
+ break;
+
+ case 0x4A554E4B: /* "JUNK" */
JunkFound = 1;
break;
+
default:
/* ignorance is bliss */
break;
@@ -383,7 +422,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
if (!FormatChunkFound || !DataChunkFound) goto fail;
- //todo improve detection using fmt sizes/values as Wwise's don't match the RIFF standard
+ //todo improve detection using fmt sizes/values as Wwise's don't match the RIFF standard
/* JUNK is an optional Wwise chunk, and Wwise hijacks the MSADPCM/MS_IMA/XBOX IMA ids (how nice).
* To ensure their stuff is parsed in wwise.c we reject their JUNK, which they put almost always.
* As JUNK is legal (if unusual) we only reject those codecs.
@@ -393,10 +432,18 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
&& (fmt.coding_type==coding_MSADPCM /*|| fmt.coding_type==coding_MS_IMA*/ || fmt.coding_type==coding_XBOX_IMA))
goto fail;
+ /* ignore Beyond Good & Evil HD PS3 evil reuse of PCM codec */
+ if (fmt.coding_type == coding_PCM16LE &&
+ read_32bitBE(start_offset+0x00, streamFile) == 0x4D534643 && /* "MSF\43" */
+ read_32bitBE(start_offset+0x34, streamFile) == 0xFFFFFFFF && /* always */
+ read_32bitBE(start_offset+0x38, streamFile) == 0xFFFFFFFF &&
+ read_32bitBE(start_offset+0x3c, streamFile) == 0xFFFFFFFF)
+ goto fail;
+
#ifdef VGM_USE_VORBIS
/* special case using init_vgmstream_ogg_vorbis */
- if (fmt.coding_type == coding_ogg_vorbis) {
+ if (fmt.coding_type == coding_OGG_VORBIS) {
return parse_riff_ogg(streamFile, start_offset, data_size);
}
#endif
@@ -445,41 +492,26 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
break;
case coding_MSADPCM:
- vgmstream->num_samples = fact_sample_count ? fact_sample_count :
- msadpcm_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count);
+ vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count);
+ if (fact_sample_count && fact_sample_count < vgmstream->num_samples)
+ vgmstream->num_samples = fact_sample_count;
break;
case coding_MS_IMA:
- vgmstream->num_samples = fact_sample_count ? fact_sample_count :
- ms_ima_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count);
+ vgmstream->num_samples = ms_ima_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count);
+ if (fact_sample_count && fact_sample_count < vgmstream->num_samples)
+ vgmstream->num_samples = fact_sample_count;
+ break;
+
+ case coding_AICA:
+ case coding_AICA_int:
+ vgmstream->num_samples = aica_bytes_to_samples(data_size, fmt.channel_count);
break;
case coding_XBOX_IMA:
- vgmstream->num_samples = fact_sample_count ? fact_sample_count :
- xbox_ima_bytes_to_samples(data_size, fmt.channel_count);
- break;
-
- case coding_NGC_DSP:
- if (!sns) goto fail;
- if (fact_sample_count <= 0) goto fail;
- vgmstream->num_samples = fact_sample_count;
- //vgmstream->num_samples = dsp_bytes_to_samples(data_size, fmt.channel_count);
-
- /* coefs */
- {
- int i, ch;
- static const int16_t coef[16] = { /* common codebook? */
- 0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1,
- 0x084d,0xfaa4,0x0982,0xfdf7,0x0af6,0xfafa,0x0be6,0xfbf5
- };
-
- for (ch = 0; ch < fmt.channel_count; ch++) {
- for (i = 0; i < 16; i++) {
- vgmstream->ch[ch].adpcm_coef[i] = coef[i];
- }
- }
- }
-
+ vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, fmt.channel_count);
+ if (fact_sample_count && fact_sample_count < vgmstream->num_samples)
+ vgmstream->num_samples = fact_sample_count; /* some (converted?) Xbox games have bigger fact_samples */
break;
#ifdef VGM_USE_FFMPEG
@@ -499,8 +531,8 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
/* RIFF loop/sample values are absolute (with skip samples), adjust */
if (loop_flag) {
- loop_start_offset -= ffmpeg_data->skipSamples;
- loop_end_offset -= ffmpeg_data->skipSamples;
+ loop_start_smpl -= (int32_t)ffmpeg_data->skipSamples;
+ loop_end_smpl -= (int32_t)ffmpeg_data->skipSamples;
}
}
break;
@@ -531,8 +563,8 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
vgmstream->num_samples = fact_sample_count;
/* RIFF loop/sample values are absolute (with skip samples), adjust */
if (loop_flag) {
- loop_start_offset -= fact_sample_skip;
- loop_end_offset -= fact_sample_skip;
+ loop_start_smpl -= fact_sample_skip;
+ loop_end_smpl -= fact_sample_skip;
}
break;
@@ -547,6 +579,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
switch (fmt.coding_type) {
case coding_MSADPCM:
case coding_MS_IMA:
+ case coding_AICA:
case coding_XBOX_IMA:
#ifdef VGM_USE_FFMPEG
case coding_FFmpeg:
@@ -574,11 +607,16 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
vgmstream->loop_end_sample = (long long)loop_end_ms*fmt.sample_rate/1000;
vgmstream->meta_type = meta_RIFF_WAVE_labl;
}
- else if (loop_start_offset >= 0) {
- vgmstream->loop_start_sample = loop_start_offset;
- vgmstream->loop_end_sample = loop_end_offset;
+ else if (loop_start_smpl >= 0) {
+ vgmstream->loop_start_sample = loop_start_smpl;
+ vgmstream->loop_end_sample = loop_end_smpl;
vgmstream->meta_type = meta_RIFF_WAVE_smpl;
}
+ else if (loop_start_wsmp >= 0) {
+ vgmstream->loop_start_sample = loop_start_wsmp;
+ vgmstream->loop_end_sample = loop_end_wsmp;
+ vgmstream->meta_type = meta_RIFF_WAVE_wsmp;
+ }
else if (mwv && mwv_ctrl_offset != -1) {
vgmstream->loop_start_sample = read_32bitLE(mwv_ctrl_offset+12, streamFile);
vgmstream->loop_end_sample = vgmstream->num_samples;
@@ -587,9 +625,6 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
if (mwv) {
vgmstream->meta_type = meta_RIFF_WAVE_MWV;
}
- if (sns) {
- vgmstream->meta_type = meta_RIFF_WAVE_SNS;
- }
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
@@ -652,7 +687,6 @@ VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
streamFile,
current_chunk,
&fmt,
- 0, /* sns == false */
0)) /* mwv == false */
goto fail;
@@ -803,24 +837,21 @@ static VGMSTREAM *parse_riff_ogg(STREAMFILE * streamFile, off_t start_offset, si
{
VGMSTREAM *vgmstream = NULL;
STREAMFILE *custom_streamFile = NULL;
- char filename[PATH_LIMIT];
- vgm_vorbis_info_t inf = {0};
+ ogg_vorbis_meta_info_t ovmi = {0};
riff_ogg_io_data io_data = {0};
size_t io_data_size = sizeof(riff_ogg_io_data);
- inf.layout_type = layout_ogg_vorbis;
- inf.meta_type = meta_RIFF_WAVE;
- inf.stream_size = real_size;
+ ovmi.meta_type = meta_RIFF_WAVE;
+ ovmi.stream_size = real_size;
//inf.loop_flag = 0; /* not observed */
io_data.patch_offset = patch_offset;
- custom_streamFile = open_io_streamfile(open_wrap_streamfile(streamFile), &io_data,io_data_size, riff_ogg_io_read);
+ custom_streamFile = open_io_streamfile(open_wrap_streamfile(streamFile), &io_data,io_data_size, riff_ogg_io_read,NULL);
if (!custom_streamFile) return NULL;
- streamFile->get_name(streamFile,filename,sizeof(filename));
- vgmstream = init_vgmstream_ogg_vorbis_callbacks(custom_streamFile, filename, NULL, start_offset, &inf);
+ vgmstream = init_vgmstream_ogg_vorbis_callbacks(custom_streamFile, NULL, start_offset, &ovmi);
close_streamfile(custom_streamFile);
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/rkv.c b/Frameworks/vgmstream/vgmstream/src/meta/rkv.c
index 56f7efb3d..a880c58db 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/rkv.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/rkv.c
@@ -1,77 +1,115 @@
#include "meta.h"
-#include "../util.h"
+#include "../coding/coding.h"
-/* RKV (from Legacy of Kain - Blood Omen 2) */
+/* RKV - from Legacy of Kain - Blood Omen 2 (PS2) */
VGMSTREAM * init_vgmstream_ps2_rkv(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- off_t start_offset=0;
- int loop_flag;
- int channel_count;
+ off_t start_offset, header_offset;
+ size_t data_size;
+ int loop_flag, channel_count;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("rkv",filename_extension(filename))) goto fail;
- // Some RKV got info @ offset 0
- // Some other @ offset 4
- if(read_32bitLE(0,streamFile)==0)
- start_offset=4;
+ /* checks */
+ if (!check_extensions(streamFile, "rkv"))
+ goto fail;
+ if (read_32bitBE(0x24,streamFile) != 0x00) /* quick test vs GC rkv (coef position) */
+ goto fail;
- loop_flag = (read_32bitLE(start_offset+4,streamFile)!=0xFFFFFFFF);
- channel_count = read_32bitLE(start_offset+0x0c,streamFile)+1;
-
- /* build the VGMSTREAM */
+ /* some RKV got info at offset 0x00, some other at 0x0 4 */
+ if (read_32bitLE(0x00,streamFile)==0)
+ header_offset = 0x04;
+ else
+ header_offset = 0x00;
+
+ switch (read_32bitLE(header_offset+0x0c,streamFile)) {
+ case 0x00: channel_count = 1; break;
+ case 0x01: channel_count = 2; break;
+ default: goto fail;
+ }
+ loop_flag = (read_32bitLE(header_offset+0x04,streamFile) != 0xFFFFFFFF);
+ start_offset = 0x800;
+ data_size = get_streamfile_size(streamFile) - start_offset;
+
+
+ /* 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_32bitLE(start_offset,streamFile);
+ vgmstream->sample_rate = read_32bitLE(header_offset,streamFile);
+ vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
+ //vgmstream->num_samples = read_32bitLE(header_offset+0x08,streamFile); /* sometimes not set */
+ if (loop_flag) {
+ vgmstream->loop_start_sample = read_32bitLE(header_offset+0x04,streamFile);
+ vgmstream->loop_end_sample = read_32bitLE(header_offset+0x08,streamFile);
+ }
+
+ vgmstream->meta_type = meta_PS2_RKV;
vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x400;
+ if (vgmstream->interleave_block_size)
+ vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
- // sometimes sample count is not set on the header
- vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)/16*28/channel_count;
-
- if (loop_flag) {
- vgmstream->loop_start_sample = read_32bitLE(start_offset+4,streamFile);
- vgmstream->loop_end_sample = read_32bitLE(start_offset+8,streamFile);
- }
-
- start_offset = 0x800;
-
- if((get_streamfile_size(streamFile)-0x800)%0x400)
- {
- vgmstream->layout_type = layout_interleave_shortblock;
- vgmstream->interleave_smallblock_size=((get_streamfile_size(streamFile)-0x800)%0x400)/channel_count;
- } else {
- vgmstream->layout_type = layout_interleave;
- }
-
- vgmstream->interleave_block_size = 0x400;
- vgmstream->meta_type = meta_PS2_RKV;
- /* open the file for reading */
- {
- int i;
- STREAMFILE * file;
- file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!file) goto fail;
- for (i=0;ich[i].streamfile = file;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=start_offset+
- vgmstream->interleave_block_size*i;
-
- }
- }
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
+/* RKV - from Legacy of Kain - Blood Omen 2 (GC) */
+VGMSTREAM * init_vgmstream_ngc_rkv(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ int loop_flag, channel_count;
+
+ /* checks */
+ /* "": empty (files have names but no extensions), .rkv: container bigfile extension, .bo2: fake extension */
+ if (!check_extensions(streamFile, ",rkv,bo2"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x00)
+ goto fail;
+ if (read_32bitBE(0x24,streamFile) == 0x00) /* quick test vs GC rkv (coef position) */
+ goto fail;
+
+ switch (read_32bitBE(0x10,streamFile)) {
+ case 0x00: channel_count = 1; break;
+ case 0x01: channel_count = 2; break;
+ default: goto fail;
+ }
+ loop_flag = (read_32bitBE(0x08,streamFile) != 0xFFFFFFFF);
+ start_offset = 0x800;
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = read_32bitBE(0x04,streamFile);
+ vgmstream->num_samples = read_32bitBE(0x0C,streamFile);
+ if (loop_flag) {
+ vgmstream->loop_start_sample = read_32bitBE(0x08,streamFile);
+ vgmstream->loop_end_sample = read_32bitBE(0x0C,streamFile);
+ }
+
+ vgmstream->meta_type = meta_NGC_RKV;
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x400;
+
+ dsp_read_coefs_be(vgmstream,streamFile,0x24,0x2e);
+ /* hist at 0x44/0x72? */
+
+
+ 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/rs03.c b/Frameworks/vgmstream/vgmstream/src/meta/rs03.c
index 03307961e..6244e2eaa 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/rs03.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/rs03.c
@@ -1,81 +1,54 @@
#include "meta.h"
#include "../coding/coding.h"
-#include "../util.h"
-
-/* .dsp w/ RS03 header - from Metroid Prime 2 */
+/* RS03 - from Metroid Prime 2 (GC) */
VGMSTREAM * init_vgmstream_rs03(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
-
- int channel_count;
- int loop_flag;
off_t start_offset;
- int i;
+ size_t data_size;
+ int channel_count, loop_flag;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("dsp",filename_extension(filename))) goto fail;
- /* check header */
- if ((uint32_t)read_32bitBE(0,streamFile)!=0x52530003) /* "RS03" */
+ /* checks */
+ if (!check_extensions(streamFile, "dsp"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x52530003) /* "RS03" */
goto fail;
- channel_count = read_32bitBE(4,streamFile);
+ channel_count = read_32bitBE(0x04,streamFile);
if (channel_count != 1 && channel_count != 2) goto fail;
-
- /* build the VGMSTREAM */
-
loop_flag = read_16bitBE(0x14,streamFile);
+ start_offset = 0x60;
+ data_size = (get_streamfile_size(streamFile) - start_offset);
+
+
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- /* fill in the vital statistics */
- vgmstream->num_samples = read_32bitBE(8,streamFile);
vgmstream->sample_rate = read_32bitBE(0xc,streamFile);
-
+ vgmstream->num_samples = read_32bitBE(8,streamFile);
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitBE(0x18,streamFile)/8*14;
vgmstream->loop_end_sample = read_32bitBE(0x1c,streamFile)/8*14;
}
- start_offset = 0x60;
-
- vgmstream->coding_type = coding_NGC_DSP;
- if (channel_count == 2) {
- vgmstream->layout_type = layout_interleave_shortblock;
- vgmstream->interleave_block_size = 0x8f00;
- vgmstream->interleave_smallblock_size = (((get_streamfile_size(streamFile)-start_offset)%(0x8f00*2))/2+7)/8*8;
- } else
- vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_DSP_RS03;
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x8f00;
+ if (vgmstream->interleave_block_size)
+ vgmstream->interleave_last_block_size = ((data_size % (vgmstream->interleave_block_size*vgmstream->channels))/2+7)/8*8;
- for (i=0;i<16;i++)
- vgmstream->ch[0].adpcm_coef[i]=read_16bitBE(0x20+i*2,streamFile);
- if (channel_count==2) {
- for (i=0;i<16;i++)
- vgmstream->ch[1].adpcm_coef[i]=read_16bitBE(0x40+i*2,streamFile);
- }
+ dsp_read_coefs_be(vgmstream,streamFile,0x20,0x20);
- /* open the file for reading by each channel */
- {
- int i;
- for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,0x8f00);
-
- if (!vgmstream->ch[i].streamfile) goto fail;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=
- start_offset+0x8f00*i;
- }
- }
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
return vgmstream;
- /* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/rsd.c b/Frameworks/vgmstream/vgmstream/src/meta/rsd.c
index ca1beed1c..c4af75e60 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/rsd.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/rsd.c
@@ -903,12 +903,11 @@ fail:
/* RSD6OGG */
VGMSTREAM * init_vgmstream_rsd6oogv(STREAMFILE *streamFile) {
#ifdef VGM_USE_VORBIS
- char filename[PATH_LIMIT];
off_t start_offset;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("rsd",filename_extension(filename))) goto fail;
+ /* check extension */
+ if (!check_extensions(streamFile, "rsd"))
+ goto fail;
/* check header */
if (read_32bitBE(0x0,streamFile) != 0x52534436) /* RSD6 */
@@ -917,15 +916,13 @@ VGMSTREAM * init_vgmstream_rsd6oogv(STREAMFILE *streamFile) {
goto fail;
{
- vgm_vorbis_info_t inf;
+ ogg_vorbis_meta_info_t ovmi = {0};
VGMSTREAM * result = NULL;
- memset(&inf, 0, sizeof(inf));
- inf.layout_type = layout_ogg_vorbis;
- inf.meta_type = meta_RSD6OOGV;
+ ovmi.meta_type = meta_RSD6OOGV;
start_offset = 0x800;
- result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf);
+ result = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
if (result != NULL) {
return result;
@@ -938,7 +935,7 @@ fail:
return NULL;
}
-/* RSD6XADP - from Crash Tag Team Racing (Xbox) */
+/* RSD6XADP - from Crash Tag Team Racing (Xbox), Scarface (Xbox) */
VGMSTREAM * init_vgmstream_rsd6xadp(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
@@ -966,9 +963,10 @@ VGMSTREAM * init_vgmstream_rsd6xadp(STREAMFILE *streamFile) {
vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, vgmstream->channels);
- vgmstream->coding_type = coding_XBOX_IMA;
- vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_RSD6XADP;
+ vgmstream->coding_type = (channel_count > 2) ? coding_XBOX_IMA_mch : coding_XBOX_IMA;
+ vgmstream->layout_type = layout_none;
+
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
goto fail;
@@ -1081,3 +1079,131 @@ fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
+
+/* RSD6AT3+ [Crash of the Titans (PSP)] */
+VGMSTREAM * init_vgmstream_rsd6at3p(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ size_t data_size;
+ int loop_flag, channel_count;
+
+
+ /* check extension, case insensitive */
+ if (!check_extensions(streamFile,"rsd"))
+ goto fail;
+
+ /* check header */
+ if (read_32bitBE(0x00,streamFile) != 0x52534436) /* "RSD6" */
+ goto fail;
+ if (read_32bitBE(0x04,streamFile) != 0x4154332B) /* "AT3+" */
+ goto fail;
+
+ loop_flag = 0;
+ channel_count = read_32bitLE(0x08, streamFile);
+ start_offset = 0x800;
+ data_size = get_streamfile_size(streamFile) - start_offset;
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->meta_type = meta_RSD6AT3P;
+ vgmstream->sample_rate = read_32bitLE(0x10, streamFile);
+
+#ifdef VGM_USE_FFMPEG
+ {
+ ffmpeg_codec_data *ffmpeg_data = NULL;
+
+ /* full RIFF header at start_offset */
+ ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,data_size);
+ if (!ffmpeg_data) goto fail;
+ vgmstream->codec_data = ffmpeg_data;
+ vgmstream->coding_type = coding_FFmpeg;
+ vgmstream->layout_type = layout_none;
+
+ if (channel_count != ffmpeg_data->channels) goto fail;
+
+ vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact samples */
+
+ /* manually read skip_samples if FFmpeg didn't do it */
+ if (ffmpeg_data->skipSamples <= 0) {
+ off_t chunk_offset;
+ size_t chunk_size, fact_skip_samples = 0;
+ if (!find_chunk_le(streamFile, 0x66616374,start_offset+0xc,0, &chunk_offset,&chunk_size)) /* find "fact" */
+ goto fail;
+ if (chunk_size == 0x08) {
+ fact_skip_samples = read_32bitLE(chunk_offset+0x4, streamFile);
+ } else if (chunk_size == 0xc) {
+ fact_skip_samples = read_32bitLE(chunk_offset+0x8, streamFile);
+ }
+ ffmpeg_set_skip_samples(ffmpeg_data, fact_skip_samples);
+ }
+ }
+#else
+ goto fail;
+#endif
+
+ if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
+ goto fail;
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+
+/* RSD6WMA [Scarface (Xbox)] */
+VGMSTREAM * init_vgmstream_rsd6wma(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ size_t data_size;
+ int loop_flag, channel_count;
+
+
+ /* checks */
+ if (!check_extensions(streamFile,"rsd"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x52534436) /* "RSD6" */
+ goto fail;
+ if (read_32bitBE(0x04,streamFile) != 0x574D4120) /* "WMA " */
+ goto fail;
+
+ loop_flag = 0;
+ channel_count = read_32bitLE(0x08, streamFile);
+ start_offset = 0x800;
+ data_size = get_streamfile_size(streamFile) - start_offset;
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->meta_type = meta_RSD6WMA;
+ //vgmstream->num_samples = read_32bitLE(start_offset + 0x00, streamFile) / channel_count / 2; /* may be PCM data size, but not exact */
+ vgmstream->sample_rate = read_32bitLE(start_offset + 0x04, streamFile);
+
+#ifdef VGM_USE_FFMPEG
+ {
+ ffmpeg_codec_data *ffmpeg_data = NULL;
+
+ /* mini header + WMA header at start_offset */
+ ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset+0x08,data_size);
+ if (!ffmpeg_data) goto fail;
+ vgmstream->codec_data = ffmpeg_data;
+ vgmstream->coding_type = coding_FFmpeg;
+ vgmstream->layout_type = layout_none;
+
+ vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples; /* an estimation, sometimes cuts files a bit early */
+ }
+#else
+ goto fail;
+#endif
+
+ 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/rws.c b/Frameworks/vgmstream/vgmstream/src/meta/rws.c
index 0f4796f1d..c40898752 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/rws.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/rws.c
@@ -155,7 +155,7 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
if (name_offset)
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamFile);
- vgmstream->layout_type = layout_rws_blocked;
+ vgmstream->layout_type = layout_blocked_rws;
vgmstream->current_block_size = block_size / vgmstream->channels;
vgmstream->full_block_size = block_size_total;
@@ -207,7 +207,7 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
- rws_block_update(start_offset, vgmstream); /* block init */
+ block_update_rws(start_offset, vgmstream); /* block init */
return vgmstream;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sab.c b/Frameworks/vgmstream/vgmstream/src/meta/sab.c
index 6ce952b1c..3fce2b609 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/sab.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/sab.c
@@ -109,7 +109,7 @@ static void get_stream_name(char * stream_name, STREAMFILE *streamFile, int targ
size_t name_size = 0;
off_t name_offset = 0x10;
- streamInfo = open_stream_ext(streamFile, "sob");
+ streamInfo = open_streamfile_by_ext(streamFile, "sob");
if (!streamInfo) goto end;
if (read_32bitBE(0x00,streamInfo) != 0x43544632) /* "CTF2" */
goto end;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c b/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c
index 33c04628c..e37444632 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c
@@ -24,7 +24,7 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
/* SGB+SGH: use SGH as header; otherwise use the current file as header */
if (is_sgb) {
- streamHeader = open_stream_ext(streamFile, "sgh");
+ streamHeader = open_streamfile_by_ext(streamFile, "sgh");
if (!streamHeader) goto fail;
} else {
streamHeader = streamFile;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/smc_smh.c b/Frameworks/vgmstream/vgmstream/src/meta/smc_smh.c
new file mode 100644
index 000000000..9f65e45ff
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/smc_smh.c
@@ -0,0 +1,65 @@
+#include "meta.h"
+#include "../coding/coding.h"
+
+/* SMC+SMH - from Wangan Midnight 1/R (System246) */
+VGMSTREAM * init_vgmstream_smc_smh(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ STREAMFILE * streamHeader = NULL;
+ off_t start_offset, header_offset = 0;
+ size_t stream_size;
+ int loop_flag = 0, channel_count, sample_rate;
+ int total_subsongs, target_subsong = streamFile->stream_index;
+
+
+ /* checks */
+ if (!check_extensions(streamFile, "smc"))
+ goto fail;
+
+ streamHeader = open_streamfile_by_ext(streamFile, "smh");
+ if (!streamHeader) goto fail;
+
+
+ total_subsongs = read_32bitLE(0x00,streamHeader);
+ if (target_subsong == 0) target_subsong = 1;
+ if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
+
+ if (total_subsongs*0x10 + 0x10 != get_streamfile_size(streamHeader))
+ goto fail;
+
+ header_offset = 0x10 + (target_subsong-1)*0x10;
+
+ start_offset = read_32bitLE(header_offset+0x00, streamHeader);
+ stream_size = read_32bitLE(header_offset+0x04, streamHeader);
+ sample_rate = read_32bitLE(header_offset+0x08, streamHeader);
+ /* 0x0c(2): always 0x10, frame size? */
+ channel_count = read_16bitLE(header_offset+0x0e, streamHeader);
+ loop_flag = 0;
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = sample_rate;
+ vgmstream->num_samples = ps_bytes_to_samples(stream_size,channel_count);
+
+ vgmstream->num_streams = total_subsongs;
+ vgmstream->stream_size = stream_size;
+ vgmstream->meta_type = meta_SMC_SMH;
+
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = read_32bitLE(0x04, streamHeader);
+
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
+
+ close_streamfile(streamHeader);
+ return vgmstream;
+
+fail:
+ close_streamfile(streamHeader);
+ close_vgmstream(vgmstream);
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/smv.c b/Frameworks/vgmstream/vgmstream/src/meta/smv.c
new file mode 100644
index 000000000..6691a0846
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/smv.c
@@ -0,0 +1,50 @@
+#include "meta.h"
+#include "../coding/coding.h"
+
+/* .SMV - from Cho Aniki Zero (PSP) */
+VGMSTREAM * init_vgmstream_smv(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ int loop_flag, channel_count;
+ size_t channel_size, loop_start;
+
+
+ /* check extension */
+ if (!check_extensions(streamFile, "smv"))
+ goto fail;
+
+ channel_size = read_32bitLE(0x00,streamFile);
+ /* 0x08: number of full interleave blocks */
+ channel_count = read_16bitLE(0x0a,streamFile);
+ loop_start = read_32bitLE(0x18,streamFile);
+ loop_flag = (loop_start != -1);
+ start_offset = 0x800;
+
+ if (channel_size * channel_count + start_offset != get_streamfile_size(streamFile))
+ goto fail;
+
+ channel_size -= 0x10; /* last value has SPU end frame without flag 0x7 as it should */
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count, loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = read_32bitLE(0x10, streamFile);
+ vgmstream->num_samples = ps_bytes_to_samples(channel_size*channel_count, channel_count);
+ vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start*channel_count, channel_count);
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+
+ vgmstream->meta_type = meta_SMV;
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = read_32bitLE(0x04, streamFile);
+ vgmstream->interleave_last_block_size = read_32bitLE(0x0c, streamFile);
+
+ 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/sps_n1.c b/Frameworks/vgmstream/vgmstream/src/meta/sps_n1.c
index 5ac38d25f..6eca13000 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/sps_n1.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/sps_n1.c
@@ -44,9 +44,6 @@ VGMSTREAM * init_vgmstream_sps_n1(STREAMFILE *streamFile) {
goto fail;
}
- //VGM_LOG(vgmstream->num_samples != num_samples,
- // "SPS: sps num_samples and subfile num_samples don't match\n");
- //vgmstream->num_samples = num_samples; //todo adjusted for MAIATRAC3
vgmstream->sample_rate = sample_rate; /* .vag header doesn't match */
close_streamfile(temp_streamFile);
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c b/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c
index 7c524c06b..dd14dbf4a 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c
@@ -1,5 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
+#include "../layout/layout.h"
#include "sqex_scd_streamfile.h"
@@ -11,9 +12,8 @@ static void scd_ogg_v3_decryption_callback(void *ptr, size_t size, size_t nmemb,
/* SCD - Square-Enix games (FF XIII, XIV) */
VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- off_t start_offset, tables_offset, meta_offset, post_meta_offset, name_offset = 0;
- int32_t stream_size, subheader_size, loop_start, loop_end;
+ off_t start_offset, tables_offset, meta_offset, extradata_offset, name_offset = 0;
+ int32_t stream_size, extradata_size, loop_start, loop_end;
int loop_flag = 0, channel_count, codec, sample_rate;
int version, target_entry, aux_chunk_count;
@@ -26,7 +26,6 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
/* check extension, case insensitive */
if ( !check_extensions(streamFile, "scd") )
goto fail;
- streamFile->get_name(streamFile,filename,sizeof(filename));
/** main header **/
if (read_32bitBE(0x00,streamFile) != 0x53454442 && /* "SEDB" */
@@ -113,13 +112,13 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
loop_start = read_32bit(meta_offset+0x10,streamFile);
loop_end = read_32bit(meta_offset+0x14,streamFile);
- subheader_size = read_32bit(meta_offset+0x18,streamFile);
+ extradata_size = read_32bit(meta_offset+0x18,streamFile);
aux_chunk_count = read_32bit(meta_offset+0x1c,streamFile);
/* 0x01e(2): unknown, seen in some FF XIV sfx (MSADPCM) */
loop_flag = (loop_end > 0);
- post_meta_offset = meta_offset + 0x20;
- start_offset = post_meta_offset + subheader_size;
+ extradata_offset = meta_offset + 0x20;
+ start_offset = extradata_offset + extradata_size;
/* only "MARK" chunk is known (some FF XIV PS3 have "STBL" but it's not counted) */
if (aux_chunk_count > 1 && aux_chunk_count < 0xFFFF) { /* some FF XIV Heavensward IMA sfx have 0x01000000 */
@@ -128,8 +127,8 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
}
/* skips aux chunks, sometimes needed (Lightning Returns X360, FF XIV PC) */
- if (aux_chunk_count && read_32bitBE(post_meta_offset, streamFile) == 0x4D41524B) { /* "MARK" */
- post_meta_offset += read_32bit(post_meta_offset+0x04, streamFile);
+ if (aux_chunk_count && read_32bitBE(extradata_offset, streamFile) == 0x4D41524B) { /* "MARK" */
+ extradata_offset += read_32bit(extradata_offset+0x04, streamFile);
}
/* find name if possible */
@@ -151,41 +150,40 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
if (codec == 0x06) {
VGMSTREAM *ogg_vgmstream;
uint8_t ogg_version, ogg_byte;
- vgm_vorbis_info_t inf = {0};
+ ogg_vorbis_meta_info_t ovmi = {0};
- inf.layout_type = layout_ogg_vorbis;
- inf.meta_type = meta_SQEX_SCD;
- inf.total_subsongs = total_subsongs;
+ ovmi.meta_type = meta_SQEX_SCD;
+ ovmi.total_subsongs = total_subsongs;
/* loop values are in bytes, let init_vgmstream_ogg_vorbis find loop comments instead */
- ogg_version = read_8bit(post_meta_offset + 0x00, streamFile);
+ ogg_version = read_8bit(extradata_offset + 0x00, streamFile);
/* 0x01(1): 0x20 in v2/3, this ogg miniheader size? */
- ogg_byte = read_8bit(post_meta_offset + 0x02, streamFile);
+ ogg_byte = read_8bit(extradata_offset + 0x02, streamFile);
/* 0x03(1): ? in v3 */
if (ogg_version == 0) { /* 0x10? header, then custom Vorbis header before regular Ogg (FF XIV PC v1) */
- inf.stream_size = stream_size;
+ ovmi.stream_size = stream_size;
}
else { /* 0x20 header, then seek table */
- size_t seek_table_size = read_32bit(post_meta_offset+0x10, streamFile);
- size_t vorb_header_size = read_32bit(post_meta_offset+0x14, streamFile);
+ size_t seek_table_size = read_32bit(extradata_offset+0x10, streamFile);
+ size_t vorb_header_size = read_32bit(extradata_offset+0x14, streamFile);
/* 0x18(4): ? (can be 0) */
- if ((post_meta_offset-meta_offset) + seek_table_size + vorb_header_size != subheader_size)
+ if ((extradata_offset-meta_offset) + seek_table_size + vorb_header_size != extradata_size)
goto fail;
- inf.stream_size = vorb_header_size + stream_size;
- start_offset = post_meta_offset + 0x20 + seek_table_size; /* subheader_size skips vorb_header */
+ ovmi.stream_size = vorb_header_size + stream_size;
+ start_offset = extradata_offset + 0x20 + seek_table_size; /* extradata_size skips vorb_header */
if (ogg_version == 2) { /* header is XOR'ed using byte (FF XIV PC) */
- inf.decryption_callback = scd_ogg_v2_decryption_callback;
- inf.scd_xor = ogg_byte;
- inf.scd_xor_length = vorb_header_size;
+ ovmi.decryption_callback = scd_ogg_v2_decryption_callback;
+ ovmi.scd_xor = ogg_byte;
+ ovmi.scd_xor_length = vorb_header_size;
}
else if (ogg_version == 3) { /* file is XOR'ed using table (FF XIV Heavensward PC) */
- inf.decryption_callback = scd_ogg_v3_decryption_callback;
- inf.scd_xor = stream_size & 0xFF; /* ogg_byte not used? */
- inf.scd_xor_length = vorb_header_size + stream_size;
+ ovmi.decryption_callback = scd_ogg_v3_decryption_callback;
+ ovmi.scd_xor = stream_size & 0xFF; /* ogg_byte not used? */
+ ovmi.scd_xor_length = vorb_header_size + stream_size;
}
else {
VGM_LOG("SCD: unknown ogg_version 0x%x\n", ogg_version);
@@ -193,7 +191,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
}
/* actual Ogg init */
- ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf);
+ ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
if (ogg_vgmstream && name_offset)
read_string(ogg_vgmstream->stream_name, PATH_LIMIT, name_offset, streamFile);
return ogg_vgmstream;
@@ -270,8 +268,8 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
case 0x0C: /* MS ADPCM [Final Fantasy XIV (PC) sfx] */
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
- vgmstream->interleave_block_size = read_16bit(post_meta_offset+0x0c,streamFile);
- /* in post_meta_offset is a WAVEFORMATEX (including coefs and all) */
+ vgmstream->interleave_block_size = read_16bit(extradata_offset+0x0c,streamFile);
+ /* in extradata_offset is a WAVEFORMATEX (including coefs and all) */
vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, vgmstream->interleave_block_size, vgmstream->channels);
if (loop_flag) {
@@ -282,61 +280,54 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
case 0x0A: /* DSP ADPCM [Dragon Quest X (Wii)] */
case 0x15: { /* DSP ADPCM [Dragon Quest X (Wii U)] (no apparent differences except higher sample rate) */
- STREAMFILE * file;
- int i;
const off_t interleave_size = 0x800;
const off_t stride_size = interleave_size * channel_count;
+ int i;
size_t total_size;
- scd_int_codec_data * data = NULL;
-
+ layered_layout_data * data = NULL;
+ /* interleaved DSPs including the header (so the first 0x800 is 0x60 header + 0x740 data)
+ * so interleave layout can't used; we'll setup de-interleaving streamfiles as layers/channels instead */
+ //todo this could be simplified using a block layout or adding interleave_first_block
vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_scd_int;
+ vgmstream->layout_type = layout_layered;
- /* a normal DSP header... */
- total_size = (read_32bitBE(start_offset+0x04,streamFile)+1)/2;
- vgmstream->num_samples = read_32bitBE(start_offset+0x00,streamFile);
- if (loop_flag) {
- vgmstream->loop_start_sample = loop_start;
- vgmstream->loop_end_sample = loop_end+1;
- }
+ /* read from the first DSP header and verify other channel headers */
+ {
+ total_size = (read_32bitBE(start_offset+0x04,streamFile)+1)/2; /* rounded nibbles / 2 */
+ vgmstream->num_samples = read_32bitBE(start_offset+0x00,streamFile);
+ if (loop_flag) {
+ vgmstream->loop_start_sample = loop_start;
+ vgmstream->loop_end_sample = loop_end+1;
+ }
- /* verify other channel headers */
- for (i = 1; i < channel_count; i++) {
- if (read_32bitBE(start_offset+interleave_size*i+0,streamFile) != vgmstream->num_samples ||
- (read_32bitBE(start_offset+4,streamFile)+1)/2 != total_size) {
- goto fail;
+ for (i = 1; i < channel_count; i++) {
+ if ((read_32bitBE(start_offset+4,streamFile)+1)/2 != total_size ||
+ read_32bitBE(start_offset+interleave_size*i+0x00,streamFile) != vgmstream->num_samples) {
+ goto fail;
+ }
}
}
- /* the primary streamfile we'll be using */
- file = streamFile->open(streamFile,filename,stride_size);
- if (!file) goto fail;
+ /* init layout */
+ data = init_layout_layered(channel_count);
+ if (!data) goto fail;
+ vgmstream->layout_data = data;
- vgmstream->ch[0].streamfile = file;
+ /* open each layer subfile */
+ for (i = 0; i < channel_count; i++) {
+ STREAMFILE* temp_streamFile = setup_scd_dsp_streamfile(streamFile, start_offset+interleave_size*i, interleave_size, stride_size, total_size);
+ if (!temp_streamFile) goto fail;
- data = malloc(sizeof(scd_int_codec_data));
- data->substream_count = channel_count;
- data->substreams = calloc(channel_count, sizeof(VGMSTREAM *));
- data->intfiles = calloc(channel_count, sizeof(STREAMFILE *));
-
- vgmstream->codec_data = data;
-
- for (i=0;isubstreams[i] = init_vgmstream_ngc_dsp_std(intfile);
- data->intfiles[i] = intfile;
- if (!data->substreams[i]) goto fail;
-
- /* TODO: only handles mono substreams, though that's all we have with DSP */
- /* save start things so we can restart for seeking/looping */
- memcpy(data->substreams[i]->start_ch,data->substreams[i]->ch,sizeof(VGMSTREAMCHANNEL)*1);
- memcpy(data->substreams[i]->start_vgmstream,data->substreams[i],sizeof(VGMSTREAM));
+ data->layers[i] = init_vgmstream_ngc_dsp_std(temp_streamFile);
+ close_streamfile(temp_streamFile);
+ if (!data->layers[i]) goto fail;
}
+ /* setup layered VGMSTREAMs */
+ if (!setup_layout_layered(data))
+ goto fail;
+
break;
}
@@ -346,8 +337,8 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
uint8_t buf[200];
int32_t bytes;
- /* post_meta_offset+0x00: fmt0x166 header (BE), post_meta_offset+0x34: seek table */
- bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, post_meta_offset,0x34, stream_size, streamFile, 1);
+ /* extradata_offset+0x00: fmt0x166 header (BE), extradata_offset+0x34: seek table */
+ bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, extradata_offset,0x34, stream_size, streamFile, 1);
if (bytes <= 0) goto fail;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,stream_size);
@@ -365,7 +356,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
case 0x0E: { /* ATRAC3/ATRAC3plus [Lord of Arcana (PSP), Final Fantasy Type-0] */
ffmpeg_codec_data *ffmpeg_data = NULL;
- /* full RIFF header at start_offset/post_meta_offset (same) */
+ /* full RIFF header at start_offset/extradata_offset (same) */
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
if (!ffmpeg_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
@@ -401,17 +392,17 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
/* post header has various typical ATRAC9 values */
cfg.channels = vgmstream->channels;
- cfg.config_data = read_32bit(post_meta_offset+0x0c,streamFile);
- cfg.encoder_delay = read_32bit(post_meta_offset+0x18,streamFile);
+ cfg.config_data = read_32bit(extradata_offset+0x0c,streamFile);
+ cfg.encoder_delay = read_32bit(extradata_offset+0x18,streamFile);
vgmstream->codec_data = init_atrac9(&cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_ATRAC9;
vgmstream->layout_type = layout_none;
- vgmstream->num_samples = read_32bit(post_meta_offset+0x10,streamFile); /* loop values above are also weird and ignored */
- vgmstream->loop_start_sample = read_32bit(post_meta_offset+0x20, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_start
- vgmstream->loop_end_sample = read_32bit(post_meta_offset+0x24, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_end
+ vgmstream->num_samples = read_32bit(extradata_offset+0x10,streamFile); /* loop values above are also weird and ignored */
+ vgmstream->loop_start_sample = read_32bit(extradata_offset+0x20, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_start
+ vgmstream->loop_end_sample = read_32bit(extradata_offset+0x24, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_end
break;
}
#endif
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd_streamfile.h b/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd_streamfile.h
index 2d9f67c76..2d54bc831 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd_streamfile.h
+++ b/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd_streamfile.h
@@ -2,72 +2,30 @@
#define _SQEX_SCD_STREAMFILE_H_
#include "../streamfile.h"
-/* special streamfile type to handle deinterleaving of complete files (based heavily on AIXSTREAMFILE */
-typedef struct _SCDINTSTREAMFILE {
- STREAMFILE sf;
- STREAMFILE *real_file;
- const char * filename;
- off_t start_physical_offset;
- off_t current_logical_offset;
- off_t interleave_block_size;
- off_t stride_size;
- size_t total_size;
-} SCDINTSTREAMFILE;
+typedef struct {
+ off_t start_physical_offset; /* interleaved data start, for this substream */
+ size_t interleave_block_size; /* max size that can be read before encountering other substreams */
+ size_t stride_size; /* step size between interleave blocks (interleave*channels) */
+ size_t total_size; /* final size of the deinterleaved substream */
+} scd_dsp_io_data;
-/*static*/ STREAMFILE *open_scdint_with_STREAMFILE(STREAMFILE *file, const char * filename, off_t start_offset, off_t interleave_block_size, off_t stride_size, size_t total_size);
-
-
-static STREAMFILE *open_scdint_impl(SCDINTSTREAMFILE *streamfile,const char * const filename,size_t buffersize) {
- SCDINTSTREAMFILE *newfile;
-
- if (strcmp(filename, streamfile->filename))
- return NULL;
-
- newfile = malloc(sizeof(SCDINTSTREAMFILE));
- if (!newfile)
- return NULL;
-
- memcpy(newfile,streamfile,sizeof(SCDINTSTREAMFILE));
- return &newfile->sf;
-}
-
-static void close_scdint(SCDINTSTREAMFILE *streamfile) {
- free(streamfile);
- return;
-}
-
-static size_t get_size_scdint(SCDINTSTREAMFILE *streamfile) {
- return streamfile->total_size;
-}
-
-static size_t get_offset_scdint(SCDINTSTREAMFILE *streamfile) {
- return streamfile->current_logical_offset;
-}
-
-static void get_name_scdint(SCDINTSTREAMFILE *streamfile, char *buffer, size_t length) {
- strncpy(buffer,streamfile->filename,length);
- buffer[length-1]='\0';
-}
-
-static size_t read_scdint(SCDINTSTREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length) {
- size_t sz = 0;
+/* Handles deinterleaving of complete files, skipping portions or other substreams. */
+static size_t scd_dsp_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, scd_dsp_io_data* data) {
+ size_t total_read = 0;
while (length > 0) {
- off_t to_read;
- off_t length_available;
+ size_t to_read;
+ size_t length_available;
off_t block_num;
off_t intrablock_offset;
off_t physical_offset;
-
- block_num = offset / streamfile->interleave_block_size;
- intrablock_offset = offset % streamfile->interleave_block_size;
- streamfile->current_logical_offset = offset;
- physical_offset = streamfile->start_physical_offset + block_num * streamfile->stride_size + intrablock_offset;
-
- length_available = streamfile->interleave_block_size - intrablock_offset;
+ block_num = offset / data->interleave_block_size;
+ intrablock_offset = offset % data->interleave_block_size;
+ physical_offset = data->start_physical_offset + block_num*data->stride_size + intrablock_offset;
+ length_available = data->interleave_block_size - intrablock_offset;
if (length < length_available) {
to_read = length;
@@ -79,16 +37,11 @@ static size_t read_scdint(SCDINTSTREAMFILE *streamfile, uint8_t *dest, off_t off
if (to_read > 0) {
size_t bytes_read;
- bytes_read = read_streamfile(dest,
- physical_offset,
- to_read, streamfile->real_file);
-
- sz += bytes_read;
-
- streamfile->current_logical_offset = offset + bytes_read;
+ bytes_read = read_streamfile(dest, physical_offset, to_read, streamfile);
+ total_read += bytes_read;
if (bytes_read != to_read) {
- return sz; /* an error which we will not attempt to handle here */
+ return total_read;
}
dest += bytes_read;
@@ -97,38 +50,43 @@ static size_t read_scdint(SCDINTSTREAMFILE *streamfile, uint8_t *dest, off_t off
}
}
- return sz;
+ return total_read;
}
-/* start_offset is for *this* interleaved stream */
-/*static*/ STREAMFILE *open_scdint_with_STREAMFILE(STREAMFILE *file, const char * filename, off_t start_offset, off_t interleave_block_size, off_t stride_size, size_t total_size) {
- SCDINTSTREAMFILE * scd = NULL;
+static size_t scd_dsp_io_size(STREAMFILE *streamfile, scd_dsp_io_data* data) {
+ return data->total_size;
+}
- /* _scdint funcs can't handle this case */
- if (start_offset + total_size > file->get_size(file))
- return NULL;
- scd = malloc(sizeof(SCDINTSTREAMFILE));
- if (!scd)
- return NULL;
+static STREAMFILE* setup_scd_dsp_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t interleave_block_size, size_t stride_size, size_t total_size) {
+ STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
+ scd_dsp_io_data io_data = {0};
+ size_t io_data_size = sizeof(scd_dsp_io_data);
- scd->sf.read = (void*)read_scdint;
- scd->sf.get_size = (void*)get_size_scdint;
- scd->sf.get_offset = (void*)get_offset_scdint;
- scd->sf.get_name = (void*)get_name_scdint;
- scd->sf.get_realname = (void*)get_name_scdint;
- scd->sf.open = (void*)open_scdint_impl;
- scd->sf.close = (void*)close_scdint;
+ io_data.start_physical_offset = start_offset;
+ io_data.interleave_block_size = interleave_block_size;
+ io_data.stride_size = stride_size;
+ io_data.total_size = total_size;
- scd->real_file = file;
- scd->filename = filename;
- scd->start_physical_offset = start_offset;
- scd->current_logical_offset = 0;
- scd->interleave_block_size = interleave_block_size;
- scd->stride_size = stride_size;
- scd->total_size = total_size;
- return &scd->sf;
+ /* setup subfile */
+ new_streamFile = open_wrap_streamfile(streamFile);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, scd_dsp_io_read,scd_dsp_io_size);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"dsp");
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ return temp_streamFile;
+
+fail:
+ close_streamfile(temp_streamFile);
+ return NULL;
}
#endif /* _SCD_STREAMFILE_H_ */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sqex_sead.c b/Frameworks/vgmstream/vgmstream/src/meta/sqex_sead.c
index cd2cbf5cc..be1cafc53 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/sqex_sead.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/sqex_sead.c
@@ -7,8 +7,8 @@ static STREAMFILE* setup_sead_hca_streamfile(STREAMFILE *streamFile, off_t subfi
/* SABF/MABF - Square Enix's "sead" audio games [Dragon Quest Builders (PS3), Dissidia Opera Omnia (mobile), FF XV (PS4)] */
VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) {
VGMSTREAM * vgmstream = NULL;
- off_t start_offset, tables_offset, mtrl_offset, meta_offset, post_meta_offset; //, info_offset, name_offset = 0;
- size_t stream_size, descriptor_size, subheader_size, special_size; //, name_size = 0;
+ off_t start_offset, tables_offset, mtrl_offset, meta_offset, extradata_offset; //, info_offset, name_offset = 0;
+ size_t stream_size, descriptor_size, extradata_size, special_size; //, name_size = 0;
int loop_flag = 0, channel_count, codec, sample_rate, loop_start, loop_end;
@@ -118,12 +118,12 @@ VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) {
loop_start = read_32bit(meta_offset+0x0c,streamFile); /* in samples but usually ignored */
loop_end = read_32bit(meta_offset+0x10,streamFile);
- subheader_size = read_32bit(meta_offset+0x14,streamFile); /* including subfile header */
+ extradata_size = read_32bit(meta_offset+0x14,streamFile); /* including subfile header, can be 0 */
stream_size = read_32bit(meta_offset+0x18,streamFile); /* not including subfile header */
special_size = read_32bit(meta_offset+0x1c,streamFile);
loop_flag = (loop_end > 0);
- post_meta_offset = meta_offset + 0x20;
+ extradata_offset = meta_offset + 0x20;
/** info section (get stream name) **/
@@ -155,38 +155,47 @@ VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) {
switch(codec) {
+ case 0x01: { /* PCM [Chrono Trigger sfx (PC)] */
+ start_offset = extradata_offset + extradata_size;
+
+ vgmstream->coding_type = coding_PCM16LE;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x02;
+
+ vgmstream->num_samples = pcm_bytes_to_samples(stream_size, vgmstream->channels, 16);
+ vgmstream->loop_start_sample = loop_start;
+ vgmstream->loop_end_sample = loop_end;
+ break;
+ }
+
case 0x02: { /* MSADPCM [Dragon Quest Builders (Vita) sfx] */
- start_offset = post_meta_offset + subheader_size;
+ start_offset = extradata_offset + extradata_size;
/* 0x00 (2): null?, 0x02(2): entry size? */
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
- vgmstream->interleave_block_size = read_16bit(post_meta_offset+0x04,streamFile);
+ vgmstream->interleave_block_size = read_16bit(extradata_offset+0x04,streamFile);
/* much like AKBs, there are slightly different loop values here, probably more accurate
* (if no loop, loop_end doubles as num_samples) */
vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, vgmstream->interleave_block_size, vgmstream->channels);
- vgmstream->loop_start_sample = read_32bit(post_meta_offset+0x08, streamFile); //loop_start
- vgmstream->loop_end_sample = read_32bit(post_meta_offset+0x0c, streamFile); //loop_end
+ vgmstream->loop_start_sample = read_32bit(extradata_offset+0x08, streamFile); //loop_start
+ vgmstream->loop_end_sample = read_32bit(extradata_offset+0x0c, streamFile); //loop_end
break;
}
#ifdef VGM_USE_VORBIS
case 0x03: { /* OGG [Final Fantasy XV Benchmark sfx (PC)] */
VGMSTREAM *ogg_vgmstream = NULL;
- vgm_vorbis_info_t inf = {0};
- off_t subfile_offset = post_meta_offset + subheader_size;
- char filename[PATH_LIMIT];
+ ogg_vorbis_meta_info_t ovmi = {0};
+ off_t subfile_offset = extradata_offset + extradata_size;
- streamFile->get_name(streamFile,filename,sizeof(filename));
-
- inf.layout_type = layout_ogg_vorbis;
- inf.meta_type = vgmstream->meta_type;
- inf.total_subsongs = total_subsongs;
- inf.stream_size = stream_size;
+ ovmi.meta_type = vgmstream->meta_type;
+ ovmi.total_subsongs = total_subsongs;
+ ovmi.stream_size = stream_size;
/* post header has some kind of repeated values, config/table? */
- ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, subfile_offset, &inf);
+ ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, subfile_offset, &ovmi);
if (ogg_vgmstream) {
ogg_vgmstream->num_streams = vgmstream->num_streams;
ogg_vgmstream->stream_size = vgmstream->stream_size;
@@ -206,21 +215,21 @@ VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) {
case 0x04: { /* ATRAC9 [Dragon Quest Builders (Vita), Final Fantaxy XV (PS4)] */
atrac9_config cfg = {0};
- start_offset = post_meta_offset + subheader_size;
+ start_offset = extradata_offset + extradata_size;
/* post header has various typical ATRAC9 values */
cfg.channels = vgmstream->channels;
- cfg.config_data = read_32bit(post_meta_offset+0x0c,streamFile);
- cfg.encoder_delay = read_32bit(post_meta_offset+0x18,streamFile);
+ cfg.config_data = read_32bit(extradata_offset+0x0c,streamFile);
+ cfg.encoder_delay = read_32bit(extradata_offset+0x18,streamFile);
vgmstream->codec_data = init_atrac9(&cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_ATRAC9;
vgmstream->layout_type = layout_none;
- vgmstream->sample_rate = read_32bit(post_meta_offset+0x1c,streamFile); /* SAB's sample rate can be different but it's ignored */
- vgmstream->num_samples = read_32bit(post_meta_offset+0x10,streamFile); /* loop values above are also weird and ignored */
- vgmstream->loop_start_sample = read_32bit(post_meta_offset+0x20, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_start
- vgmstream->loop_end_sample = read_32bit(post_meta_offset+0x24, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_end
+ vgmstream->sample_rate = read_32bit(extradata_offset+0x1c,streamFile); /* SAB's sample rate can be different but it's ignored */
+ vgmstream->num_samples = read_32bit(extradata_offset+0x10,streamFile); /* loop values above are also weird and ignored */
+ vgmstream->loop_start_sample = read_32bit(extradata_offset+0x20, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_start
+ vgmstream->loop_end_sample = read_32bit(extradata_offset+0x24, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_end
break;
}
#endif
@@ -230,7 +239,7 @@ VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) {
mpeg_codec_data *mpeg_data = NULL;
mpeg_custom_config cfg = {0};
- start_offset = post_meta_offset + subheader_size;
+ start_offset = extradata_offset + extradata_size;
/* post header is a proper MSF, but sample rate/loops are ignored in favor of SAB's */
mpeg_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_STANDARD, &cfg);
@@ -249,13 +258,13 @@ VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) {
//todo there is no easy way to use the HCA decoder; try subfile hack for now
VGMSTREAM *temp_vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
- off_t subfile_offset = post_meta_offset + 0x10;
- size_t subfile_size = stream_size + subheader_size - 0x10;
+ off_t subfile_offset = extradata_offset + 0x10;
+ size_t subfile_size = stream_size + extradata_size - 0x10;
/* post header: values from the HCA header, in file endianness + HCA header */
size_t key_start = special_size & 0xff;
- size_t header_size = read_16bit(post_meta_offset+0x02, streamFile);
- int encryption = read_16bit(post_meta_offset+0x0c, streamFile); //maybe 8bit?
+ size_t header_size = read_16bit(extradata_offset+0x02, streamFile);
+ int encryption = read_16bit(extradata_offset+0x0c, streamFile); //maybe 8bit?
/* encryption type 0x01 found in Final Fantasy XII TZA (PS4/PC) */
temp_streamFile = setup_sead_hca_streamfile(streamFile, subfile_offset, subfile_size, encryption, header_size, key_start);
@@ -304,32 +313,33 @@ typedef struct {
static size_t sead_decryption_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, sead_decryption_data* data) {
/* Found in FFXII_TZA.exe (same key in SCD Ogg V3) */
static const uint8_t encryption_key[0x100] = {
- 0x3A, 0x32, 0x32, 0x32, 0x03, 0x7E, 0x12, 0xF7, 0xB2, 0xE2, 0xA2, 0x67, 0x32, 0x32, 0x22, 0x32, // 00-0F
- 0x32, 0x52, 0x16, 0x1B, 0x3C, 0xA1, 0x54, 0x7B, 0x1B, 0x97, 0xA6, 0x93, 0x1A, 0x4B, 0xAA, 0xA6, // 10-1F
- 0x7A, 0x7B, 0x1B, 0x97, 0xA6, 0xF7, 0x02, 0xBB, 0xAA, 0xA6, 0xBB, 0xF7, 0x2A, 0x51, 0xBE, 0x03, // 20-2F
- 0xF4, 0x2A, 0x51, 0xBE, 0x03, 0xF4, 0x2A, 0x51, 0xBE, 0x12, 0x06, 0x56, 0x27, 0x32, 0x32, 0x36, // 30-3F
- 0x32, 0xB2, 0x1A, 0x3B, 0xBC, 0x91, 0xD4, 0x7B, 0x58, 0xFC, 0x0B, 0x55, 0x2A, 0x15, 0xBC, 0x40, // 40-4F
- 0x92, 0x0B, 0x5B, 0x7C, 0x0A, 0x95, 0x12, 0x35, 0xB8, 0x63, 0xD2, 0x0B, 0x3B, 0xF0, 0xC7, 0x14, // 50-5F
- 0x51, 0x5C, 0x94, 0x86, 0x94, 0x59, 0x5C, 0xFC, 0x1B, 0x17, 0x3A, 0x3F, 0x6B, 0x37, 0x32, 0x32, // 60-6F
- 0x30, 0x32, 0x72, 0x7A, 0x13, 0xB7, 0x26, 0x60, 0x7A, 0x13, 0xB7, 0x26, 0x50, 0xBA, 0x13, 0xB4, // 70-7F
- 0x2A, 0x50, 0xBA, 0x13, 0xB5, 0x2E, 0x40, 0xFA, 0x13, 0x95, 0xAE, 0x40, 0x38, 0x18, 0x9A, 0x92, // 80-8F
- 0xB0, 0x38, 0x00, 0xFA, 0x12, 0xB1, 0x7E, 0x00, 0xDB, 0x96, 0xA1, 0x7C, 0x08, 0xDB, 0x9A, 0x91, // 90-9F
- 0xBC, 0x08, 0xD8, 0x1A, 0x86, 0xE2, 0x70, 0x39, 0x1F, 0x86, 0xE0, 0x78, 0x7E, 0x03, 0xE7, 0x64, // A0-AF
- 0x51, 0x9C, 0x8F, 0x34, 0x6F, 0x4E, 0x41, 0xFC, 0x0B, 0xD5, 0xAE, 0x41, 0xFC, 0x0B, 0xD5, 0xAE, // B0-BF
- 0x41, 0xFC, 0x3B, 0x70, 0x71, 0x64, 0x33, 0x32, 0x12, 0x32, 0x32, 0x36, 0x70, 0x34, 0x2B, 0x56, // C0-CF
- 0x22, 0x70, 0x3A, 0x13, 0xB7, 0x26, 0x60, 0xBA, 0x1B, 0x94, 0xAA, 0x40, 0x38, 0x00, 0xFA, 0xB2, // D0-DF
- 0xE2, 0xA2, 0x67, 0x32, 0x32, 0x12, 0x32, 0xB2, 0x32, 0x32, 0x32, 0x32, 0x75, 0xA3, 0x26, 0x7B, // E0-EF
- 0x83, 0x26, 0xF9, 0x83, 0x2E, 0xFF, 0xE3, 0x16, 0x7D, 0xC0, 0x1E, 0x63, 0x21, 0x07, 0xE3, 0x01, // F0-FF
+ 0x3A,0x32,0x32,0x32,0x03,0x7E,0x12,0xF7,0xB2,0xE2,0xA2,0x67,0x32,0x32,0x22,0x32, // 00-0F
+ 0x32,0x52,0x16,0x1B,0x3C,0xA1,0x54,0x7B,0x1B,0x97,0xA6,0x93,0x1A,0x4B,0xAA,0xA6, // 10-1F
+ 0x7A,0x7B,0x1B,0x97,0xA6,0xF7,0x02,0xBB,0xAA,0xA6,0xBB,0xF7,0x2A,0x51,0xBE,0x03, // 20-2F
+ 0xF4,0x2A,0x51,0xBE,0x03,0xF4,0x2A,0x51,0xBE,0x12,0x06,0x56,0x27,0x32,0x32,0x36, // 30-3F
+ 0x32,0xB2,0x1A,0x3B,0xBC,0x91,0xD4,0x7B,0x58,0xFC,0x0B,0x55,0x2A,0x15,0xBC,0x40, // 40-4F
+ 0x92,0x0B,0x5B,0x7C,0x0A,0x95,0x12,0x35,0xB8,0x63,0xD2,0x0B,0x3B,0xF0,0xC7,0x14, // 50-5F
+ 0x51,0x5C,0x94,0x86,0x94,0x59,0x5C,0xFC,0x1B,0x17,0x3A,0x3F,0x6B,0x37,0x32,0x32, // 60-6F
+ 0x30,0x32,0x72,0x7A,0x13,0xB7,0x26,0x60,0x7A,0x13,0xB7,0x26,0x50,0xBA,0x13,0xB4, // 70-7F
+ 0x2A,0x50,0xBA,0x13,0xB5,0x2E,0x40,0xFA,0x13,0x95,0xAE,0x40,0x38,0x18,0x9A,0x92, // 80-8F
+ 0xB0,0x38,0x00,0xFA,0x12,0xB1,0x7E,0x00,0xDB,0x96,0xA1,0x7C,0x08,0xDB,0x9A,0x91, // 90-9F
+ 0xBC,0x08,0xD8,0x1A,0x86,0xE2,0x70,0x39,0x1F,0x86,0xE0,0x78,0x7E,0x03,0xE7,0x64, // A0-AF
+ 0x51,0x9C,0x8F,0x34,0x6F,0x4E,0x41,0xFC,0x0B,0xD5,0xAE,0x41,0xFC,0x0B,0xD5,0xAE, // B0-BF
+ 0x41,0xFC,0x3B,0x70,0x71,0x64,0x33,0x32,0x12,0x32,0x32,0x36,0x70,0x34,0x2B,0x56, // C0-CF
+ 0x22,0x70,0x3A,0x13,0xB7,0x26,0x60,0xBA,0x1B,0x94,0xAA,0x40,0x38,0x00,0xFA,0xB2, // D0-DF
+ 0xE2,0xA2,0x67,0x32,0x32,0x12,0x32,0xB2,0x32,0x32,0x32,0x32,0x75,0xA3,0x26,0x7B, // E0-EF
+ 0x83,0x26,0xF9,0x83,0x2E,0xFF,0xE3,0x16,0x7D,0xC0,0x1E,0x63,0x21,0x07,0xE3,0x01, // F0-FF
};
size_t bytes_read;
+ off_t encrypted_offset = data->header_size;
int i;
bytes_read = streamfile->read(streamfile, dest, offset, length);
/* decrypt data (xor) */
- if (offset >= data->header_size) {
+ if (offset >= encrypted_offset) {
for (i = 0; i < bytes_read; i++) {
- dest[i] ^= encryption_key[(data->key_start + (offset - data->header_size) + i) % 0x100];
+ dest[i] ^= encryption_key[(data->key_start + (offset - encrypted_offset) + i) % 0x100];
}
}
@@ -355,7 +365,7 @@ static STREAMFILE* setup_sead_hca_streamfile(STREAMFILE *streamFile, off_t subfi
io_data.header_size = header_size;
io_data.key_start = key_start;
- new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, sead_decryption_read);
+ new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, sead_decryption_read,NULL);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sthd.c b/Frameworks/vgmstream/vgmstream/src/meta/sthd.c
new file mode 100644
index 000000000..9c83a0134
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/sthd.c
@@ -0,0 +1,68 @@
+#include "meta.h"
+#include "../coding/coding.h"
+#include "../layout/layout.h"
+
+/* STHD - Dream Factory .stx [Kakuto Chojin (Xbox)] */
+VGMSTREAM * init_vgmstream_sthd(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ int loop_flag, channel_count;
+
+
+ /* checks */
+ if (!check_extensions(streamFile, "stx"))
+ goto fail;
+ if (read_32bitBE(0x00,streamFile) != 0x53544844) /* "STHD" */
+ goto fail;
+ /* first block has special values */
+ if (read_32bitLE(0x04,streamFile) != 0x0800 &&
+ read_32bitLE(0x0c,streamFile) != 0x0001 &&
+ read_32bitLE(0x14,streamFile) != 0x0000)
+ goto fail;
+
+ channel_count = read_16bitLE(0x06,streamFile);
+ loop_flag = read_16bitLE(0x18,streamFile) != -1;
+ start_offset = 0x800;
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count, loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = read_32bitLE(0x20, streamFile); /* repeated ~8 times? */
+ vgmstream->meta_type = meta_STHD;
+ vgmstream->coding_type = coding_XBOX_IMA_int;
+ vgmstream->layout_type = layout_blocked_sthd;
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
+ goto fail;
+
+ /* calc num_samples manually (blocks data varies in size) */
+ {
+ /* loop values may change to +1 in first actual block, but this works ok enough */
+ int loop_start_block = (uint16_t)read_16bitLE(0x1a,streamFile);
+ int loop_end_block = (uint16_t)read_16bitLE(0x1c,streamFile);
+ int block_count = 1; /* header block = 0 */
+
+ vgmstream->next_block_offset = start_offset;
+ do {
+ block_update_sthd(vgmstream->next_block_offset,vgmstream);
+
+ if (block_count == loop_start_block)
+ vgmstream->loop_start_sample = vgmstream->num_samples;
+ if (block_count == loop_end_block)
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+
+ vgmstream->num_samples += xbox_ima_bytes_to_samples(vgmstream->current_block_size, 1);
+ block_count++;
+ }
+ while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
+ }
+
+ block_update_sthd(start_offset, vgmstream);
+
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/str_snds.c b/Frameworks/vgmstream/vgmstream/src/meta/str_snds.c
index b731f27cd..6a43997aa 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/str_snds.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/str_snds.c
@@ -122,7 +122,7 @@ VGMSTREAM * init_vgmstream_str_snds(STREAMFILE *streamFile) {
default:
goto fail;
}
- vgmstream->layout_type = layout_str_snds_blocked;
+ vgmstream->layout_type = layout_blocked_str_snds;
vgmstream->meta_type = meta_STR_SNDS;
/* channels and loop flag are set by allocate_vgmstream */
@@ -144,7 +144,7 @@ VGMSTREAM * init_vgmstream_str_snds(STREAMFILE *streamFile) {
}
/* start me up */
- str_snds_block_update(0,vgmstream);
+ block_update_str_snds(0,vgmstream);
return vgmstream;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sxd.c b/Frameworks/vgmstream/vgmstream/src/meta/sxd.c
index 224dc80ac..8a8c85ac1 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/sxd.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/sxd.c
@@ -25,7 +25,7 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
if (is_dual) {
if (read_32bitBE(0x00,streamFile) != 0x53584453) /* "SXDS" */
goto fail;
- streamHeader = open_stream_ext(streamFile, "sxd1");
+ streamHeader = open_streamfile_by_ext(streamFile, "sxd1");
if (!streamHeader) goto fail;
} else {
streamHeader = streamFile;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ta_aac.c b/Frameworks/vgmstream/vgmstream/src/meta/ta_aac.c
index f7984bd9b..c6ce49f0b 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ta_aac.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ta_aac.c
@@ -210,13 +210,11 @@ fail:
}
/* Android/iOS Variants (Star Ocean Anamnesis (APK v1.9.2), Heaven x Inferno (iOS)) */
-VGMSTREAM * init_vgmstream_ta_aac_mobile(STREAMFILE *streamFile) {
+VGMSTREAM * init_vgmstream_ta_aac_mobile_vorbis(STREAMFILE *streamFile) {
#ifdef VGM_USE_VORBIS
off_t start_offset;
- char filename[PATH_LIMIT];
int8_t codec_id;
- streamFile->get_name(streamFile, filename, sizeof(filename));
/* check extension, case insensitive */
/* .aac: expected, .laac/ace: for players to avoid hijacking MP4/AAC */
if (!check_extensions(streamFile, "aac,laac,ace"))
@@ -231,19 +229,17 @@ VGMSTREAM * init_vgmstream_ta_aac_mobile(STREAMFILE *streamFile) {
codec_id = read_8bit(0x104, streamFile);
if (codec_id == 0xe) /* Vorbis */
{
- vgm_vorbis_info_t inf;
+ ogg_vorbis_meta_info_t ovmi = {0};
VGMSTREAM * result = NULL;
- memset(&inf, 0, sizeof(inf));
- inf.layout_type = layout_ogg_vorbis;
- inf.meta_type = meta_TA_AAC_VORBIS;
- inf.loop_start = read_32bitLE(0x140, streamFile);
- inf.loop_end = read_32bitLE(0x144, streamFile);
- inf.loop_flag = inf.loop_end > inf.loop_start;
- inf.loop_end_found = inf.loop_flag;
+ ovmi.meta_type = meta_TA_AAC_MOBILE;
+ ovmi.loop_start = read_32bitLE(0x140, streamFile);
+ ovmi.loop_end = read_32bitLE(0x144, streamFile);
+ ovmi.loop_flag = ovmi.loop_end > ovmi.loop_start;
+ ovmi.loop_end_found = ovmi.loop_flag;
start_offset = read_32bitLE(0x120, streamFile);
- result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf);
+ result = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
if (result != NULL) {
return result;
@@ -255,3 +251,65 @@ fail:
#endif
return NULL;
}
+
+/* Android/iOS Variants, before they switched to Vorbis (Star Ocean Anamnesis (Android), Heaven x Inferno (iOS)) */
+VGMSTREAM * init_vgmstream_ta_aac_mobile(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ int channel_count, loop_flag, codec;
+ size_t data_size;
+
+
+ /* check extension, case insensitive */
+ /* .aac: expected, .laac/ace: for players to avoid hijacking MP4/AAC */
+ if (!check_extensions(streamFile, "aac,laac,ace"))
+ goto fail;
+
+ if (read_32bitLE(0x00, streamFile) != 0x41414320) /* "AAC " */
+ goto fail;
+
+ if (read_32bitLE(0xf0, streamFile) != 0x57415645) /* "WAVE" */
+ goto fail;
+
+ codec = read_8bit(0x104, streamFile);
+ channel_count = read_8bit(0x105, streamFile);
+ /* 0x106: 0x01?, 0x107: 0x10? */
+ data_size = read_32bitLE(0x10c, streamFile); /* usable data only, cuts last frame */
+ start_offset = read_32bitLE(0x120, streamFile);
+ /* 0x124: full data size */
+ loop_flag = (read_32bitLE(0x134, streamFile) > 0);
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count, loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = read_32bitLE(0x108, streamFile);
+ vgmstream->meta_type = meta_TA_AAC_MOBILE;
+
+ switch(codec) {
+ case 0x0d:
+ if (read_32bitLE(0x144, streamFile) != 0x40) goto fail; /* frame size */
+ if (read_32bitLE(0x148, streamFile) != (0x40-0x04*channel_count)*2 / channel_count) goto fail; /* frame samples */
+ if (channel_count > 2) goto fail; /* unknown data layout */
+
+ vgmstream->coding_type = coding_YAMAHA;
+ vgmstream->layout_type = layout_none;
+
+ vgmstream->num_samples = yamaha_bytes_to_samples(data_size, channel_count);
+ vgmstream->loop_start_sample = yamaha_bytes_to_samples(read_32bitLE(0x130, streamFile), channel_count);;
+ vgmstream->loop_end_sample = yamaha_bytes_to_samples(read_32bitLE(0x134, streamFile), channel_count);;
+ break;
+
+ default:
+ goto fail;
+ }
+
+ 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/thp.c b/Frameworks/vgmstream/vgmstream/src/meta/thp.c
index 2a9c95b9d..1244ff58a 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/thp.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/thp.c
@@ -88,10 +88,10 @@ VGMSTREAM * init_vgmstream_thp(STREAMFILE *streamFile) {
}
vgmstream->full_block_size = read_32bitBE(0x18,streamFile); /* block size of current block, changes every time */
- thp_block_update(start_offset,vgmstream);
+ block_update_thp(start_offset,vgmstream);
vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = layout_thp_blocked;
+ vgmstream->layout_type = layout_blocked_thp;
vgmstream->meta_type = meta_THP;
return vgmstream;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/txth.c b/Frameworks/vgmstream/vgmstream/src/meta/txth.c
index 82d6e560f..25a7a6bd7 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/txth.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/txth.c
@@ -1,7 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
-#include "../util.h"
#define TXT_LINE_MAX 0x2000
@@ -82,6 +81,11 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
coding_t coding;
int i, j;
+
+ /* reject .txth as the CLI can open and decode with itself */
+ if (check_extensions(streamFile, "txth"))
+ goto fail;
+
/* no need for ID or ext checks -- if a .TXTH exists all is good
* (player still needs to accept the streamfile's ext, so at worst rename to .vgmstream) */
streamText = open_txth(streamFile);
@@ -168,6 +172,8 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
coding = coding_DVI_IMA_int;
if (coding == coding_IMA)
coding = coding_IMA_int;
+ if (coding == coding_AICA)
+ coding = coding_AICA_int;
}
/* to avoid endless loops */
@@ -176,7 +182,8 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
coding == coding_PSX_badflags ||
coding == coding_IMA_int ||
coding == coding_DVI_IMA_int ||
- coding == coding_SDX2_int) ) {
+ coding == coding_SDX2_int ||
+ coding == coding_AICA_int) ) {
goto fail;
}
} else {
@@ -184,7 +191,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
}
/* setup adpcm */
- if (coding == coding_AICA) {
+ if (coding == coding_AICA || coding == coding_AICA_int) {
int i;
for (i=0;ichannels;i++) {
vgmstream->ch[i].adpcm_step_index = 0x7f;
@@ -206,7 +213,15 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
vgmstream->layout_type = layout_none;
break;
case coding_XBOX_IMA:
- vgmstream->layout_type = layout_none;
+ if (txth.codec_mode == 1) {
+ if (!txth.interleave) goto fail; /* creates garbage */
+ coding = coding_XBOX_IMA_int;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = txth.interleave;
+ }
+ else {
+ vgmstream->layout_type = layout_none;
+ }
break;
case coding_NGC_DTK:
if (vgmstream->channels != 2) goto fail;
@@ -374,14 +389,14 @@ static STREAMFILE * open_txth(STREAMFILE * streamFile) {
STREAMFILE * streamText;
/* try "(path/)(name.ext).txth" */
- if (!get_streamfile_name(streamFile,filename,PATH_LIMIT)) goto fail;
+ get_streamfile_name(streamFile,filename,PATH_LIMIT);
strcat(filename, ".txth");
streamText = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (streamText) return streamText;
/* try "(path/)(.ext).txth" */
- if (!get_streamfile_path(streamFile,filename,PATH_LIMIT)) goto fail;
- if (!get_streamfile_ext(streamFile,fileext,PATH_LIMIT)) goto fail;
+ get_streamfile_path(streamFile,filename,PATH_LIMIT);
+ get_streamfile_ext(streamFile,fileext,PATH_LIMIT);
strcat(filename,".");
strcat(filename, fileext);
strcat(filename, ".txth");
@@ -389,14 +404,13 @@ static STREAMFILE * open_txth(STREAMFILE * streamFile) {
if (streamText) return streamText;
/* try "(path/).txth" */
- if (!get_streamfile_path(streamFile,filename,PATH_LIMIT)) goto fail;
+ get_streamfile_path(streamFile,filename,PATH_LIMIT);
strcat(filename, ".txth");
streamText = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (streamText) return streamText;
-fail:
/* not found */
- return 0;
+ return NULL;
}
/* Simple text parser of "key = value" lines.
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/txtp.c b/Frameworks/vgmstream/vgmstream/src/meta/txtp.c
new file mode 100644
index 000000000..1a5176222
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/txtp.c
@@ -0,0 +1,357 @@
+#include "meta.h"
+#include "../coding/coding.h"
+#include "../layout/layout.h"
+
+
+#define TXT_LINE_MAX 0x2000
+
+typedef struct {
+ char filename[TXT_LINE_MAX];
+ int subsong;
+ uint32_t channel_mask;
+} txtp_entry;
+
+typedef struct {
+ txtp_entry *entry;
+ size_t entry_count;
+ size_t entry_max;
+
+ size_t loop_start_segment;
+ size_t loop_end_segment;
+} txtp_header;
+
+static txtp_header* parse_txtp(STREAMFILE* streamFile);
+static void clean_txtp(txtp_header* txtp);
+
+
+/* TXTP - an artificial playlist-like format to play segmented files with config */
+VGMSTREAM * init_vgmstream_txtp(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ txtp_header* txtp = NULL;
+ segmented_layout_data *data = NULL;
+
+
+ /* checks */
+ if (!check_extensions(streamFile, "txtp"))
+ goto fail;
+
+ /* read .txtp text file to get segments */
+ txtp = parse_txtp(streamFile);
+ if (!txtp) goto fail;
+
+
+ if (txtp->entry_count == 0)
+ goto fail;
+
+
+ if (txtp->entry_count == 1 && !txtp->loop_start_segment) {
+ /* single file */
+ STREAMFILE* temp_streamFile = open_streamfile_by_filename(streamFile, txtp->entry[0].filename);
+ if (!temp_streamFile) goto fail;
+ temp_streamFile->stream_index = txtp->entry[0].subsong;
+
+ vgmstream = init_vgmstream_from_STREAMFILE(temp_streamFile);
+ close_streamfile(temp_streamFile);
+ if (!vgmstream) goto fail;
+
+ vgmstream->channel_mask = txtp->entry[0].channel_mask;
+ }
+ else {
+ /* multi file */
+ int num_samples, loop_start_sample = 0, loop_end_sample = 0;
+ int i;
+ int loop_flag, channel_count;
+
+
+ /* init layout */
+ data = init_layout_segmented(txtp->entry_count);
+ if (!data) goto fail;
+
+ /* open each segment subfile */
+ for (i = 0; i < txtp->entry_count; i++) {
+ STREAMFILE* temp_streamFile = open_streamfile_by_filename(streamFile, txtp->entry[i].filename);
+ if (!temp_streamFile) goto fail;
+ temp_streamFile->stream_index = txtp->entry[i].subsong;
+
+ data->segments[i] = init_vgmstream_from_STREAMFILE(temp_streamFile);
+ close_streamfile(temp_streamFile);
+ if (!data->segments[i]) goto fail;
+
+ data->segments[i]->channel_mask = txtp->entry[0].channel_mask;
+ }
+
+ /* setup segmented VGMSTREAMs */
+ if (!setup_layout_segmented(data))
+ goto fail;
+
+ /* get looping and samples */
+ if (txtp->loop_start_segment && !txtp->loop_end_segment)
+ txtp->loop_end_segment = txtp->entry_count;
+ loop_flag = (txtp->loop_start_segment > 0 && txtp->loop_start_segment <= txtp->entry_count);
+ num_samples = 0;
+ for (i = 0; i < data->segment_count; i++) {
+
+ if (loop_flag && txtp->loop_start_segment == i+1) {
+ loop_start_sample = num_samples;
+ }
+
+ num_samples += data->segments[i]->num_samples;
+
+ if (loop_flag && txtp->loop_end_segment == i+1) {
+ loop_end_sample = num_samples;
+ }
+ }
+
+ channel_count = data->segments[0]->channels;
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = data->segments[0]->sample_rate;
+ vgmstream->num_samples = num_samples;
+ vgmstream->loop_start_sample = loop_start_sample;
+ vgmstream->loop_end_sample = loop_end_sample;
+
+ vgmstream->meta_type = meta_TXTP;
+ vgmstream->coding_type = data->segments[0]->coding_type;
+ vgmstream->layout_type = layout_segmented;
+
+ vgmstream->layout_data = data;
+ if (loop_flag)
+ data->loop_segment = txtp->loop_start_segment-1;
+ }
+
+
+ clean_txtp(txtp);
+ return vgmstream;
+
+fail:
+ clean_txtp(txtp);
+ close_vgmstream(vgmstream);
+ free_layout_segmented(data);
+ return NULL;
+}
+
+
+static int add_filename(txtp_header * txtp, char *filename) {
+ int i;
+ uint32_t channel_mask = 0;
+ size_t range_start, range_end;
+
+ //;VGM_LOG("TXTP: filename=%s\n", filename);
+
+ /* parse config:
+ * - file.ext#2 = play subsong 2
+ * - file.ext#2~10 = play subsongs in 2 to 10 range
+ * - file.ext#c1,2 = play channels 1,2 */
+ {
+ char *config;
+
+ /* position in base extension */
+ config = strrchr(filename,'.');
+ if (!config) /* needed...? */
+ config = filename;
+
+ range_start = 0;
+ range_end = 1;
+ do {
+ /* get config pointer but remove config from filename */
+ config = strchr(config, '#');
+ if (!config)
+ continue;
+
+ config[0] = '\0';
+ config++;
+
+
+ if (config[0] == 'c') {
+ /* mask channels */
+ int n, ch;
+
+ config++;
+ channel_mask = 0;
+ while (sscanf(config, "%d%n", &ch,&n) == 1) {
+ if (ch > 0 && ch < 32)
+ channel_mask |= (1 << (ch-1));
+
+ config += n;
+ if (config[0]== ',' || config[0]== '-') /* "-" for PowerShell, may have problems with "," */
+ config++;
+ else if (config[0] != '\0')
+ break;
+ };
+ }
+ else {
+ /* subsong range */
+ int subsong_start = 0, subsong_end = 0;
+
+ if (sscanf(config, "%d~%d", &subsong_start, &subsong_end) == 2) {
+ if (subsong_start > 0 && subsong_end > 0) {
+ range_start = subsong_start-1;
+ range_end = subsong_end-1;
+ }
+ }
+ else if (sscanf(config, "%u", &subsong_start) == 1) {
+ if (subsong_start > 0) {
+ range_start = subsong_start-1;
+ range_end = subsong_start;
+ }
+ }
+ else {
+ config = NULL; /* wrong config, ignore */
+ }
+ }
+
+ } while (config != NULL);
+
+ //;VGM_LOG("TXTP: config: range %i~%i, mask=%x\n", range_start, range_end, channel_mask);
+ }
+
+
+ /* hack to allow relative paths in various OSs */
+ {
+ char c;
+
+ i = 0;
+ while ((c = filename[i]) != '\0') {
+ if ((c == '\\' && DIR_SEPARATOR == '/') || (c == '/' && DIR_SEPARATOR == '\\'))
+ filename[i] = DIR_SEPARATOR;
+ i++;
+ }
+ }
+
+
+ /* add filesnames */
+ for (i = range_start; i < range_end; i++){
+ /* resize in steps if not enough */
+ if (txtp->entry_count+1 > txtp->entry_max) {
+ txtp_entry *temp_entry;
+
+ txtp->entry_max += 5;
+ temp_entry = realloc(txtp->entry, sizeof(txtp_entry) * txtp->entry_max);
+ if (!temp_entry) goto fail;
+ txtp->entry = temp_entry;
+ }
+
+ /* new entry */
+ memset(&txtp->entry[txtp->entry_count],0, sizeof(txtp_entry));
+
+ strcpy(txtp->entry[txtp->entry_count].filename, filename);
+ txtp->entry[txtp->entry_count].channel_mask = channel_mask;
+ txtp->entry[txtp->entry_count].subsong = (i+1);
+ txtp->entry_count++;
+ }
+
+ return 1;
+fail:
+ return 0;
+}
+
+static int parse_num(const char * val, uint32_t * out_value) {
+ int hex = (val[0]=='0' && val[1]=='x');
+ if (sscanf(val, hex ? "%x" : "%u", out_value)!=1)
+ goto fail;
+
+ return 1;
+fail:
+ return 0;
+}
+
+static int parse_keyval(txtp_header * txtp, const char * key, const char * val) {
+ //;VGM_LOG("TXTP: key %s = val %s\n", key,val);
+
+ if (0==strcmp(key,"loop_start_segment")) {
+ if (!parse_num(val, &txtp->loop_start_segment)) goto fail;
+ }
+ else if (0==strcmp(key,"loop_end_segment")) {
+ if (!parse_num(val, &txtp->loop_end_segment)) goto fail;
+ }
+ else {
+ VGM_LOG("TXTP: unknown key=%s, val=%s\n", key,val);
+ goto fail;
+ }
+
+ return 1;
+fail:
+ return 0;
+}
+
+static txtp_header* parse_txtp(STREAMFILE* streamFile) {
+ txtp_header* txtp = NULL;
+ off_t txt_offset = 0x00;
+ off_t file_size = get_streamfile_size(streamFile);
+
+
+ txtp = calloc(1,sizeof(txtp_header));
+ if (!txtp) goto fail;
+
+
+ /* empty file: use filename with config (ex. "song.ext#3.txtp") */
+ if (get_streamfile_size(streamFile) == 0) {
+ char filename[PATH_LIMIT] = {0};
+ char* ext;
+ get_streamfile_filename(streamFile, filename,PATH_LIMIT);
+
+ /* remove ".txtp" */
+ ext = strrchr(filename,'.');
+ if (!ext) goto fail; /* ??? */
+ ext[0] = '\0';
+
+ if (!add_filename(txtp, filename))
+ goto fail;
+
+ return txtp;
+ }
+
+
+ /* skip BOM if needed */
+ if (read_16bitLE(0x00, streamFile) == 0xFFFE || read_16bitLE(0x00, streamFile) == 0xFEFF)
+ txt_offset = 0x02;
+
+ /* read lines */
+ while (txt_offset < file_size) {
+ char line[TXT_LINE_MAX] = {0};
+ char key[TXT_LINE_MAX] = {0}, val[TXT_LINE_MAX] = {0}; /* at least as big as a line to avoid overflows (I hope) */
+ char filename[TXT_LINE_MAX] = {0};
+ int ok, bytes_read, line_done;
+
+ bytes_read = get_streamfile_text_line(TXT_LINE_MAX,line, txt_offset,streamFile, &line_done);
+ if (!line_done) goto fail;
+
+ txt_offset += bytes_read;
+
+ /* get key/val (ignores lead/trail spaces, stops at space/comment/separator) */
+ ok = sscanf(line, " %[^ \t#=] = %[^ \t#\r\n] ", key,val);
+ if (ok == 2) { /* no key=val */
+ if (!parse_keyval(txtp, key, val)) /* read key/val */
+ goto fail;
+ continue;
+ }
+
+ /* must be a filename (only remove spaces from start/end, as filenames con contain mid spaces/#/etc) */
+ ok = sscanf(line, " %[^\t\r\n] ", filename);
+ if (ok != 1) /* not a filename either */
+ continue;
+ if (filename[0] == '#')
+ continue; /* simple comment */
+
+ /* filename with config */
+ if (!add_filename(txtp, filename))
+ goto fail;
+ }
+
+
+ return txtp;
+fail:
+ clean_txtp(txtp);
+ return NULL;
+}
+
+static void clean_txtp(txtp_header* txtp) {
+ if (!txtp)
+ return;
+
+ free(txtp->entry);
+ free(txtp);
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c
new file mode 100644
index 000000000..1ce698ccf
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c
@@ -0,0 +1,517 @@
+#include "meta.h"
+#include "../coding/coding.h"
+
+
+typedef enum { NONE = 0, UBI_ADPCM, RAW_PCM, RAW_PSX, RAW_XMA1, RAW_XMA2, RAW_AT3, FMT_AT3, RAW_DSP, FMT_OGG } ubi_bao_codec;
+typedef struct {
+ ubi_bao_codec codec;
+ int big_endian;
+ int total_subsongs;
+
+ /* stream info */
+ size_t header_size;
+ size_t stream_size;
+ off_t stream_offset;
+ uint32_t stream_id;
+ off_t extradata_offset;
+ int is_external;
+
+ int header_codec;
+ int num_samples;
+ int sample_rate;
+ int channels;
+
+ char resource_name[255];
+ int types_count[9];
+} ubi_bao_header;
+
+static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset);
+static int parse_pk_header(ubi_bao_header * bao, STREAMFILE *streamFile);
+static VGMSTREAM * init_vgmstream_ubi_bao_main(ubi_bao_header * bao, STREAMFILE *streamFile);
+
+
+/* .PK - packages with BAOs from Ubisoft's sound engine ("DARE") games in 2008+ */
+VGMSTREAM * init_vgmstream_ubi_bao_pk(STREAMFILE *streamFile) {
+ ubi_bao_header bao = {0};
+
+ /* checks */
+ if (!check_extensions(streamFile, "pk,lpk"))
+ goto fail;
+
+ /* .pk+spk (or .lpk+lspk) is a database-like format, evolved from Ubi sb0/sm0+sp0.
+ * .pk has "BAO" headers pointing to internal or external .spk resources (also BAOs). */
+
+ /* main parse */
+ if ( !parse_pk_header(&bao, streamFile) )
+ goto fail;
+
+ return init_vgmstream_ubi_bao_main(&bao, streamFile);
+fail:
+ return NULL;
+}
+
+#if 0
+/* .BAO - files with a single BAO from Ubisoft's sound engine ("DARE") games in 2008+ */
+VGMSTREAM * init_vgmstream_ubi_bao_file(STREAMFILE *streamFile) {
+ ubi_bao_header bao = {0};
+
+ /* checks */
+ if (!check_extensions(streamFile, "bao"))
+ goto fail;
+
+ /* single .bao+sbao found in .forge and similar bigfiles (containing compressed
+ * "BAO_0xNNNNNNNN" headers/links, or "Common/English/(etc)_BAO_0xNNNNNNNN" streams).
+ * The bigfile acts as index, but external files can be opened as are named after their id.
+ * Extension isn't always given but is .bao in some games. */
+
+ /* main parse */
+ if ( !parse_bao_header(&bao, streamFile) )
+ goto fail;
+
+ return init_vgmstream_ubi_bao_main(&bao, streamFile);
+fail:
+ return NULL;
+}
+#endif
+
+
+static VGMSTREAM * init_vgmstream_ubi_bao_main(ubi_bao_header * bao, STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ STREAMFILE *streamData = NULL;
+ off_t start_offset;
+ int loop_flag = 0;
+
+
+ /* open external stream if needed */
+ if (bao->is_external) {
+ streamData = open_streamfile_by_filename(streamFile,bao->resource_name);
+ if (!streamData) {
+ VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name);
+ goto fail;
+ }
+ }
+ else {
+ streamData = streamFile;
+ }
+
+ start_offset = bao->stream_offset;
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(bao->channels,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->num_samples = bao->num_samples;
+ vgmstream->sample_rate = bao->sample_rate;
+ vgmstream->num_streams = bao->total_subsongs;
+ vgmstream->stream_size = bao->stream_size;
+ vgmstream->meta_type = meta_UBI_BAO;
+
+ switch(bao->codec) {
+#if 0
+ case UBI_ADPCM: {
+ vgmstream->coding_type = coding_UBI_IMA;
+ vgmstream->layout_type = layout_none;
+ break;
+ }
+#endif
+
+ case RAW_PCM:
+ vgmstream->coding_type = coding_PCM16LE; /* always LE even on Wii */
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x02;
+ break;
+
+ case RAW_PSX:
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = bao->stream_size / bao->channels;
+ break;
+
+ case RAW_DSP:
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = bao->stream_size / bao->channels;
+ dsp_read_coefs_be(vgmstream,streamFile,bao->extradata_offset+0x10, 0x40);
+ break;
+
+#ifdef VGM_USE_FFMPEG
+ case RAW_XMA1:
+ case RAW_XMA2: {
+ uint8_t buf[0x100];
+ size_t bytes, chunk_size;
+
+ chunk_size = (bao->codec == RAW_XMA1) ? 0x20 : 0x34;
+
+ bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, bao->extradata_offset,chunk_size, bao->stream_size, streamFile, 1);
+ vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,bao->stream_size);
+ if ( !vgmstream->codec_data ) goto fail;
+ vgmstream->coding_type = coding_FFmpeg;
+ vgmstream->layout_type = layout_none;
+ break;
+ }
+
+ case RAW_AT3: {
+ uint8_t buf[0x100];
+ int32_t bytes, block_size, encoder_delay, joint_stereo;
+
+ block_size = 0xc0 * vgmstream->channels;
+ joint_stereo = 0;
+ encoder_delay = 0x00;//todo not correct
+
+ bytes = ffmpeg_make_riff_atrac3(buf,0x100, vgmstream->num_samples, bao->stream_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay);
+ vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,bao->stream_size);
+ if (!vgmstream->codec_data) goto fail;
+ vgmstream->coding_type = coding_FFmpeg;
+ vgmstream->layout_type = layout_none;
+ break;
+ }
+
+ case FMT_AT3: {
+ ffmpeg_codec_data *ffmpeg_data;
+
+ ffmpeg_data = init_ffmpeg_offset(streamData, start_offset, bao->stream_size);
+ if ( !ffmpeg_data ) goto fail;
+ vgmstream->codec_data = ffmpeg_data;
+ vgmstream->coding_type = coding_FFmpeg;
+ vgmstream->layout_type = layout_none;
+
+ /* manually read skip_samples if FFmpeg didn't do it */
+ if (ffmpeg_data->skipSamples <= 0) {
+ off_t chunk_offset;
+ size_t chunk_size, fact_skip_samples = 0;
+ if (!find_chunk_le(streamData, 0x66616374,start_offset+0xc,0, &chunk_offset,&chunk_size)) /* find "fact" */
+ goto fail;
+ if (chunk_size == 0x8) {
+ fact_skip_samples = read_32bitLE(chunk_offset+0x4, streamData);
+ } else if (chunk_size == 0xc) {
+ fact_skip_samples = read_32bitLE(chunk_offset+0x8, streamData);
+ }
+ ffmpeg_set_skip_samples(ffmpeg_data, fact_skip_samples);
+ }
+ break;
+ }
+
+ case FMT_OGG: {
+ ffmpeg_codec_data *ffmpeg_data;
+
+ ffmpeg_data = init_ffmpeg_offset(streamData, start_offset, bao->stream_size);
+ if ( !ffmpeg_data ) goto fail;
+ vgmstream->codec_data = ffmpeg_data;
+ vgmstream->coding_type = coding_FFmpeg;
+ vgmstream->layout_type = layout_none;
+
+ vgmstream->num_samples = bao->num_samples; /* ffmpeg_data->totalSamples */
+ VGM_ASSERT(bao->num_samples != ffmpeg_data->totalSamples, "UBI BAO: header samples differ\n");
+ break;
+ }
+
+#endif
+ default:
+ goto fail;
+ }
+
+ /* open the file for reading (can be an external stream, different from the current .pk) */
+ if ( !vgmstream_open_stream(vgmstream, streamData, start_offset) )
+ goto fail;
+
+ if (bao->is_external && streamData) close_streamfile(streamData);
+ return vgmstream;
+
+fail:
+ if (bao->is_external && streamData) close_streamfile(streamData);
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+/* parse a .pk (package) file: index + BAOs + external .spk resource table. We want header
+ * BAOs pointing to internal/external stream BAOs (.spk is the same, with stream BAOs only). */
+static int parse_pk_header(ubi_bao_header * bao, STREAMFILE *streamFile) {
+ int i;
+ int index_entries;
+ size_t index_size, index_header_size;
+ off_t bao_offset, resources_offset;
+ int target_subsong = streamFile->stream_index;
+
+
+ /* class: 0x01=index, 0x02=BAO */
+ if (read_8bit(0x00, streamFile) != 0x01)
+ goto fail;
+ /* index and resources always LE */
+
+ /* 0x01(3): version, major/minor/release (numbering continues from .sb0/sm0) */
+ index_size = read_32bitLE(0x04, streamFile); /* can be 0 */
+ resources_offset = read_32bitLE(0x08, streamFile); /* always found even if not used */
+ /* 0x0c: always 0? */
+ /* 0x10: unknown, null if no entries */
+ /* 0x14: config/flags/time? (changes a bit between files), null if no entries */
+ /* 0x18(10): file GUID? clones may share it */
+ /* 0x24: unknown */
+ /* 0x2c: unknown, may be same as 0x14, can be null */
+ /* 0x30(10): parent GUID? may be same as 0x18, may be shared with other files */
+ /* (the above values seem ignored by games, probably just info for their tools) */
+
+ index_entries = index_size / 0x08;
+ index_header_size = 0x40;
+
+ /* parse index to get target subsong N = Nth header BAO */
+ bao_offset = index_header_size + index_size;
+ for (i = 0; i < index_entries; i++) {
+ //uint32_t bao_id = read_32bitLE(index_header_size+0x08*i+0x00, streamFile);
+ size_t bao_size = read_32bitLE(index_header_size+0x08*i+0x04, streamFile);
+
+ /* parse and continue to find out total_subsongs */
+ if (!parse_bao(bao, streamFile, bao_offset))
+ goto fail;
+
+ bao_offset += bao_size; /* files simply concat BAOs */
+ }
+
+ ;VGM_LOG("BAO types: 10=%i,20=%i,30=%i,40=%i,50=%i,70=%i,80=%i\n",
+ bao->types_count[1],bao->types_count[2],bao->types_count[3],bao->types_count[4],bao->types_count[5],bao->types_count[7],bao->types_count[8]);
+
+ if (bao->total_subsongs == 0) {
+ VGM_LOG("UBI BAO: no streams\n");
+ goto fail; /* not uncommon */
+ }
+ if (target_subsong < 0 || target_subsong > bao->total_subsongs || bao->total_subsongs < 1) goto fail;
+
+
+ /* get stream pointed by header */
+ if (bao->is_external) {
+ /* parse resource table, LE (may be empty, or exist even with nothing in the file) */
+ off_t offset;
+ int resources_count = read_32bitLE(resources_offset+0x00, streamFile);
+ size_t strings_size = read_32bitLE(resources_offset+0x04, streamFile);
+
+ offset = resources_offset + 0x04+0x04 + strings_size;
+ for (i = 0; i < resources_count; i++) {
+ uint32_t resource_id = read_32bitLE(offset+0x10*i+0x00, streamFile);
+ off_t name_offset = read_32bitLE(offset+0x10*i+0x04, streamFile);
+ off_t resource_offset = read_32bitLE(offset+0x10*i+0x08, streamFile);
+ size_t resource_size = read_32bitLE(offset+0x10*i+0x0c, streamFile);
+
+ if (resource_id == bao->stream_id) {
+ bao->stream_offset = resource_offset + bao->header_size;
+ read_string(bao->resource_name,255, resources_offset + 0x04+0x04 + name_offset, streamFile);
+
+ VGM_ASSERT(bao->stream_size != resource_size - bao->header_size, "UBI BAO: stream vs resource size mismatch\n");
+ break;
+ }
+ }
+
+
+ //todo find flag and fix
+ /* some songs divide data in internal+external resource and data may be split arbitrarily,
+ * must join on reads (needs multifile_streamfile); resources may use block layout in XMA too */
+ bao_offset = index_header_size + index_size;
+ for (i = 0; i < index_entries; i++) {
+ uint32_t bao_id = read_32bitLE(index_header_size+0x08*i+0x00, streamFile);
+ size_t bao_size = read_32bitLE(index_header_size+0x08*i+0x04, streamFile);
+
+ if (bao_id == bao->stream_id) {
+ VGM_LOG("UBI BAO: found internal+external at offset=%lx\n",bao_offset);
+ goto fail;
+ }
+
+ bao_offset += bao_size;
+ }
+ }
+ else {
+ /* find within index */
+
+ bao_offset = index_header_size + index_size;
+ for (i = 0; i < index_entries; i++) {
+ uint32_t bao_id = read_32bitLE(index_header_size+0x08*i+0x00, streamFile);
+ size_t bao_size = read_32bitLE(index_header_size+0x08*i+0x04, streamFile);
+
+ if (bao_id == bao->stream_id) {
+ bao->stream_offset = bao_offset + bao->header_size; /* relative, adjust to skip descriptor */
+ break;
+ }
+
+ bao_offset += bao_size;
+ }
+ }
+
+ if (!bao->stream_offset) {
+ VGM_LOG("UBI BAO: stream not found (id=%08x, external=%i)\n", bao->stream_id, bao->is_external);
+ goto fail;
+ }
+
+ ;VGM_LOG("BAO stream: id=%x, offset=%lx, size=%x, res=%s\n", bao->stream_id, bao->stream_offset, bao->stream_size, (bao->is_external ? bao->resource_name : "internal"));
+
+ return 1;
+fail:
+ return 0;
+}
+
+/* parse a single BAO (binary audio object) descriptor */
+static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset) {
+ int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
+ uint32_t bao_version, descriptor_type;
+ size_t header_size;
+ int target_subsong = streamFile->stream_index;
+
+
+ /* 0x00(1): class? usually 0x02 but older BAOs have 0x01 too */
+ bao_version = read_32bitBE(offset + 0x00, streamFile) & 0x00FFFFFF;
+
+ /* detect endianness */
+ if (read_32bitLE(offset+0x04, streamFile) < 0x0000FFFF) {
+ read_32bit = read_32bitLE;
+ } else {
+ read_32bit = read_32bitBE;
+ bao->big_endian = 1;
+ }
+
+ header_size = read_32bit(offset+0x04, streamFile); /* mainly 0x28, rarely 0x24 */
+ /* 0x08(10): descriptor GUID? */
+ /* 0x18: null */
+ /* 0x1c: null */
+ descriptor_type = read_32bit(offset+0x20, streamFile);
+ /* 0x28: subtype? usually 0x02/0x01, games may crash if changed */
+
+ /* for debugging purposes */
+ switch(descriptor_type) {
+ case 0x10000000: bao->types_count[1]++; break; /* link by id to another descriptor (link or header) */
+ case 0x20000000: bao->types_count[2]++; break; /* stream header (and subtypes) */
+ case 0x30000000: bao->types_count[3]++; break; /* internal stream (in .pk) */
+ case 0x40000000: bao->types_count[4]++; break; /* package info? */
+ case 0x50000000: bao->types_count[5]++; break; /* external stream (in .spk) */
+ case 0x70000000: bao->types_count[7]++; break; /* project info? (sometimes special id 0x7fffffff)*/
+ case 0x80000000: bao->types_count[8]++; break; /* unknown (some id/info?) */
+ default:
+ VGM_LOG("UBI BAO: unknown descriptor type at %lx\n", offset);
+ goto fail;
+ }
+
+ /* only parse headers */
+ if (descriptor_type != 0x20000000)
+ return 1;
+ /* ignore other header subtypes, 0x01=sound header, 0x04=info? (like Ubi .sb0) */
+ if (read_32bit(offset+header_size+0x04, streamFile) != 0x01)
+ return 1;
+
+ bao->total_subsongs++;
+ if (target_subsong == 0) target_subsong = 1;
+
+ if (target_subsong != bao->total_subsongs)
+ return 1;
+
+ /* parse BAO per version. Structure is mostly the same with some extra fields.
+ * - descriptor id (ignored by game)
+ * - type (may crash on game startup if changed)
+ * - stream size
+ * - stream id, corresponding to an internal (0x30) or external (0x50) stream
+ * - various flags/config fields
+ * - channels, ?, sample rate, average bit rate?, samples, full stream_size?, codec, etc
+ * - subtable entries, subtable size (may contain offsets/ids, cues, etc)
+ * - extra data per codec (ex. XMA header in some versions) */
+ //todo skip tables when getting extradata
+ ;VGM_LOG("BAO header at %lx\n", offset);
+
+ switch(bao_version) {
+
+ case 0x001F0011: /* Naruto: The Broken Bond (X360)-pk */
+ case 0x0022000D: /* Just Dance (Wii)-pk */
+ bao->stream_size = read_32bit(offset+header_size+0x08, streamFile);
+ bao->stream_id = read_32bit(offset+header_size+0x1c, streamFile);
+ bao->is_external = read_32bit(offset+header_size+0x28, streamFile); /* maybe 0x30 */
+ bao->channels = read_32bit(offset+header_size+0x44, streamFile);
+ bao->sample_rate = read_32bit(offset+header_size+0x4c, streamFile);
+ bao->num_samples = read_32bit(offset+header_size+0x54, streamFile);
+ bao->header_codec = read_32bit(offset+header_size+0x64, streamFile);
+
+ switch(bao->header_codec) {
+ case 0x01: bao->codec = RAW_PCM; break;
+ case 0x05: bao->codec = RAW_XMA1; break;
+ case 0x09: bao->codec = RAW_DSP; break;
+ default: VGM_LOG("UBI BAO: unknown codec at %lx\n", offset); goto fail;
+ }
+
+ //todo use flags?
+ if (bao->header_codec == 0x09) {
+ bao->extradata_offset = offset+header_size+0x80; /* mini DSP header */
+ }
+ if (bao->header_codec == 0x05 && !bao->is_external) {
+ bao->extradata_offset = offset+header_size + 0x7c; /* XMA header */
+ }
+ //todo external XMA may use blocked layout + layered layout
+
+ break;
+
+ case 0x00220015: /* James Cameron's Avatar: The Game (PSP)-pk */
+ case 0x0022001E: /* Prince of Persia: The Forgotten Sands (PSP)-pk */
+ bao->stream_size = read_32bit(offset+header_size+0x08, streamFile);
+ bao->stream_id = read_32bit(offset+header_size+0x1c, streamFile);
+ bao->is_external = read_32bit(offset+header_size+0x20, streamFile) & 0x04;
+ bao->channels = read_32bit(offset+header_size+0x28, streamFile);
+ bao->sample_rate = read_32bit(offset+header_size+0x30, streamFile);
+ if (read_32bit(offset+header_size+0x20, streamFile) & 0x20) {
+ bao->num_samples = read_32bit(offset+header_size+0x40, streamFile);
+ }
+ else {
+ bao->num_samples = read_32bit(offset+header_size+0x38, streamFile); /* from "fact" if AT3 */
+ }
+ bao->header_codec = read_32bit(offset+header_size+0x48, streamFile);
+
+ switch(bao->header_codec) {
+ case 0x06: bao->codec = RAW_PSX; break;
+ case 0x07: bao->codec = FMT_AT3; break;
+ default: VGM_LOG("UBI BAO: unknown codec at %lx\n", offset); goto fail;
+ }
+
+ if (read_32bit(offset+header_size+0x20, streamFile) & 0x10) {
+ VGM_LOG("UBI BAO: possible full loop at %lx\n", offset);
+ /* RIFFs may have "smpl" and this flag, even when data shouldn't loop... */
+ }
+
+ break;
+
+ case 0x00250108: /* Scott Pilgrim vs the World (PS3/X360)-pk */
+ case 0x0025010A: /* Prince of Persia: The Forgotten Sands (PS3/X360)-file */
+ bao->stream_size = read_32bit(offset+header_size+0x08, streamFile);
+ bao->stream_id = read_32bit(offset+header_size+0x24, streamFile);
+ bao->is_external = read_32bit(offset+header_size+0x30, streamFile);
+ bao->channels = read_32bit(offset+header_size+0x48, streamFile);
+ bao->sample_rate = read_32bit(offset+header_size+0x50, streamFile);
+ if (read_32bit(offset+header_size+0x38, streamFile) & 0x01) { /* single flag? */
+ bao->num_samples = read_32bit(offset+header_size+0x60, streamFile);
+ }
+ else {
+ bao->num_samples = read_32bit(offset+header_size+0x58, streamFile);
+ }
+ bao->header_codec = read_32bit(offset+header_size+0x68, streamFile);
+ /* when is internal+external (flag 0x2c?), 0xa0: internal data size */
+
+ switch(bao->header_codec) {
+ case 0x01: bao->codec = RAW_PCM; break;
+ case 0x04: bao->codec = RAW_XMA2; break;
+ case 0x05: bao->codec = RAW_PSX; break;
+ case 0x06: bao->codec = RAW_AT3; break;
+ default: VGM_LOG("UBI BAO: unknown codec at %lx\n", offset); goto fail;
+ }
+
+ if (bao->header_codec == 0x04 && !bao->is_external) {
+ bao->extradata_offset = offset+header_size + 0x8c; /* XMA header */
+ }
+
+ break;
+
+ case 0x001B0100: /* Assassin's Creed (PS3/X360/PC)-file */
+ case 0x001B0200: /* Beowulf (PS3)-file */
+ case 0x001F0010: /* Prince of Persia 2008 (PS3/X360)-file, Far Cry 2 (PS3)-file */
+ case 0x00280306: /* Far Cry 3: Blood Dragon (X360)-file */
+ case 0x00290106: /* Splinter Cell Blacklist? */
+ default:
+ VGM_LOG("UBI BAO: unknown BAO version at %lx\n", offset);
+ goto fail;
+ }
+
+ bao->header_size = header_size;
+
+ return 1;
+fail:
+ return 0;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_jade.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_jade.c
new file mode 100644
index 000000000..aab40b98c
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_jade.c
@@ -0,0 +1,401 @@
+#include "meta.h"
+#include "../coding/coding.h"
+
+static STREAMFILE* setup_jade_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext);
+static int get_loop_points(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end);
+
+/* Jade RIFF - from Ubisoft Jade engine games [Beyond Good & Evil (multi), Rayman Raving Rabbids 1/2 (multi)] */
+VGMSTREAM * init_vgmstream_ubi_jade(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset, first_offset = 0xc;
+ off_t fmt_offset, data_offset;
+ size_t fmt_size, data_size;
+ int loop_flag, channel_count, sample_rate, codec, block_size;
+ int loop_start = 0, loop_end = 0;
+ int is_jade_v2 = 0;
+
+
+ /* checks */
+ /* .waa: ambiances, .wam: music, .wac: sfx, .wad: dialogs (usually)
+ * .wav: Beyond Good & Evil HD (PS3), .psw: fake/badly extracted names [ex. Rayman Raving Rabbids (PS2)] */
+ if (!check_extensions(streamFile,"waa,wac,wad,wam,wav,lwav,psw"))
+ goto fail;
+
+ /* a slightly twisted RIFF with custom codecs */
+ if (read_32bitBE(0x00,streamFile) != 0x52494646 || /* "RIFF" */
+ read_32bitBE(0x08,streamFile) != 0x57415645) /* "WAVE" */
+ goto fail;
+
+ if (check_extensions(streamFile,"psw")) { /* .psw are incorrectly extracted missing 0x04 at the end */
+ if (read_32bitLE(0x04,streamFile)+0x04 != get_streamfile_size(streamFile))
+ goto fail;
+ }
+ else {
+ if (read_32bitLE(0x04,streamFile)+0x04+0x04 != get_streamfile_size(streamFile))
+ goto fail;
+ }
+
+ if (!find_chunk(streamFile, 0x666d7420,first_offset,0, &fmt_offset,&fmt_size, 0, 0)) /* "fmt " */
+ goto fail;
+ if (!find_chunk(streamFile, 0x64617461,first_offset,0, &data_offset,&data_size, 0, 0)) /* "data" */
+ goto fail;
+
+ /* ignore LyN RIFF (needed as codec 0xFFFE is reused) */
+ {
+ off_t fact_offset;
+ size_t fact_size;
+
+ if (find_chunk(streamFile, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */
+ if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, streamFile) == 0x4C794E20) /* "LyN " */
+ goto fail; /* parsed elsewhere */
+ /* Jade doesn't use "fact", though */
+ }
+ }
+
+
+ /* parse format */
+ {
+ if (fmt_size < 0x10)
+ goto fail;
+ codec = (uint16_t)read_16bitLE(fmt_offset+0x00,streamFile);
+ channel_count = read_16bitLE(fmt_offset+0x02,streamFile);
+ sample_rate = read_32bitLE(fmt_offset+0x04,streamFile);
+ block_size = (uint16_t)read_16bitLE(fmt_offset+0x0c,streamFile);
+ /* 0x08: average bytes, 0x0e: bps, etc */
+
+ /* autodetect Jade "v2", uses a different interleave [Rayman Raving Rabbids (PS2/Wii)] */
+ switch(codec) {
+ case 0xFFFF: { /* PS2 */
+ int i;
+
+ /* half interleave check as there is no flag (ends with the PS-ADPCM stop frame) */
+ for (i = 0; i < channel_count; i++) {
+ off_t end_frame = data_offset + (data_size / channel_count) * (i+1) - 0x10;
+ if (read_32bitBE(end_frame+0x00,streamFile) != 0x07007777 ||
+ read_32bitBE(end_frame+0x04,streamFile) != 0x77777777 ||
+ read_32bitBE(end_frame+0x08,streamFile) != 0x77777777 ||
+ read_32bitBE(end_frame+0x0c,streamFile) != 0x77777777) {
+ is_jade_v2 = 1;
+ break;
+ }
+ }
+ break;
+ }
+
+ case 0xFFFE: /* GC/Wii */
+ is_jade_v2 = (read_16bitLE(fmt_offset+0x10,streamFile) == 0); /* extra data size (0x2e*channels) */
+ break;
+ }
+
+ /* hopefully catches PC Rabbids */
+ if (find_chunk(streamFile, 0x63756520,first_offset,0, NULL,NULL, 0, 0)) { /* "cue " */
+ is_jade_v2 = 1;
+ }
+ }
+
+
+ /* get loop points */
+ if (is_jade_v2) {
+ loop_flag = get_loop_points(streamFile, &loop_start, &loop_end); /* loops in "LIST" */
+ }
+ else {
+ /* BG&E files don't contain looping information, so the looping is done by extension.
+ * wam and waa contain ambient sounds and music, so often they contain looped music.
+ * Later, if the file is too short looping will be disabled. */
+ loop_flag = check_extensions(streamFile,"waa,wam");
+ }
+
+ start_offset = data_offset;
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = sample_rate;
+ vgmstream->meta_type = meta_UBI_JADE;
+ if (is_jade_v2) {
+ vgmstream->loop_start_sample = loop_start;
+ vgmstream->loop_end_sample = loop_end;
+ }
+
+ switch(codec) {
+
+ case 0x0069: /* Xbox */
+ if (block_size != 0x24*channel_count)
+ goto fail;
+ vgmstream->coding_type = coding_XBOX_IMA;
+ vgmstream->layout_type = layout_none;
+
+ vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, channel_count);
+ if (!is_jade_v2) {
+ vgmstream->loop_start_sample = 0;
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+ }
+
+ break;
+
+ case 0xFFFF: /* PS2 */
+ if (block_size != 0x10)
+ goto fail;
+ vgmstream->coding_type = coding_PSX;
+ vgmstream->layout_type = layout_interleave;
+
+ if (is_jade_v2) {
+ vgmstream->interleave_block_size = 0x6400;
+ if (vgmstream->interleave_block_size)
+ vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
+ }
+ else {
+ vgmstream->interleave_block_size = data_size / channel_count;
+ }
+
+ vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
+ if (!is_jade_v2) {
+ vgmstream->loop_start_sample = 0;
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+ }
+
+ break;
+
+ case 0xFFFE: /* GC/Wii */
+ if (block_size != 0x08)
+ goto fail;
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = layout_interleave;
+
+ vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
+ if (!is_jade_v2) {
+ vgmstream->loop_start_sample = 0;
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+ }
+
+ /* coefs / interleave */
+ if (is_jade_v2) {
+ vgmstream->interleave_block_size = 0x6400;
+ if (vgmstream->interleave_block_size)
+ vgmstream->interleave_last_block_size = ((data_size % (vgmstream->interleave_block_size*vgmstream->channels))/2+7)/8*8;
+
+ {
+ static const int16_t coef[16] = { /* default Ubisoft coefs, from ELF */
+ 0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1,
+ 0x084d,0xfaa4,0x0982,0xfdf7,0x0af6,0xfafa,0x0be6,0xfbf5
+ };
+ int i, ch;
+
+ for (ch = 0; ch < channel_count; ch++) {
+ for (i = 0; i < 16; i++) {
+ vgmstream->ch[ch].adpcm_coef[i] = coef[i];
+ }
+ }
+ }
+ }
+ else {
+ /* has extra 0x2e coefs before each channel, not counted in data_size */
+ vgmstream->interleave_block_size = (data_size + 0x2e*channel_count) / channel_count;
+
+ dsp_read_coefs_be(vgmstream, streamFile, start_offset+0x00, vgmstream->interleave_block_size);
+ dsp_read_hist_be (vgmstream, streamFile, start_offset+0x20, vgmstream->interleave_block_size);
+ start_offset += 0x2e;
+ }
+ break;
+
+ case 0x0002: /* PC */
+ if (block_size != 0x24*channel_count)
+ goto fail;
+ vgmstream->coding_type = coding_MSADPCM;
+ vgmstream->layout_type = layout_none;
+ vgmstream->interleave_block_size = 0x24*channel_count;
+
+ vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, vgmstream->interleave_block_size, channel_count);
+ if (!is_jade_v2) {
+ vgmstream->loop_start_sample = 0;
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+ }
+
+ break;
+
+ case 0x0001: { /* PS3 */
+ VGMSTREAM *temp_vgmstream = NULL;
+ STREAMFILE *temp_streamFile = NULL;
+
+ if (block_size != 0x02*channel_count)
+ goto fail;
+
+ /* a MSF (usually ATRAC3) masquerading as PCM */
+ if (read_32bitBE(start_offset, streamFile) != 0x4D534643) /* "MSF\43" */
+ goto fail;
+
+ temp_streamFile = setup_jade_streamfile(streamFile, start_offset, data_size, "msf");
+ if (!temp_streamFile) goto fail;
+
+ temp_vgmstream = init_vgmstream_ps3_msf(temp_streamFile);
+ close_streamfile(temp_streamFile);
+ if (!temp_vgmstream) goto fail;
+
+ temp_vgmstream->meta_type = vgmstream->meta_type;
+ close_vgmstream(vgmstream);
+ return temp_vgmstream;
+ }
+
+ default: /* X360 uses .XMA */
+ goto fail;
+ }
+
+ /* V1 loops by extension, try to detect incorrectly looped jingles (too short) */
+ if (!is_jade_v2) {
+ if(loop_flag
+ && vgmstream->num_samples < 15*sample_rate) { /* in seconds */
+ vgmstream->loop_flag = 0;
+ }
+ }
+
+
+ if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
+ goto fail;
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+/* extract loops from "cue /LIST", returns if loops (info from Droolie) */
+static int get_loop_points(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end) {
+ off_t cue_offset, list_offset;
+ size_t cue_size, list_size;
+ off_t offset, first_offset = 0x0c;
+ int i, cue_count, loop_id = 0, loop_start = 0, loop_end = 0;
+
+
+ /* unlooped files may contain LIST, but also may not */
+ if (!find_chunk(streamFile, 0x63756520,first_offset,0, &cue_offset,&cue_size, 0, 0)) /* "cue " */
+ goto fail;
+ if (!find_chunk(streamFile, 0x4C495354,first_offset,0, &list_offset,&list_size, 0, 0)) /* "LIST" */
+ goto fail;
+
+ offset = list_offset + 0x04;
+ while (offset < list_offset + list_size) {
+ uint32_t chunk_id = read_32bitBE(offset+0x00, streamFile);
+ uint32_t chunk_size = read_32bitLE(offset+0x04, streamFile);
+ offset += 0x08;
+
+ switch(chunk_id) {
+ case 0x6C61626C: /* "labl" */
+ if (read_32bitBE(offset+0x04, streamFile) == 0x6C6F6F70) /* "loop", actually an string tho */
+ loop_id = read_32bitLE(offset+0x00, streamFile);
+ chunk_size += (chunk_size % 2) ? 1 : 0; /* string is even-padded after size */
+ break;
+ case 0x6C747874: /* "ltxt" */
+ if (loop_id == read_32bitLE(offset+0x00, streamFile))
+ loop_end = read_32bitLE(offset+0x04, streamFile);
+ break;
+
+ default:
+ VGM_LOG("Jade: unknown LIST chunk at %lx\n", offset);
+ goto fail;
+ }
+
+ offset += chunk_size;
+ }
+
+ if (!loop_end)
+ return 0;
+
+ cue_count = read_32bitLE(cue_offset+0x00, streamFile);
+ for (i = 0; i < cue_count; i++) {
+ if (loop_id == read_32bitLE(cue_offset+0x04 + i*0x18 + 0x00, streamFile)) {
+ loop_start = read_32bitLE(cue_offset+0x04 + i*0x18 + 0x04, streamFile);
+ loop_end += loop_start;
+ break;
+ }
+ }
+
+ *out_loop_start = loop_start;
+ *out_loop_end = loop_end;
+ return 1;
+
+fail:
+ return 0;
+}
+
+
+/* Jade RIFF in containers */
+VGMSTREAM * init_vgmstream_ubi_jade_container(STREAMFILE *streamFile) {
+ VGMSTREAM *vgmstream = NULL;
+ STREAMFILE *temp_streamFile = NULL;
+ off_t subfile_offset;
+ size_t subfile_size;
+
+ /* Jade packs files in bigfiles, and once extracted the sound files have extra engine data before
+ * the RIFF + padding after. Most extractors don't remove the padding correctly, so here we add support. */
+
+ /* checks */
+ /* standard Jade exts + .xma for padded XMA used in Beyond Good & Evil HD (X360) */
+ if (!check_extensions(streamFile,"waa,wac,wad,wam,wav,lwav,xma"))
+ goto fail;
+
+ if (read_32bitBE(0x04,streamFile) == 0x52494646 &&
+ read_32bitLE(0x00,streamFile)+0x04 == get_streamfile_size(streamFile)) {
+ /* data size + RIFF + padding */
+ subfile_offset = 0x04;
+ }
+ else if (read_32bitBE(0x00,streamFile) == 0x52494646 &&
+ read_32bitLE(0x04,streamFile)+0x04+0x04 < get_streamfile_size(streamFile) &&
+ (get_streamfile_size(streamFile) + 0x04) % 0x800 == 0) {
+ /* RIFF + padding with data size removed (bad extraction) */
+ subfile_offset = 0x00;
+ }
+ else if (read_32bitBE(0x04,streamFile) == 0x52494646 &&
+ read_32bitLE(0x00,streamFile) == get_streamfile_size(streamFile)) {
+ /* data_size + RIFF + padding - 0x04 (bad extraction) */
+ subfile_offset = 0x04;
+ }
+ else {
+ goto fail;
+ }
+
+ subfile_size = read_32bitLE(subfile_offset+0x04,streamFile) + 0x04+0x04;
+
+ temp_streamFile = setup_jade_streamfile(streamFile, subfile_offset,subfile_size, NULL);
+ if (!temp_streamFile) goto fail;
+
+ if (check_extensions(streamFile,"xma")) {
+ vgmstream = init_vgmstream_xma(temp_streamFile);
+ } else {
+ vgmstream = init_vgmstream_ubi_jade(temp_streamFile);
+ }
+
+ close_streamfile(temp_streamFile);
+ return vgmstream;
+
+fail:
+ close_streamfile(temp_streamFile);
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+static STREAMFILE* setup_jade_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext) {
+ STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
+
+ /* setup subfile */
+ new_streamFile = open_wrap_streamfile(streamFile);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ if (fake_ext) {
+ new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,fake_ext);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+ }
+
+ return temp_streamFile;
+
+fail:
+ close_streamfile(temp_streamFile);
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_lyn.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_lyn.c
new file mode 100644
index 000000000..77c714a16
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_lyn.c
@@ -0,0 +1,293 @@
+#include "meta.h"
+#include "../layout/layout.h"
+#include "../coding/coding.h"
+#include "ubi_lyn_ogg_streamfile.h"
+
+static STREAMFILE* setup_lyn_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size);
+
+/* LyN RIFF - from Ubisoft LyN engine games [Red Steel 2 (Wii), Adventures of Tintin (Multi), From Dust (Multi), Just Dance 3/4 (multi)] */
+VGMSTREAM * init_vgmstream_ubi_lyn(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset, first_offset = 0xc;
+ off_t fmt_offset, data_offset, fact_offset;
+ size_t fmt_size, data_size, fact_size;
+ int loop_flag, channel_count, sample_rate, codec;
+ int num_samples;
+
+
+ /* checks */
+ /* .sns: Red Steel 2, .wav: Tintin, .son: From Dust */
+ if (!check_extensions(streamFile,"sns,wav,lwav,son"))
+ goto fail;
+
+ /* a slightly eccentric RIFF with custom codecs */
+ if (read_32bitBE(0x00,streamFile) != 0x52494646 || /* "RIFF" */
+ read_32bitBE(0x08,streamFile) != 0x57415645) /* "WAVE" */
+ goto fail;
+ if (read_32bitLE(0x04,streamFile)+0x04+0x04 != get_streamfile_size(streamFile))
+ goto fail;
+
+ if (!find_chunk(streamFile, 0x666d7420,first_offset,0, &fmt_offset,&fmt_size, 0, 0)) /* "fmt " */
+ goto fail;
+ if (!find_chunk(streamFile, 0x64617461,first_offset,0, &data_offset,&data_size, 0, 0)) /* "data" */
+ goto fail;
+
+ /* always found, even with PCM (LyN subchunk seems to contain the engine version, ex. 0x0d/10) */
+ if (!find_chunk(streamFile, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) /* "fact" */
+ goto fail;
+ if (fact_size != 0x10 || read_32bitBE(fact_offset+0x04, streamFile) != 0x4C794E20) /* "LyN " */
+ goto fail;
+ num_samples = read_32bitLE(fact_offset+0x00, streamFile);
+ /* sometimes there is a LySE chunk */
+
+
+ /* parse format */
+ {
+ if (fmt_size < 0x12)
+ goto fail;
+ codec = (uint16_t)read_16bitLE(fmt_offset+0x00,streamFile);
+ channel_count = read_16bitLE(fmt_offset+0x02,streamFile);
+ sample_rate = read_32bitLE(fmt_offset+0x04,streamFile);
+ /* 0x08: average bytes, 0x0c: block align, 0x0e: bps, etc */
+
+ /* fake WAVEFORMATEX, used with > 2ch */
+ if (codec == 0xFFFE) {
+ if (fmt_size < 0x28)
+ goto fail;
+ /* fake GUID with first value doubling as codec */
+ codec = read_32bitLE(fmt_offset+0x18,streamFile);
+ if (read_32bitBE(fmt_offset+0x1c,streamFile) != 0x00001000 &&
+ read_32bitBE(fmt_offset+0x20,streamFile) != 0x800000AA &&
+ read_32bitBE(fmt_offset+0x24,streamFile) != 0x00389B71) {
+ goto fail;
+ }
+ }
+ }
+
+ /* most songs simply repeat, loop if it looks long enough */
+ loop_flag = (num_samples > 20*sample_rate); /* in seconds */
+ start_offset = data_offset;
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count,loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = sample_rate;
+ vgmstream->meta_type = meta_UBI_LYN;
+ vgmstream->num_samples = num_samples;
+ vgmstream->loop_start_sample = 0;
+ vgmstream->loop_end_sample = vgmstream->num_samples;
+
+ switch(codec) {
+ case 0x0001: /* PCM */
+ vgmstream->coding_type = coding_PCM16LE; /* LE even in X360 */
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x02;
+ break;
+
+ case 0x5050: /* DSP (Wii) */
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = 0x08;
+
+ /* setup default Ubisoft coefs */
+ {
+ static const int16_t coef[16] = {
+ 0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1,
+ 0x084d,0xfaa4,0x0982,0xfdf7,0x0af6,0xfafa,0x0be6,0xfbf5
+ };
+ int i, ch;
+
+ for (ch = 0; ch < channel_count; ch++) {
+ for (i = 0; i < 16; i++) {
+ vgmstream->ch[ch].adpcm_coef[i] = coef[i];
+ }
+ }
+ }
+
+ break;
+
+#ifdef VGM_USE_VORBIS
+ case 0x3157: { /* Ogg (PC), interleaved 1ch */
+ size_t interleave_size, stride_size;
+ layered_layout_data* data = NULL;
+ int i;
+
+ if (read_32bitLE(start_offset+0x00,streamFile) != 1) /* id? */
+ goto fail;
+
+ interleave_size = read_32bitLE(start_offset+0x04,streamFile);
+ stride_size = interleave_size * channel_count;
+ /* interleave is adjusted so there is no smaller last block, it seems */
+
+ vgmstream->coding_type = coding_OGG_VORBIS;
+ vgmstream->layout_type = layout_layered;
+
+ /* init layout */
+ data = init_layout_layered(channel_count);
+ if (!data) goto fail;
+ vgmstream->layout_data = data;
+
+ /* open each layer subfile */
+ for (i = 0; i < channel_count; i++) {
+ STREAMFILE* temp_streamFile = NULL;
+ size_t total_size = read_32bitLE(start_offset+0x08 + 0x04*i,streamFile);
+ off_t layer_offset = start_offset+0x08 + 0x04*channel_count + interleave_size*i;
+
+ temp_streamFile = setup_lyn_ogg_streamfile(streamFile, layer_offset, interleave_size, stride_size, total_size);
+ if (!temp_streamFile) goto fail;
+
+ data->layers[i] = init_vgmstream_ogg_vorbis(temp_streamFile);
+ close_streamfile(temp_streamFile);
+ if (!data->layers[i]) goto fail;
+
+ /* could validate between layers, meh */
+ }
+
+ /* setup layered VGMSTREAMs */
+ if (!setup_layout_layered(data))
+ goto fail;
+
+ break;
+ }
+#endif
+
+#ifdef VGM_USE_MPEG
+ case 0x5051: { /* MPEG (PS3/PC), interleaved 1ch */
+ mpeg_codec_data *mpeg_data = NULL;
+ mpeg_custom_config cfg = {0};
+ int i;
+
+ if (read_32bitLE(start_offset+0x00,streamFile) != 2) /* id? */
+ goto fail;
+
+ cfg.interleave = read_32bitLE(start_offset+0x04,streamFile);
+ cfg.chunk_size = read_32bitLE(start_offset+0x08,streamFile);
+ /* 0x08: frame size, 0x0c: frame per interleave, 0x10: samples per frame */
+
+ /* skip seek tables and find actual start */
+ start_offset += 0x14;
+ data_size -= 0x14;
+ for (i = 0; i < channel_count; i++) {
+ int entries = read_32bitLE(start_offset,streamFile);
+
+ start_offset += 0x04 + entries*0x08;
+ data_size -= 0x04 + entries*0x08;
+ }
+
+ cfg.data_size = data_size;
+
+ //todo data parsing looks correct but some files decode a bit wrong at the end (ex. Tintin: Music~Boss~Allan~Victory~02)
+ mpeg_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_LYN, &cfg);
+ if (!mpeg_data) goto fail;
+ vgmstream->codec_data = mpeg_data;
+ vgmstream->layout_type = layout_none;
+
+ break;
+ }
+#endif
+
+#ifdef VGM_USE_FFMPEG
+ case 0x0166: { /* XMA (X360), standard */
+ uint8_t buf[0x100];
+ int bytes;
+ off_t chunk_offset;
+ size_t chunk_size, seek_size;
+
+ if (read_32bitLE(start_offset+0x00,streamFile) != 3) /* id? */
+ goto fail;
+
+ /* skip standard XMA header + seek table */
+ chunk_offset = start_offset + 0x04 + 0x04;
+ chunk_size = read_32bitLE(start_offset + 0x04, streamFile);
+ seek_size = read_32bitLE(chunk_offset+chunk_size, streamFile);
+ start_offset += (0x04 + 0x04 + chunk_size + 0x04 + seek_size);
+ data_size -= (0x04 + 0x04 + chunk_size + 0x04 + seek_size);
+
+ bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, chunk_offset,chunk_size, data_size, streamFile, 1);
+ vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
+ if ( !vgmstream->codec_data ) goto fail;
+ vgmstream->coding_type = coding_FFmpeg;
+ vgmstream->layout_type = layout_none;
+
+ break;
+ }
+#endif
+
+ default:
+ goto fail;
+ }
+
+
+ if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
+ goto fail;
+ return vgmstream;
+
+fail:
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+
+/* LyN RIFF in containers */
+VGMSTREAM * init_vgmstream_ubi_lyn_container(STREAMFILE *streamFile) {
+ VGMSTREAM *vgmstream = NULL;
+ STREAMFILE *temp_streamFile = NULL;
+ off_t subfile_offset;
+ size_t subfile_size;
+
+ /* LyN packs files in bigfiles, and once extracted the sound files have extra engine
+ * data before the RIFF. Might as well support them in case the RIFF wasn't extracted. */
+
+ /* checks */
+ if (!check_extensions(streamFile,"sns,wav,lwav,son"))
+ goto fail;
+
+ /* find "RIFF" position */
+ if (read_32bitBE(0x00,streamFile) == 0x4C795345 && /* "LySE" */
+ read_32bitBE(0x14,streamFile) == 0x52494646) { /* "RIFF" */
+ subfile_offset = 0x14; /* Adventures of Tintin */
+ }
+ else if (read_32bitLE(0x00,streamFile)+0x20 == get_streamfile_size(streamFile) &&
+ read_32bitBE(0x20,streamFile) == 0x52494646) { /* "RIFF" */
+ subfile_offset = 0x20; /* Red Steel 2, From Dust */
+ }
+ else {
+ goto fail;
+ }
+
+ subfile_size = read_32bitLE(subfile_offset+0x04,streamFile) + 0x04+0x04;
+
+ temp_streamFile = setup_lyn_streamfile(streamFile, subfile_offset,subfile_size);
+ if (!temp_streamFile) goto fail;
+
+ vgmstream = init_vgmstream_ubi_lyn(temp_streamFile);
+
+ close_streamfile(temp_streamFile);
+ return vgmstream;
+
+fail:
+ close_streamfile(temp_streamFile);
+ close_vgmstream(vgmstream);
+ return NULL;
+}
+
+static STREAMFILE* setup_lyn_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size) {
+ STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
+
+ /* setup subfile */
+ new_streamFile = open_wrap_streamfile(streamFile);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ return temp_streamFile;
+
+fail:
+ close_streamfile(temp_streamFile);
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_lyn_ogg_streamfile.h b/Frameworks/vgmstream/vgmstream/src/meta/ubi_lyn_ogg_streamfile.h
new file mode 100644
index 000000000..aeec84f87
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_lyn_ogg_streamfile.h
@@ -0,0 +1,92 @@
+#ifndef _LYN_OGG_STREAMFILE_H_
+#define _LYN_OGG_STREAMFILE_H_
+#include "../streamfile.h"
+
+
+typedef struct {
+ off_t start_physical_offset; /* interleaved data start, for this substream */
+ size_t interleave_block_size; /* max size that can be read before encountering other substreams */
+ size_t stride_size; /* step size between interleave blocks (interleave*channels) */
+ size_t total_size; /* final size of the deinterleaved substream */
+} lyn_ogg_io_data;
+
+
+/* Handles deinterleaving of complete files, skipping portions or other substreams. */
+static size_t scd_dsp_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, lyn_ogg_io_data* data) {
+ size_t total_read = 0;
+
+ while (length > 0) {
+ size_t to_read;
+ size_t length_available;
+ off_t block_num;
+ off_t intrablock_offset;
+ off_t physical_offset;
+
+ block_num = offset / data->interleave_block_size;
+ intrablock_offset = offset % data->interleave_block_size;
+ physical_offset = data->start_physical_offset + block_num*data->stride_size + intrablock_offset;
+ length_available = data->interleave_block_size - intrablock_offset;
+
+ if (length < length_available) {
+ to_read = length;
+ }
+ else {
+ to_read = length_available;
+ }
+
+ if (to_read > 0) {
+ size_t bytes_read;
+
+ bytes_read = read_streamfile(dest, physical_offset, to_read, streamfile);
+ total_read += bytes_read;
+
+ if (bytes_read != to_read) {
+ return total_read;
+ }
+
+ dest += bytes_read;
+ offset += bytes_read;
+ length -= bytes_read;
+ }
+ }
+
+ return total_read;
+}
+
+static size_t scd_dsp_io_size(STREAMFILE *streamfile, lyn_ogg_io_data* data) {
+ return data->total_size;
+}
+
+
+static STREAMFILE* setup_lyn_ogg_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t interleave_block_size, size_t stride_size, size_t total_size) {
+ STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
+ lyn_ogg_io_data io_data = {0};
+ size_t io_data_size = sizeof(lyn_ogg_io_data);
+
+ io_data.start_physical_offset = start_offset;
+ io_data.interleave_block_size = interleave_block_size;
+ io_data.stride_size = stride_size;
+ io_data.total_size = total_size;
+
+
+ /* setup subfile */
+ new_streamFile = open_wrap_streamfile(streamFile);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, scd_dsp_io_read,scd_dsp_io_size);
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"ogg");
+ if (!new_streamFile) goto fail;
+ temp_streamFile = new_streamFile;
+
+ return temp_streamFile;
+
+fail:
+ close_streamfile(temp_streamFile);
+ return NULL;
+}
+
+#endif /* _LYN_OGG_STREAMFILE_H_ */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c
index ad0d9abb0..5b9c33395 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c
@@ -90,7 +90,7 @@ VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE *streamFile) {
if (sb.autodetect_external) { /* works most of the time but could give false positives */
VGM_LOG("UBI SB: autodetecting external stream '%s'\n", sb.stream_name);
- streamData = open_stream_name(streamFile,sb.stream_name);
+ streamData = open_streamfile_by_filename(streamFile,sb.stream_name);
if (!streamData) {
streamData = streamFile; /* assume internal */
if (sb.stream_size > get_streamfile_size(streamData)) {
@@ -102,7 +102,7 @@ VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE *streamFile) {
}
}
else if (sb.is_external) {
- streamData = open_stream_name(streamFile,sb.stream_name);
+ streamData = open_streamfile_by_filename(streamFile,sb.stream_name);
if (!streamData) {
VGM_LOG("UBI SB: external stream '%s' not found\n", sb.stream_name);
goto fail;
@@ -674,7 +674,7 @@ static int config_sb_header_version(ubi_sb_header * sb, STREAMFILE *streamFile)
/* two games with same id; use project file as identifier */
if (sb->version == 0x0012000C && is_sb4) {
- STREAMFILE * streamTest = open_stream_name(streamFile, "BIAAUDIO.SP4");
+ STREAMFILE * streamTest = open_streamfile_by_filename(streamFile, "BIAAUDIO.SP4");
if (streamTest) {
is_biadd_psp = 1;
close_streamfile(streamTest);
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/vs.c b/Frameworks/vgmstream/vgmstream/src/meta/vs.c
index 9fe5ec34b..0e7aa209a 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/vs.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/vs.c
@@ -42,7 +42,7 @@ VGMSTREAM * init_vgmstream_vs(STREAMFILE *streamFile) {
}
#endif
- vgmstream->layout_type = layout_vs_blocked;
+ vgmstream->layout_type = layout_blocked_vs;
vgmstream->meta_type = meta_VS;
@@ -55,15 +55,15 @@ VGMSTREAM * init_vgmstream_vs(STREAMFILE *streamFile) {
}
/* Calc num_samples */
- vs_block_update(start_offset,vgmstream);
+ block_update_vs(start_offset,vgmstream);
vgmstream->num_samples=0;
do {
vgmstream->num_samples += vgmstream->current_block_size*28/16;
- vs_block_update(vgmstream->next_block_offset,vgmstream);
+ block_update_vs(vgmstream->next_block_offset,vgmstream);
} while (vgmstream->next_block_offsetget_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("vsf",filename_extension(filename))) goto fail;
+ if (!check_extensions(streamFile, "vsf"))
+ goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x56534600) /* "VSF" */
goto fail;
loop_flag = (read_32bitLE(0x1c,streamFile)==0x13);
- if(read_32bitLE(0x8,streamFile)==0x0)
- channel_count = 1;
- else
- channel_count = 2;
+ if(read_8bit(0x1C,streamFile)==0x0)
+ channel_count = 1;
+ else
+ channel_count = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
@@ -44,25 +41,12 @@ VGMSTREAM * init_vgmstream_ps2_vsf(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_PS2_VSF;
/* open the file for reading */
- {
- int i;
- STREAMFILE * file;
- file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (!file) goto fail;
- for (i=0;ich[i].streamfile = file;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=start_offset+
- vgmstream->interleave_block_size*i;
-
- }
- }
-
+ if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
+ goto fail;
return vgmstream;
/* clean up anything we may have opened */
fail:
- if (vgmstream) close_vgmstream(vgmstream);
+ close_vgmstream(vgmstream);
return NULL;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/waa_wac_wad_wam.c b/Frameworks/vgmstream/vgmstream/src/meta/waa_wac_wad_wam.c
deleted file mode 100644
index 0b7b50d4e..000000000
--- a/Frameworks/vgmstream/vgmstream/src/meta/waa_wac_wad_wam.c
+++ /dev/null
@@ -1,182 +0,0 @@
-#include "meta.h"
-#include "../coding/coding.h"
-
-/*
-const short wad_coef[16][2] =
-{
- {0x4002,0x2003},
- {0x2016,0xc600},
- {0xC600,0x98ab},
- {0x96bf,0x29c5},
- {0x2003,0x0081},
- {0x0e00,0x2004},
- {0x8e01,0xc500},
- {0x70bf,0x8128},
- {0x288e,0xc600},
- {0x016e,0x0e5b},
- {0xbe20,0x2003},
- {0x03c6,0xc600},
- {0x0048,0xe85a},
- {0xbe28,0x28c6},
- {0xc600,0x00F6},
- {0xbeab,0x5520}
-};*/
-const short wad_coef[16] =
-{
- 0x04ab, 0xfced,
- 0x0789, 0xfedf,
- 0x09a2, 0xfae5,
- 0x0c90, 0xfac1,
- 0x084d, 0xfaa4,
- 0x0982, 0xfdf7,
- 0x0af6, 0xfafa,
- 0x0be6, 0xfbf5
-};
-
-
-/* WAC/WAD/WAM/WAA - from Beyond Good & Evil (PS2/Xbox/GC/Wii) */
-VGMSTREAM * init_vgmstream_waa_wac_wad_wam(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
- int i;
- off_t start_offset;
- int loop_flag;
- int channel_count;
- int coef1_start;
- int coef2_start;
- int second_channel_start = -1;
-
- // Check file extensions
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("waa",filename_extension(filename)) &&
- strcasecmp("wac",filename_extension(filename)) &&
- strcasecmp("wad",filename_extension(filename)) &&
- strcasecmp("wam",filename_extension(filename))) goto fail;
-
- /* check header */
- if (read_32bitBE(0x00,streamFile) != 0x52494646 || /* "RIFF" */
- read_32bitBE(0x08,streamFile) != 0x57415645 || /* "WAVE" */
- read_32bitBE(0x0C,streamFile) != 0x666D7420 || /* "fmt " */
- read_32bitBE(0x10,streamFile) != 0x12000000) /* "0x12000000" */
- goto fail;
-
- /* files don't contain looping information,
- so the looping is not done depending on extension.
- wam and waa contain ambient sounds and music, so often they contain
- looped music. Change extension to wac or wad to make the sound non-looping.
- */
- loop_flag = strcasecmp("wac",filename_extension(filename)) &&
- strcasecmp("wad",filename_extension(filename));
- channel_count = (uint16_t)read_16bitLE(0x16,streamFile);
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(channel_count,loop_flag);
- if (!vgmstream) goto fail;
-
- /* Check what encoder is needed */
- //FIXME: //PC version uses pcm, but which encoder?
-
- vgmstream->channels = channel_count;
- vgmstream->sample_rate = read_32bitLE(0x18,streamFile);
- vgmstream->meta_type = meta_WAA_WAC_WAD_WAM;
- vgmstream->layout_type = layout_none;
-
- switch((uint16_t)read_16bitLE(0x14,streamFile)) {
- case 0x0069: // XBOX IMA ADPCM
- start_offset = 0x2E;
- vgmstream->coding_type = coding_XBOX_IMA;
- vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bitLE(0x2A,streamFile), channel_count);
- if (loop_flag) {
- vgmstream->loop_start_sample = 0;
- vgmstream->loop_end_sample = xbox_ima_bytes_to_samples(read_32bitLE(0x2A,streamFile),channel_count);
- }
- break;
- case 0xFFFF: // PS2 ADPCM
- start_offset = 0x2E;
- vgmstream->coding_type = coding_PSX;
- vgmstream->num_samples = (read_32bitLE(0x2A,streamFile))/16*28/channel_count;
- if (loop_flag) {
- vgmstream->loop_start_sample = 0;
- vgmstream->loop_end_sample = (read_32bitLE(0x2A,streamFile))/16*28/channel_count;
- }
- second_channel_start = (read_32bitLE(0x2A,streamFile)/2)+start_offset;
- break;
- case 0xFFFE: // GameCube/WII DSP
- start_offset = 0x5C;
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->num_samples = (read_32bitLE(0x2A,streamFile))*14/8/channel_count;
- if (loop_flag) {
- vgmstream->loop_start_sample = 0;
- vgmstream->loop_end_sample = (read_32bitLE(0x2A,streamFile))*14/8/channel_count;
- }
- if(read_16bitLE(0x24,streamFile)==0x00)//is a wii file with no coeff table
- {
- //FIXME: WII version of WAM/WAD/WAC need some coeff table from somewhere
- for (i=0;i<16;i++)
- vgmstream->ch[0].adpcm_coef[i] = wad_coef[i];
- if (channel_count == 2) {
- for (i=0;i<16;i++)
- vgmstream->ch[1].adpcm_coef[i] = wad_coef[i];
- }
- goto fail;
- }
- else
- {
- second_channel_start = (read_32bitLE(0x2A,streamFile)/2)+0x8A;
- /* Retrieveing the coef tables */
- coef1_start = 0x2E;
- coef2_start = (read_32bitLE(0x2A,streamFile)/2)+0x5C;
-
- {
- int i;
- for (i=0;i<16;i++)
- vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(coef1_start+i*2,streamFile);
- if (channel_count == 2) {
- for (i=0;i<16;i++)
- vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(coef2_start+i*2,streamFile);
- }
- }
- }
- break;
- default:
- goto fail;
- }
-
-
-
-
- /* 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;
-
- if (vgmstream->coding_type == coding_XBOX_IMA) {
- /* xbox interleaving is a little odd */
- vgmstream->ch[i].channel_start_offset=start_offset;
- } else {
- vgmstream->ch[0].channel_start_offset=start_offset;
- if (channel_count == 2) {
- if (second_channel_start == -1) goto fail;
- vgmstream->ch[1].channel_start_offset=second_channel_start;
- }
- }
- vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset;
- }
- }
-
-
- 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/waf.c b/Frameworks/vgmstream/vgmstream/src/meta/waf.c
new file mode 100644
index 000000000..dbb944eda
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/waf.c
@@ -0,0 +1,43 @@
+#include "meta.h"
+#include "../coding/coding.h"
+
+/* WAF - KID's earlier PC games [ever17 (PC)] (for RLE-compressed WAFs see https://github.com/dsp2003/e17p) */
+VGMSTREAM * init_vgmstream_waf(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset;
+ int loop_flag, channel_count;
+
+
+ /* checks */
+ if (!check_extensions(streamFile, "waf"))
+ goto fail;
+
+ if (read_32bitBE(0x00,streamFile) != 0x57414600) /* "WAF\0" "*/
+ goto fail;
+ if (read_32bitLE(0x34,streamFile) + 0x38 != get_streamfile_size(streamFile))
+ goto fail;
+
+ channel_count = read_16bitLE(0x06,streamFile);
+ loop_flag = 0;
+ start_offset = 0x38;
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count, loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = read_32bitLE(0x08, streamFile);
+ vgmstream->meta_type = meta_WAF;
+ vgmstream->coding_type = coding_MSADPCM;
+ vgmstream->layout_type = layout_none;
+ vgmstream->interleave_block_size = read_16bitLE(0x10, streamFile);
+ vgmstream->num_samples = msadpcm_bytes_to_samples(read_32bitLE(0x34,streamFile), vgmstream->interleave_block_size, channel_count);
+ /* 0x04: null?, 0x0c: avg br, 0x12: bps, 0x14: s_p_f, 0x16~34: count + standard MSADPCM coefs (a modified RIFF fmt) */
+
+ 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/wave.c b/Frameworks/vgmstream/vgmstream/src/meta/wave.c
new file mode 100644
index 000000000..fe6c69453
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/wave.c
@@ -0,0 +1,108 @@
+#include "meta.h"
+#include "../coding/coding.h"
+
+/* .WAVE - WayForward "EngineBlack" games [Mighty Switch Force! (3DS), Adventure Time: Hey Ice King! Why'd You Steal Our Garbage?! (3DS)] */
+VGMSTREAM * init_vgmstream_wave(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t start_offset, extradata_offset;
+ int loop_flag = 0, channel_count, sample_rate, codec;
+ int32_t num_samples, loop_start = 0, loop_end = 0;
+ size_t interleave;
+
+ int big_endian;
+ int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
+ //int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
+
+ /* checks */
+ if (!check_extensions(streamFile, "wave"))
+ goto fail;
+
+ if (read_32bitLE(0x00,streamFile) != 0xE5B7ECFE && /* header id */
+ read_32bitBE(0x00,streamFile) != 0xE5B7ECFE)
+ goto fail;
+ if (read_32bitBE(0x04,streamFile) != 0x00) /* version? */
+ goto fail;
+
+ /* assumed */
+ big_endian = read_32bitBE(0x00,streamFile) == 0xE5B7ECFE;
+ if (big_endian) {
+ read_32bit = read_32bitBE;
+ //read_16bit = read_16bitBE;
+ } else {
+ read_32bit = read_32bitLE;
+ //read_16bit = read_16bitLE;
+ }
+
+ channel_count = read_8bit(0x05,streamFile);
+
+ if (read_32bit(0x08,streamFile) != get_streamfile_size(streamFile))
+ goto fail;
+ if (read_8bit(0x0c,streamFile) != 0x00) /* ? */
+ goto fail;
+
+ /* sample rate in 32b float (WHY?)*/
+ {
+ uint32_t sample_int = (uint32_t)read_32bit(0x0c, streamFile);
+ float* sample_float;
+ sample_float = (float*)&sample_int;
+
+ sample_rate = (int)(*sample_float);
+ }
+
+ num_samples = read_32bit(0x10, streamFile);
+ loop_start = read_32bit(0x14, streamFile);
+ loop_end = read_32bit(0x18, streamFile);
+
+ codec = read_8bit(0x1c, streamFile);
+ channel_count = read_8bit(0x1d, streamFile);
+ if (read_8bit(0x1e, streamFile) != 0x00) goto fail; /* unknown */
+ if (read_8bit(0x1f, streamFile) != 0x00) goto fail; /* unknown */
+
+ start_offset = read_32bit(0x20, streamFile);
+ interleave = read_32bit(0x24, streamFile); /* typically half data_size */
+ extradata_offset = read_32bit(0x28, streamFile); /* OR: extradata size (0x2c) */
+
+ loop_flag = (loop_start > 0);
+ /* some songs (ex. Adventure Time's m_candykingdom_overworld.wave) do full loops, but there is no way
+ * to tell them apart from sfx/voices, so we try to detect if it's long enough. */
+ if(!loop_flag
+ && loop_start == 0 && loop_end == num_samples /* full loop */
+ && channel_count > 1
+ && num_samples > 20*sample_rate) { /* in seconds */
+ loop_flag = 1;
+ }
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count, loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = sample_rate;
+ vgmstream->num_samples = num_samples;
+ vgmstream->loop_start_sample = loop_start;
+ vgmstream->loop_end_sample = loop_end;
+
+ vgmstream->meta_type = meta_WAVE;
+ /* not sure if there are other codecs but anyway */
+ switch(codec) {
+ case 0x02:
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = interleave;
+
+ /* ADPCM setup: 0x20 coefs + 0x06 initial ps/hist1/hist2 + 0x06 loop ps/hist1/hist2, per channel */
+ dsp_read_coefs(vgmstream, streamFile, extradata_offset+0x00, 0x2c, big_endian);
+ dsp_read_hist(vgmstream, streamFile, extradata_offset+0x22, 0x2c, big_endian);
+ break;
+ default:
+ goto fail;
+ }
+
+ 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/wave_segmented.c b/Frameworks/vgmstream/vgmstream/src/meta/wave_segmented.c
new file mode 100644
index 000000000..a4af548c3
--- /dev/null
+++ b/Frameworks/vgmstream/vgmstream/src/meta/wave_segmented.c
@@ -0,0 +1,219 @@
+#include "meta.h"
+#include "../coding/coding.h"
+#include "../layout/layout.h"
+
+#define MAX_SEGMENTS 4
+
+/* .WAVE - "EngineBlack" games, segmented [Shantae and the Pirate's Curse (PC/3DS), TMNT: Danger of the Ooze (PS3/3DS)] */
+VGMSTREAM * init_vgmstream_wave_segmented(STREAMFILE *streamFile) {
+ VGMSTREAM * vgmstream = NULL;
+ off_t segments_offset;
+ int loop_flag = 0, channel_count, sample_rate;
+ int32_t num_samples, loop_start_sample = 0, loop_end_sample = 0;
+
+ segmented_layout_data *data = NULL;
+ int segment_count, loop_start_segment = 0, loop_end_segment = 0;
+
+ int big_endian;
+ int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
+ int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
+
+
+ /* checks */
+ if (!check_extensions(streamFile, "wave"))
+ goto fail;
+
+ if (read_32bitLE(0x00,streamFile) != 0x4DF72D4A && /* header id */
+ read_32bitBE(0x00,streamFile) != 0x4DF72D4A)
+ goto fail;
+ if (read_8bit(0x04,streamFile) != 0x01) /* version? */
+ goto fail;
+
+ /* PS3/X360 games */
+ big_endian = read_32bitBE(0x00,streamFile) == 0x4DF72D4A;
+ if (big_endian) {
+ read_32bit = read_32bitBE;
+ read_16bit = read_16bitBE;
+ } else {
+ read_32bit = read_32bitLE;
+ read_16bit = read_16bitLE;
+ }
+
+ channel_count = read_8bit(0x05,streamFile);
+ segment_count = read_16bit(0x06,streamFile);
+ if (segment_count > MAX_SEGMENTS || segment_count <= 0) goto fail;
+
+ loop_start_segment = read_16bit(0x08, streamFile);
+ loop_end_segment = read_16bit(0x0a, streamFile);
+ segments_offset = read_32bit(0x0c, streamFile);
+
+ sample_rate = read_32bit(0x10, streamFile);
+ num_samples = read_32bit(0x14, streamFile);
+ /* 0x18: unknown (usually 0, maybe some count) */
+
+
+ /* init layout */
+ data = init_layout_segmented(segment_count);
+ if (!data) goto fail;
+
+ /* parse segments (usually: preload + intro + loop + ending, intro/ending may be skipped)
+ * Often first segment is ADPCM and rest Ogg; may only have one segment. */
+ {
+ off_t extradata_offset, table_offset, segment_offset;
+ size_t segment_size;
+ int32_t segment_samples;
+ int codec;
+ int i, ch;
+
+ /* open each segment subfile */
+ for (i = 0; i < segment_count; i++) {
+ codec = read_8bit(segments_offset+0x10*i+0x00, streamFile);
+ /* 0x01(1): unknown (flag? usually 0x00/0x01/0x02) */
+ if (read_8bit(segments_offset+0x10*i+0x02, streamFile) != 0x01) goto fail; /* unknown */
+ if (read_8bit(segments_offset+0x10*i+0x03, streamFile) != 0x00) goto fail; /* unknown */
+
+ segment_samples = read_32bit(segments_offset+0x10*i+0x04, streamFile);
+ extradata_offset = read_32bit(segments_offset+0x10*i+0x08, streamFile);
+ table_offset = read_32bit(segments_offset+0x10*i+0x0c, streamFile);
+
+ /* create a sub-VGMSTREAM per segment
+ * (we'll reopen this streamFile as needed, so each sub-VGMSTREAM is fully independent) */
+ switch(codec) {
+ case 0x02: { /* "adpcm" */
+ data->segments[i] = allocate_vgmstream(channel_count, 0);
+ if (!data->segments[i]) goto fail;
+
+ data->segments[i]->sample_rate = sample_rate;
+ data->segments[i]->meta_type = meta_WAVE;
+ data->segments[i]->coding_type = coding_IMA_int;
+ data->segments[i]->layout_type = layout_none;
+ data->segments[i]->num_samples = segment_samples;
+
+ if (!vgmstream_open_stream(data->segments[i],streamFile,0x00))
+ goto fail;
+
+ /* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
+ for (ch = 0; ch < channel_count; ch++) {
+ segment_offset = read_32bit(table_offset + 0x04*ch, streamFile);
+ data->segments[i]->ch[ch].channel_start_offset =
+ data->segments[i]->ch[ch].offset = segment_offset;
+
+ /* ADPCM setup */
+ data->segments[i]->ch[ch].adpcm_history1_32 = read_16bit(extradata_offset+0x04*ch+0x00, streamFile);
+ data->segments[i]->ch[ch].adpcm_step_index = read_8bit(extradata_offset+0x04*ch+0x02, streamFile);
+ /* 0x03: reserved */
+ }
+
+ break;
+ }
+
+ case 0x03: { /* "dsp-adpcm" */
+ data->segments[i] = allocate_vgmstream(channel_count, 0);
+ if (!data->segments[i]) goto fail;
+
+ data->segments[i]->sample_rate = sample_rate;
+ data->segments[i]->meta_type = meta_WAVE;
+ data->segments[i]->coding_type = coding_NGC_DSP;
+ data->segments[i]->layout_type = layout_none;
+ data->segments[i]->num_samples = segment_samples;
+
+ if (!vgmstream_open_stream(data->segments[i],streamFile,0x00))
+ goto fail;
+
+ /* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
+ for (ch = 0; ch < channel_count; ch++) {
+ segment_offset = read_32bit(table_offset + 0x04*ch, streamFile);
+ data->segments[i]->ch[ch].channel_start_offset =
+ data->segments[i]->ch[ch].offset = segment_offset;
+ }
+
+ /* ADPCM setup: 0x06 initial ps/hist1/hist2 (per channel) + 0x20 coefs (per channel) */
+ dsp_read_hist(data->segments[i], streamFile, extradata_offset+0x02, 0x06, big_endian);
+ dsp_read_coefs(data->segments[i], streamFile, extradata_offset+0x06*channel_count+0x00, 0x20, big_endian);
+
+ break;
+ }
+
+ case 0x04: { /* "vorbis" */
+ ogg_vorbis_meta_info_t ovmi = {0};
+
+ segment_offset = read_32bit(table_offset, streamFile);
+ segment_size = read_32bitBE(segment_offset, streamFile); /* always BE */
+
+ ovmi.meta_type = meta_WAVE;
+ ovmi.stream_size = segment_size;
+
+ data->segments[i] = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, segment_offset+0x04, &ovmi);
+ if (!data->segments[i]) goto fail;
+
+ if (data->segments[i]->num_samples != segment_samples) {
+ VGM_LOG("WAVE: segment %i samples != num_samples\n", i);
+ goto fail;
+ }
+
+ break;
+ }
+
+ default: /* others: s16be/s16le/mp3 as referenced in the exe? */
+ VGM_LOG("WAVE: unknown codec\n");
+ goto fail;
+ }
+ }
+ }
+
+ /* setup segmented VGMSTREAMs */
+ if (!setup_layout_segmented(data))
+ goto fail;
+
+
+ /* parse samples */
+ {
+ int32_t sample_count = 0;
+ int i;
+
+ loop_flag = (loop_start_segment > 0);
+
+ for (i = 0; i < segment_count; i++) {
+ if (loop_flag && loop_start_segment == i) {
+ loop_start_sample = sample_count;
+ }
+
+ sample_count += data->segments[i]->num_samples;
+
+ if (loop_flag && loop_end_segment-1 == i) {
+ loop_end_sample = sample_count;
+ }
+ }
+
+ if (sample_count != num_samples) {
+ VGM_LOG("WAVE: total segments samples %i != num_samples %i\n", sample_count, num_samples);
+ goto fail;
+ }
+ }
+
+
+ /* build the VGMSTREAM */
+ vgmstream = allocate_vgmstream(channel_count, loop_flag);
+ if (!vgmstream) goto fail;
+
+ vgmstream->sample_rate = sample_rate;
+ vgmstream->num_samples = num_samples;
+ vgmstream->loop_start_sample = loop_start_sample;
+ vgmstream->loop_end_sample = loop_end_sample;
+
+ vgmstream->meta_type = meta_WAVE_segmented;
+ /* .wave can mix codecs, usually first segment is a small ADPCM section) */
+ vgmstream->coding_type = (segment_count == 1 ? data->segments[0]->coding_type : data->segments[1]->coding_type);
+ vgmstream->layout_type = layout_segmented;
+
+ vgmstream->layout_data = data;
+ if (loop_flag)
+ data->loop_segment = (loop_start_segment);
+
+ return vgmstream;
+
+fail:
+ free_layout_segmented(data);
+ close_vgmstream(vgmstream);
+ return NULL;
+}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wii_04sw.c b/Frameworks/vgmstream/vgmstream/src/meta/wii_04sw.c
index 845b6fa6d..e1559ca98 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/wii_04sw.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/wii_04sw.c
@@ -9,12 +9,10 @@ VGMSTREAM * init_vgmstream_wii_04sw(STREAMFILE *streamFile) {
size_t file_size, data_size;
- /* check extension, case insensitive */
+ /* checks */
/* ".04sw" is just the ID, the real filename inside the file uses .XA */
if (!check_extensions(streamFile,"xa,04sw"))
goto fail;
-
- /* check header */
if (read_32bitBE(0x00,streamFile) != 0x30345357) /* "04SW" */
goto fail;
@@ -39,9 +37,9 @@ VGMSTREAM * init_vgmstream_wii_04sw(STREAMFILE *streamFile) {
vgmstream->num_samples = read_32bitBE(0x04,streamFile);
vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave_shortblock;
+ vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
vgmstream->interleave_block_size = 0x8000;
- vgmstream->interleave_smallblock_size = (read_32bitBE(0x08,streamFile) / 2 % vgmstream->interleave_block_size + 7) / 8 * 8;
+ vgmstream->interleave_last_block_size = (read_32bitBE(0x08,streamFile) / 2 % vgmstream->interleave_block_size + 7) / 8 * 8;
dsp_read_coefs_be(vgmstream,streamFile,0x20, 0x60);
/* the initial history offset seems different thatn standard DSP and possibly always zero */
@@ -50,10 +48,8 @@ VGMSTREAM * init_vgmstream_wii_04sw(STREAMFILE *streamFile) {
/* the rest of the header has unknown values (several repeats) and the filename */
- /* open the file for reading */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
-
return vgmstream;
fail:
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wii_ras.c b/Frameworks/vgmstream/vgmstream/src/meta/wii_ras.c
index d84bc94b2..fe3c0d8bc 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/wii_ras.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/wii_ras.c
@@ -1,20 +1,17 @@
#include "meta.h"
-#include "../util.h"
+#include "../coding/coding.h"
-/* RAS (from Donkey Kong Country Returns) */
+/* RAS_ - from Donkey Kong Country Returns (Wii) */
VGMSTREAM * init_vgmstream_wii_ras(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
- char filename[PATH_LIMIT];
off_t start_offset;
- int loop_flag;
- int channel_count;
+ int loop_flag, channel_count;
- /* check extension, case insensitive */
- streamFile->get_name(streamFile,filename,sizeof(filename));
- if (strcasecmp("ras",filename_extension(filename))) goto fail;
+ /* checks */
+ if (!check_extensions(streamFile, "ras"))
+ goto fail;
- /* check header */
if (read_32bitBE(0x00,streamFile) != 0x5241535F) /* "RAS_" */
goto fail;
@@ -26,63 +23,32 @@ VGMSTREAM * init_vgmstream_wii_ras(STREAMFILE *streamFile) {
loop_flag = 1;
}
channel_count = 2;
+ start_offset = read_32bitBE(0x18,streamFile);
- /* build the VGMSTREAM */
+ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
- /* fill in the vital statistics */
- start_offset = read_32bitBE(0x18,streamFile);
- vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x14,streamFile);
- vgmstream->coding_type = coding_NGC_DSP;
- vgmstream->num_samples = read_32bitBE(0x1c,streamFile)/channel_count/8*14;
- vgmstream->layout_type = layout_interleave;
- vgmstream->interleave_block_size = read_32bitBE(0x20,streamFile);
vgmstream->meta_type = meta_WII_RAS;
- if (loop_flag) {
- // loop is block + samples into block
- vgmstream->loop_start_sample =
- read_32bitBE(0x30,streamFile)*vgmstream->interleave_block_size/8*14 +
- read_32bitBE(0x34,streamFile);
- vgmstream->loop_end_sample =
- read_32bitBE(0x38,streamFile)*vgmstream->interleave_block_size/8*14 +
- read_32bitBE(0x3C,streamFile);
+ vgmstream->coding_type = coding_NGC_DSP;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = read_32bitBE(0x20,streamFile);
+
+ vgmstream->num_samples = read_32bitBE(0x1c,streamFile)/channel_count/8*14;
+ if (loop_flag) { /* loop is block + samples into block */
+ vgmstream->loop_start_sample = read_32bitBE(0x30,streamFile)*vgmstream->interleave_block_size/8*14 +
+ read_32bitBE(0x34,streamFile);
+ vgmstream->loop_end_sample = read_32bitBE(0x38,streamFile)*vgmstream->interleave_block_size/8*14 +
+ read_32bitBE(0x3C,streamFile);
}
- if (vgmstream->coding_type == coding_NGC_DSP) {
- int i;
- for (i=0;i<16;i++) {
- vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x40+i*2,streamFile);
- }
- if (channel_count == 2) {
- for (i=0;i<16;i++)
- vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x70+i*2,streamFile);
- }
- } else {
+ dsp_read_coefs_be(vgmstream,streamFile,0x40,0x30);
+
+
+ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
- }
-
- /* open the file for reading */
- {
- int i;
- for (i=0;ilayout_type==layout_interleave_shortblock)
- vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,
- vgmstream->interleave_block_size);
- else
- vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,
- 0x1000);
-
- if (!vgmstream->ch[i].streamfile) goto fail;
-
- vgmstream->ch[i].channel_start_offset=
- vgmstream->ch[i].offset=
- start_offset + i*vgmstream->interleave_block_size;
- }
- }
-
return vgmstream;
/* clean up anything we may have opened */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ws_aud.c b/Frameworks/vgmstream/vgmstream/src/meta/ws_aud.c
index cd13606c4..41ae998af 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/ws_aud.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/ws_aud.c
@@ -100,7 +100,7 @@ VGMSTREAM * init_vgmstream_ws_aud(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_WS_AUD_old;
}
- vgmstream->layout_type = layout_ws_aud_blocked;
+ vgmstream->layout_type = layout_blocked_ws_aud;
/* open the file for reading by each channel */
{
@@ -118,9 +118,9 @@ VGMSTREAM * init_vgmstream_ws_aud(STREAMFILE *streamFile) {
/* start me up */
if (new_type) {
- ws_aud_block_update(0xc,vgmstream);
+ block_update_ws_aud(0xc,vgmstream);
} else {
- ws_aud_block_update(0x8,vgmstream);
+ block_update_ws_aud(0x8,vgmstream);
}
return vgmstream;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c
index 8cd588f8d..53d1e3e3d 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c
@@ -78,6 +78,18 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
}
#endif
+ /* ignore LyN RIFF */
+ {
+ off_t fact_offset;
+ size_t fact_size;
+
+ if (find_chunk(streamFile, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */
+ if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, streamFile) == 0x4C794E20) /* "LyN " */
+ goto fail; /* parsed elsewhere */
+ /* Wwise doesn't use "fact", though */
+ }
+ }
+
/* parse format (roughly spec-compliant but some massaging is needed) */
{
@@ -123,9 +135,9 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
//todo fix repeat looping
}
}
- else if (find_chunk(streamFile, 0x4C495354,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"LIST", common */
- //todo parse "adtl" (does it ever contain loop info in Wwise?)
- }
+ //else if (find_chunk(streamFile, 0x4C495354,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"LIST", common */
+ // /* usually contains "cue"s with sample positions for events (ex. Platinum Games) but no real looping info */
+ //}
/* other Wwise specific: */
//"JUNK": optional padding for usually aligment (0-size JUNK exists too)
@@ -194,15 +206,14 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
break;
case IMA: /* common */
- /* slightly modified XBOX-IMA with interleaved sub-blocks and LE/BE header */
-
- /* Wwise uses common codecs (ex. 0x0002 MSADPCM) so this parser should go AFTER riff.c avoid misdetection */
+ /* slightly modified XBOX-IMA */
+ /* Wwise reuses common codec ids (ex. 0x0002 MSADPCM) for IMA so this parser should go AFTER riff.c avoid misdetection */
if (ww.bits_per_sample != 4) goto fail;
if (ww.block_align != 0x24 * ww.channels) goto fail;
vgmstream->coding_type = coding_WWISE_IMA;
- vgmstream->layout_type = layout_none;
- vgmstream->interleave_block_size = ww.block_align;
+ vgmstream->layout_type = layout_interleave;
+ vgmstream->interleave_block_size = ww.block_align / ww.channels;
vgmstream->codec_endian = ww.big_endian;
if (ww.truncated) /* enough to get real samples */
@@ -230,8 +241,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
/* older Wwise (~<2012) */
switch(vorb_size) {
- //case 0x2C: /* early (~2009), some EVE Online Apocrypha files? */
- case 0x28: /* early (~2009), ex. The Lord of the Rings: Conquest PC */
+ case 0x2C: /* earliest (~2009), ex. UFC Undisputed 2009 (PS3), some EVE Online Apocrypha files? */
+ case 0x28: /* early (~2009), ex. The Lord of the Rings: Conquest (PC) */
data_offsets = 0x18;
block_offsets = 0; /* no need, full headers are present */
cfg.header_type = WWV_TYPE_8;
@@ -452,7 +463,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
vgmstream->num_samples = msd.num_samples;
if (!vgmstream->num_samples)
- vgmstream->num_samples = ffmpeg_data->totalSamples; /* very wrong, from avg-br */
+ vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples; /* very wrong, from avg-br */
//num_samples seem to be found in the last "seek" table entry too, as: entry / channels / 2
}
@@ -471,7 +482,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
- vgmstream->num_samples = ffmpeg_data->totalSamples;
+ vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples;
break;
}
@@ -590,15 +601,15 @@ fail:
0x31 (1): blocksize_0_exp (large)
0x32 (2): empty
-"vorb" size 0x28 / 0x2a
+"vorb" size 0x28 / 0x2c / 0x2a
0x00 (4): num_samples
0x04 (4): data start offset after seek table+setup, or loop start when "smpl" is present
0x08 (4): data end offset after seek table (setup+packets), or loop end when "smpl" is present
-0x0c (2): ? (small, 0..~0x400)
+0x0c (2): ? (small, 0..~0x400) [(4) when size is 0x2C]
0x10 (4): setup_offset within data (0 = no seek table)
0x14 (4): audio_offset within data
0x18 (2): biggest packet size (not including header)?
-0x1a (2): ? (small, N..~0x100) uLastGranuleExtra?
+0x1a (2): ? (small, N..~0x100) uLastGranuleExtra? [(4) when size is 0x2C]
0x1c (4): ? (mid, 0~0x5000) dwDecodeAllocSize?
0x20 (4): ? (mid, 0~0x5000) dwDecodeX64AllocSize?
0x24 (4): parent bank/event id? uHashCodebook? (shared by several .wem a game, but not all need to share it)
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/x360_tra.c b/Frameworks/vgmstream/vgmstream/src/meta/x360_tra.c
index b94189113..8554076cd 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/x360_tra.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/x360_tra.c
@@ -38,7 +38,7 @@ VGMSTREAM * init_vgmstream_x360_tra(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_DVI_IMA_int;
vgmstream->num_samples = (int32_t)(get_streamfile_size(streamFile) - ((get_streamfile_size(streamFile)/0x204)*4));
- vgmstream->layout_type = layout_tra_blocked;
+ vgmstream->layout_type = layout_blocked_tra;
vgmstream->meta_type = meta_X360_TRA;
@@ -51,7 +51,7 @@ VGMSTREAM * init_vgmstream_x360_tra(STREAMFILE *streamFile) {
}
}
- tra_block_update(0,vgmstream);
+ block_update_tra(0,vgmstream);
return vgmstream;
/* clean up anything we may have opened */
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xbox_ims.c b/Frameworks/vgmstream/vgmstream/src/meta/xbox_ims.c
index 89aeef604..220eeac13 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/xbox_ims.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/xbox_ims.c
@@ -31,7 +31,7 @@ VGMSTREAM * init_vgmstream_xbox_matx(STREAMFILE *streamFile) {
vgmstream->sample_rate = read_16bitLE(0x06,streamFile) & 0xffff;
vgmstream->coding_type = coding_XBOX_IMA;
- vgmstream->layout_type = layout_matx_blocked;
+ vgmstream->layout_type = layout_blocked_matx;
vgmstream->meta_type = meta_XBOX_MATX;
/* open the file for reading by each channel */
@@ -43,15 +43,15 @@ VGMSTREAM * init_vgmstream_xbox_matx(STREAMFILE *streamFile) {
}
/* Calc num_samples */
- matx_block_update(0,vgmstream);
+ block_update_matx(0,vgmstream);
vgmstream->num_samples=0;
do {
vgmstream->num_samples += vgmstream->current_block_size/36*64;
- matx_block_update(vgmstream->next_block_offset,vgmstream);
+ block_update_matx(vgmstream->next_block_offset,vgmstream);
} while (vgmstream->next_block_offsetcoding_type = coding_XBOX_IMA;
- vgmstream->layout_type = layout_xvas_blocked;
+ vgmstream->layout_type = layout_blocked_xvas;
vgmstream->meta_type = meta_XBOX_XVAS;
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
goto fail;
- xvas_block_update(start_offset,vgmstream);
+ block_update_xvas(start_offset,vgmstream);
return vgmstream;
fail:
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xbox_xwav.c b/Frameworks/vgmstream/vgmstream/src/meta/xbox_xwav.c
deleted file mode 100644
index 735a11203..000000000
--- a/Frameworks/vgmstream/vgmstream/src/meta/xbox_xwav.c
+++ /dev/null
@@ -1,91 +0,0 @@
-#include "meta.h"
-#include "../coding/coding.h"
-
-/* XWAV - renamed WAV with XBOX-IMA
- * (could be parsed as RIFF/.lwav but has a custom loop chunk and multichannel) */
-VGMSTREAM * init_vgmstream_xbox_xwav(STREAMFILE *streamFile) {
- VGMSTREAM * vgmstream = NULL;
- int loop_flag, channel_count;
- off_t start_offset;
-
- /* check extension */
- if (!check_extensions(streamFile,"xwav"))
- goto fail;
-
- /* check for headers */
- if(!((read_32bitBE(0x00,streamFile) == 0x52494646) && /* "RIFF" */
- (read_32bitBE(0x08,streamFile) == 0x57415645) && /* "WAVE" */
- (read_32bitBE(0x0C,streamFile) == 0x666D7420) && /* "fmt " */
- (read_16bitLE(0x14,streamFile) == 0x0069))) /* codec */
- goto fail;
-
- /* loop chunk found on Koei/Omega Force games [Crimson Sea, Dynasty Warriors 5] */
- loop_flag = (read_32bitBE(0x28,streamFile) == 0x77736D70); /* "wsmp" */
- channel_count = read_16bitLE(0x16,streamFile);
-
- /* search for "data" */
- start_offset = 0x1C;
- do {
- if (read_32bitBE(start_offset,streamFile)==0x64617461)
- break;
- start_offset += 0x04;
- } while (start_offset < (off_t)get_streamfile_size(streamFile));
-
- if (start_offset >= (off_t)get_streamfile_size(streamFile))
- goto fail;
- start_offset += 0x04;
-
-
- /* build the VGMSTREAM */
- vgmstream = allocate_vgmstream(channel_count,loop_flag);
- if (!vgmstream) goto fail;
-
- vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bitLE(start_offset,streamFile), vgmstream->channels);
- vgmstream->sample_rate = read_32bitLE(0x18,streamFile);
- if (loop_flag) {
- vgmstream->loop_start_sample = read_32bitLE(0x4C,streamFile);
- vgmstream->loop_end_sample = vgmstream->loop_start_sample + read_32bitLE(0x50,streamFile);
- }
-
- vgmstream->coding_type = coding_XBOX_IMA;
- vgmstream->layout_type = layout_none;
- vgmstream->meta_type = meta_XBOX_RIFF;
-
- //if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
- // goto fail;
-
- //custom init
- {
- int i, ch;
- char filename[PATH_LIMIT];
- streamFile->get_name(streamFile,filename,sizeof(filename));
-
- if (channel_count > 2) { /* multichannel interleaved init */
- for (i=0, ch=0;ich[i].streamfile = streamFile->open(streamFile,filename,0x24);
- vgmstream->ch[i].offset = start_offset + 0x04;
-
- if (!vgmstream->ch[i].streamfile) goto fail;
- }
- }
- else {
- for (i=0; i < channel_count; i++) {
- vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x24);
- vgmstream->ch[i].offset = start_offset + 0x04;
-
- if (!vgmstream->ch[i].streamfile) goto fail;
- }
- }
- }
-
- return vgmstream;
-
-fail:
- close_vgmstream(vgmstream);
- return NULL;
-}
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xnb.c b/Frameworks/vgmstream/vgmstream/src/meta/xnb.c
index 98aac0989..c20efb11f 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/xnb.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/xnb.c
@@ -41,7 +41,7 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
{
char reader_name[255+1];
off_t current_offset = 0x0a;
- int reader_string_len;
+ size_t reader_string_len;
uint32_t fmt_chunk_size;
const char * type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */
//const char * type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* just references a companion .wma */
@@ -76,6 +76,7 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
codec = read_16bit(current_offset+0x00, streamFile);
channel_count = read_16bit(current_offset+0x02, streamFile);
sample_rate = read_32bit(current_offset+0x04, streamFile);
+ /* 0x08: byte rate */
block_size = read_16bit(current_offset+0x0c, streamFile);
bps = read_16bit(current_offset+0x0e, streamFile);
@@ -102,6 +103,10 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
switch (codec) {
case 0x01: /* Dragon's Blade (Android) */
+ /* null in Metagalactic Blitz (PC) */
+ if (!block_size)
+ block_size = (bps == 8 ? 0x01 : 0x02) * channel_count;
+
vgmstream->coding_type = bps == 8 ? coding_PCM8_U_int : coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = block_size / channel_count;
@@ -109,6 +114,7 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
break;
case 0x02: /* White Noise Online (PC) */
+ if (!block_size) goto fail;
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = block_size;
@@ -116,6 +122,7 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
break;
case 0x11:
+ if (!block_size) goto fail;
vgmstream->coding_type = coding_MS_IMA;
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = block_size;
diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xwb.c b/Frameworks/vgmstream/vgmstream/src/meta/xwb.c
index 383b31cc6..8c104f465 100644
--- a/Frameworks/vgmstream/vgmstream/src/meta/xwb.c
+++ b/Frameworks/vgmstream/vgmstream/src/meta/xwb.c
@@ -35,6 +35,11 @@ typedef struct {
size_t base_size;
off_t entry_offset;
size_t entry_size;
+ off_t names_offset;
+ size_t names_size;
+ size_t names_entry_size;
+ off_t extra_offset;
+ size_t extra_size;
off_t data_offset;
size_t data_size;
@@ -44,7 +49,7 @@ typedef struct {
uint32_t base_flags;
size_t entry_elem_size;
size_t entry_alignment;
- int streams;
+ int total_subsongs;
uint32_t entry_flags;
uint32_t format;
@@ -63,27 +68,25 @@ typedef struct {
uint32_t loop_end_sample;
} xwb_header;
-static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_header * xwb, STREAMFILE *streamFile);
+static void get_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamFile);
/* XWB - XACT Wave Bank (Microsoft SDK format for XBOX/XBOX360/Windows) */
VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, off, suboff;
- xwb_header xwb;
- int target_stream = streamFile->stream_index;
+ xwb_header xwb = {0};
+ int target_subsong = streamFile->stream_index;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
- /* basic checks */
- if (!check_extensions(streamFile,"xwb")) goto fail;
-
+ /* checks */
+ if (!check_extensions(streamFile,"xwb"))
+ goto fail;
if ((read_32bitBE(0x00,streamFile) != 0x57424E44) && /* "WBND" (LE) */
(read_32bitBE(0x00,streamFile) != 0x444E4257)) /* "DNBW" (BE) */
goto fail;
- memset(&xwb,0,sizeof(xwb_header));
-
xwb.little_endian = read_32bitBE(0x00,streamFile) == 0x57424E44;/* WBND */
if (xwb.little_endian) {
read_32bit = read_32bitLE;
@@ -101,13 +104,21 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* read segment offsets (SEGIDX) */
if (xwb.version <= XACT1_0_MAX) {
- xwb.streams = read_32bit(0x0c, streamFile);
- /* 0x10: bank name */
+ xwb.total_subsongs = read_32bit(0x0c, streamFile);
+ /* 0x10: bank name (size 0x10) */
+ xwb.base_offset = 0;
+ xwb.base_size = 0;
+ xwb.entry_offset = 0x50;
+ xwb.entry_size = xwb.entry_elem_size * xwb.total_subsongs;
xwb.entry_elem_size = 0x14;
- xwb.entry_offset= 0x50;
- xwb.entry_size = xwb.entry_elem_size * xwb.streams;
- xwb.data_offset = xwb.entry_offset + xwb.entry_size;
- xwb.data_size = get_streamfile_size(streamFile) - xwb.data_offset;
+ xwb.data_offset = xwb.entry_offset + xwb.entry_size;
+ xwb.data_size = get_streamfile_size(streamFile) - xwb.data_offset;
+
+ xwb.names_offset = 0;
+ xwb.names_size = 0;
+ xwb.names_entry_size= 0;
+ xwb.extra_offset = 0;
+ xwb.extra_size = 0;
}
else {
off = xwb.version <= XACT2_2_MAX ? 0x08 : 0x0c;
@@ -115,10 +126,32 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
xwb.base_size = read_32bit(off+0x04, streamFile);
xwb.entry_offset= read_32bit(off+0x08, streamFile);//ENTRYMETADATA
xwb.entry_size = read_32bit(off+0x0c, streamFile);
- /* go to last segment (XACT2/3 have 5 segments, XACT1 4) */
- //0x10: XACT1/2: ENTRYNAMES, XACT3: SEEKTABLES
- //0x14: XACT1: none (ENTRYWAVEDATA), XACT2: EXTRA, XACT3: ENTRYNAMES
- suboff = xwb.version <= XACT1_1_MAX ? 0x08 : 0x08+0x08;
+
+ /* read extra segments (values can be 0 == no segment) */
+ if (xwb.version <= XACT1_1_MAX) {
+ xwb.names_offset = read_32bit(off+0x10, streamFile);//ENTRYNAMES
+ xwb.names_size = read_32bit(off+0x14, streamFile);
+ xwb.names_entry_size= 0x40;
+ xwb.extra_offset = 0;
+ xwb.extra_size = 0;
+ suboff = 0x04*2;
+ }
+ else if (xwb.version <= XACT2_1_MAX) {
+ xwb.names_offset = read_32bit(off+0x10, streamFile);//ENTRYNAMES
+ xwb.names_size = read_32bit(off+0x14, streamFile);
+ xwb.names_entry_size= 0x40;
+ xwb.extra_offset = read_32bit(off+0x18, streamFile);//EXTRA
+ xwb.extra_size = read_32bit(off+0x1c, streamFile);
+ suboff = 0x04*2 + 0x04*2;
+ } else {
+ xwb.extra_offset = read_32bit(off+0x10, streamFile);//SEEKTABLES
+ xwb.extra_size = read_32bit(off+0x14, streamFile);
+ xwb.names_offset = read_32bit(off+0x18, streamFile);//ENTRYNAMES
+ xwb.names_size = read_32bit(off+0x1c, streamFile);
+ xwb.names_entry_size= 0x40;
+ suboff = 0x04*2 + 0x04*2;
+ }
+
xwb.data_offset = read_32bit(off+0x10+suboff, streamFile);//ENTRYWAVEDATA
xwb.data_size = read_32bit(off+0x14+suboff, streamFile);
@@ -128,8 +161,8 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* read base entry (WAVEBANKDATA) */
off = xwb.base_offset;
xwb.base_flags = (uint32_t)read_32bit(off+0x00, streamFile);
- xwb.streams = read_32bit(off+0x04, streamFile);
- /* 0x08 bank_name */
+ xwb.total_subsongs = read_32bit(off+0x04, streamFile);
+ /* 0x08: bank name (size 0x40) */
suboff = 0x08 + (xwb.version <= XACT1_1_MAX ? 0x10 : 0x40);
xwb.entry_elem_size = read_32bit(off+suboff+0x00, streamFile);
/* suboff+0x04: meta name entry size */
@@ -138,26 +171,32 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* suboff+0x10: build time 64b (XACT2/3) */
}
- if (target_stream == 0) target_stream = 1; /* auto: default to 1 */
- if (target_stream < 0 || target_stream > xwb.streams || xwb.streams < 1) goto fail;
+ if (target_subsong == 0) target_subsong = 1; /* auto: default to 1 */
+ if (target_subsong < 0 || target_subsong > xwb.total_subsongs || xwb.total_subsongs < 1) goto fail;
/* read stream entry (WAVEBANKENTRY) */
- off = xwb.entry_offset + (target_stream-1) * xwb.entry_elem_size;
+ off = xwb.entry_offset + (target_subsong-1) * xwb.entry_elem_size;
- if (xwb.base_flags & WAVEBANK_FLAGS_COMPACT) { /* compact entry */
- /* offset_in_sectors:21 and sector_alignment_in_bytes:11 */
- uint32_t entry = (uint32_t)read_32bit(off+0x00, streamFile);
- xwb.stream_offset = xwb.data_offset + (entry >> 11) * xwb.entry_alignment + (entry & 0x7FF);
+ if (xwb.base_flags & WAVEBANK_FLAGS_COMPACT) { /* compact entry [NFL Fever 2004 demo from Amped 2 (Xbox)] */
+ uint32_t entry, size_deviation, sector_offset;
+ off_t next_stream_offset;
- /* find size (up to next entry or data end) */
- if (xwb.streams > 1) {
- entry = (uint32_t)read_32bit(off+xwb.entry_size, streamFile);
- xwb.stream_size = xwb.stream_offset -
- (xwb.data_offset + (entry >> 11) * xwb.entry_alignment + (entry & 0x7FF));
- } else {
- xwb.stream_size = xwb.data_size;
+ entry = (uint32_t)read_32bit(off+0x00, streamFile);
+ size_deviation = ((entry >> 21) & 0x7FF); /* 11b, padding data for sector alignment in bytes*/
+ sector_offset = (entry & 0x1FFFFF); /* 21b, offset within data in sectors */
+
+ xwb.stream_offset = xwb.data_offset + sector_offset*xwb.entry_alignment;
+
+ /* find size using next offset */
+ if (target_subsong < xwb.total_subsongs) {
+ uint32_t next_entry = (uint32_t)read_32bit(off+0x04, streamFile);
+ next_stream_offset = xwb.data_offset + (next_entry & 0x1FFFFF)*xwb.entry_alignment;
}
+ else { /* for last entry (or first, when subsongs = 1) */
+ next_stream_offset = xwb.data_offset + xwb.data_size;
+ }
+ xwb.stream_size = next_stream_offset - xwb.stream_offset - size_deviation;
}
else if (xwb.version <= XACT1_0_MAX) {
xwb.format = (uint32_t)read_32bit(off+0x00, streamFile);
@@ -311,8 +350,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
else if (xwb.version <= XACT2_1_MAX && (xwb.codec == XMA1 || xwb.codec == XMA2) && xwb.loop_flag) {
/* v38: byte offset, v40+: sample offset, v39: ? */
/* need to manually find sample offsets, thanks to Microsoft dumb headers */
- ms_sample_data msd;
- memset(&msd,0,sizeof(ms_sample_data));
+ ms_sample_data msd = {0};
msd.xma_version = xwb.codec == XMA1 ? 1 : 2;
msd.channels = xwb.channels;
@@ -353,10 +391,10 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
vgmstream->num_samples = xwb.num_samples;
vgmstream->loop_start_sample = xwb.loop_start_sample;
vgmstream->loop_end_sample = xwb.loop_end_sample;
- vgmstream->num_streams = xwb.streams;
+ vgmstream->num_streams = xwb.total_subsongs;
vgmstream->stream_size = xwb.stream_size;
vgmstream->meta_type = meta_XWB;
- get_xsb_name(vgmstream->stream_name,STREAM_NAME_SIZE, target_stream, &xwb, streamFile);
+ get_name(vgmstream->stream_name,STREAM_NAME_SIZE, target_subsong, &xwb, streamFile);
switch(xwb.codec) {
case PCM: /* Unreal Championship (Xbox)[PCM8], KOF2003 (Xbox)[PCM16LE], Otomedius (X360)[PCM16BE] */
@@ -420,7 +458,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* no wma_bytes_to_samples, this should be ok */
if (!vgmstream->num_samples)
- vgmstream->num_samples = ffmpeg_data->totalSamples;
+ vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples;
break;
}
@@ -492,6 +530,24 @@ fail:
}
+/* ****************************************************************************** */
+
+/* try to get the stream name in the .xwb, though they are very rarely included */
+static int get_xwb_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamFile) {
+ size_t read;
+
+ if (!xwb->names_offset || !xwb->names_size || xwb->names_entry_size > maxsize)
+ goto fail;
+
+ read = read_string(buf,xwb->names_entry_size, xwb->names_offset + xwb->names_entry_size*(target_subsong-1),streamFile);
+ if (read == 0) goto fail;
+
+ return 1;
+
+fail:
+ return 0;
+}
+
/* ****************************************************************************** */
/* XSB parsing from xwb_split (mostly untouched), could be improved */
@@ -535,24 +591,19 @@ typedef struct {
/* try to find the stream name in a companion XSB file, a comically complex cue format. */
-static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_header * xwb, STREAMFILE *streamXwb) {
+static int get_xsb_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamXwb) {
STREAMFILE *streamFile = NULL;
int i,j, start_sound, cfg__start_sound = 0, cfg__selected_wavebank = 0;
int xsb_version;
off_t off, suboff, name_offset = 0;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
- xsb_header xsb;
-
- memset(&xsb,0,sizeof(xsb_header)); /* before any "fail"! */
+ xsb_header xsb = {0};
- streamFile = open_stream_ext(streamXwb, "xsb");
+ streamFile = open_streamfile_by_ext(streamXwb, "xsb");
if (!streamFile) goto fail;
- //todo try common names (xwb and xsb often are named slightly differently using a common convention)
-
-
/* check header */
if ((read_32bitBE(0x00,streamFile) != 0x5344424B) && /* "SDBK" (LE) */
(read_32bitBE(0x00,streamFile) != 0x4B424453)) /* "KBDS" (BE) */
@@ -609,8 +660,8 @@ static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_head
xsb.xsb_sounds_offset = read_32bit(0x46, streamFile);
}
- VGM_ASSERT(xsb.xsb_sounds_count < xwb->streams,
- "XSB: number of streams in xsb lower than xwb (xsb %i vs xwb %i)\n", xsb.xsb_sounds_count, xwb->streams);
+ VGM_ASSERT(xsb.xsb_sounds_count < xwb->total_subsongs,
+ "XSB: number of streams in xsb lower than xwb (xsb %i vs xwb %i)\n", xsb.xsb_sounds_count, xwb->total_subsongs);
VGM_ASSERT(xsb.xsb_simple_sounds_count + xsb.xsb_complex_sounds_count != xsb.xsb_sounds_count,
"XSB: number of xsb sounds doesn't match simple + complex sounds (simple %i, complex %i, total %i)\n", xsb.xsb_simple_sounds_count, xsb.xsb_complex_sounds_count, xsb.xsb_sounds_count);
@@ -747,7 +798,7 @@ static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_head
//CHECK_EXIT(w->sound_count == 0, "ERROR: xsb wavebank %i has no sounds", i); //Ikaruga PC
- if (w->sound_count == xwb->streams) {
+ if (w->sound_count == xwb->total_subsongs) {
if (!cfg__selected_wavebank) {
VGM_LOG("XSB: multiple xsb wavebanks with the same number of sounds, use -w to specify one of the wavebanks\n");
goto fail;
@@ -773,22 +824,22 @@ static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_head
}
if (cfg__start_sound) {
- if (xsb.xsb_wavebanks[cfg__selected_wavebank-1].sound_count - (cfg__start_sound-1) < xwb->streams) {
- VGM_LOG("XSB: starting sound too high (max in selected wavebank is %i)\n", xsb.xsb_wavebanks[cfg__selected_wavebank-1].sound_count - xwb->streams + 1);
+ if (xsb.xsb_wavebanks[cfg__selected_wavebank-1].sound_count - (cfg__start_sound-1) < xwb->total_subsongs) {
+ VGM_LOG("XSB: starting sound too high (max in selected wavebank is %i)\n", xsb.xsb_wavebanks[cfg__selected_wavebank-1].sound_count - xwb->total_subsongs + 1);
goto fail;
}
} else {
/*
if (!cfg->ignore_names_not_found)
- CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count > xwb->streams_count, "ERROR: number of streams in xsb wavebank bigger than xwb (xsb %i vs xwb %i), use -s to specify (1=first)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->streams_count);
+ CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count > xwb->streams_count, "ERROR: number of streams in xsb wavebank bigger than xwb (xsb %i vs xwb %i), use -s to specify (1=first)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->total_subsongs);
if (!cfg->ignore_names_not_found)
- CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count < xwb->streams_count, "ERROR: number of streams in xsb wavebank lower than xwb (xsb %i vs xwb %i), use -n to ignore (some names won't be extracted)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->streams_count);
+ CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count < xwb->streams_count, "ERROR: number of streams in xsb wavebank lower than xwb (xsb %i vs xwb %i), use -n to ignore (some names won't be extracted)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->total_subsongs);
*/
//if (!cfg->ignore_names_not_found)
- // CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count != xwb->streams_count, "ERROR: number of streams in xsb wavebank different than xwb (xsb %i vs xwb %i), use -s to specify (1=first)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->streams_count);
+ // CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count != xwb->streams_count, "ERROR: number of streams in xsb wavebank different than xwb (xsb %i vs xwb %i), use -s to specify (1=first)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->total_subsongs);
}
/* *************************** */
@@ -799,7 +850,7 @@ static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_head
for (i = start_sound; i < xsb.xsb_sounds_count; i++) {
xsb_sound *s = &(xsb.xsb_sounds[i]);
if (s->wavebank == cfg__selected_wavebank-1
- && s->stream_index == target_stream-1){
+ && s->stream_index == target_subsong-1){
name_offset = s->name_offset;
break;
}
@@ -813,6 +864,25 @@ static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_head
fail:
free(xsb.xsb_sounds);
free(xsb.xsb_wavebanks);
- if (streamFile) close_streamfile(streamFile);
- return;
+ close_streamfile(streamFile);
+
+ return (name_offset);
+}
+
+static void get_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamFile) {
+ int name_found;
+
+ /* try inside this xwb */
+ name_found = get_xwb_name(buf, maxsize, target_subsong, xwb, streamFile);
+ if (name_found) return;
+
+ /* try again in external .xsb */
+ get_xsb_name(buf, maxsize, target_subsong, xwb, streamFile);
+
+
+ //todo try again with common names (xwb and xsb often are named slightly differently using a common convention):
+ // InGameMusic.xwb + ingamemusic.xsb
+ // UIMusicBank.xwb + UISoundBank.xsb
+ // NB_BGM_m0100_WB.xwb + NB_BGM_m0100_SB.xsb
+ // Wave Bank.xwb + Sound Bank.xsb
}
diff --git a/Frameworks/vgmstream/vgmstream/src/streamfile.c b/Frameworks/vgmstream/vgmstream/src/streamfile.c
index f62b78422..b285164ea 100644
--- a/Frameworks/vgmstream/vgmstream/src/streamfile.c
+++ b/Frameworks/vgmstream/vgmstream/src/streamfile.c
@@ -6,12 +6,6 @@
#include "vgmstream.h"
-/* On EOF reads we can return length 0, or ignore and return the requested length + 0-set the buffer.
- * Some decoders don't check for EOF and may decode garbage if returned 0, as read_Nbit() funcs return -1.
- * Only matters for metas that get num_samples wrong (bigger than total data). */
-#define STREAMFILE_IGNORE_EOF 0
-
-
/* a STREAMFILE that operates via standard IO using a buffer */
typedef struct {
STREAMFILE sf; /* callbacks */
@@ -27,20 +21,26 @@ typedef struct {
static STREAMFILE * open_stdio_streamfile_buffer(const char * const filename, size_t buffersize);
static STREAMFILE * open_stdio_streamfile_buffer_by_file(FILE *infile,const char * const filename, size_t buffersize);
-static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOSTREAMFILE * streamfile) {
- size_t length_read_total=0;
+static size_t read_stdio(STDIOSTREAMFILE *streamfile,uint8_t * dest, off_t offset, size_t length) {
+ size_t length_read_total = 0;
+
+ if (!streamfile || !dest || length <= 0 || offset < 0)
+ return 0;
/* is the part of the requested length in the buffer? */
if (offset >= streamfile->offset && offset < streamfile->offset + streamfile->validsize) {
- size_t length_read;
+ size_t length_to_read;
off_t offset_into_buffer = offset - streamfile->offset;
- length_read = streamfile->validsize - offset_into_buffer;
- memcpy(dest,streamfile->buffer + offset_into_buffer,length_read);
- length_read_total += length_read;
- length -= length_read;
- offset += length_read;
- dest += length_read;
+ length_to_read = streamfile->validsize - offset_into_buffer;
+ if (length_to_read > length)
+ length_to_read = length;
+
+ memcpy(dest,streamfile->buffer + offset_into_buffer,length_to_read);
+ length_read_total += length_to_read;
+ length -= length_to_read;
+ offset += length_to_read;
+ dest += length_to_read;
}
/* What would make more sense here is to read the whole request
@@ -49,25 +49,18 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST
* The destination buffer is supposed to be much smaller than the
* STREAMFILE buffer, though. Maybe we should only ever return up
* to the buffer size to avoid having to deal with things like this
- * which are outside of my intended use.
- */
+ * which are outside of my intended use. */
+
/* read the rest of the requested length */
while (length > 0) {
- size_t length_to_read;
- size_t length_read;
+ size_t length_to_read, length_read;
streamfile->validsize = 0; /* buffer is empty now */
/* request outside file: ignore to avoid seek/read */
if (offset > streamfile->filesize) {
streamfile->offset = streamfile->filesize;
VGM_LOG_ONCE("ERROR: reading over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length);
-
-#if STREAMFILE_IGNORE_EOF
- memset(dest,0,length); /* dest is already shifted */
- return length_read_total + length; /* partially-read + 0-set buffer */
-#else
return length_read_total; /* partially-read buffer */
-#endif
}
/* position to new offset */
@@ -90,13 +83,7 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST
/* if we can't get enough to satisfy the request (EOF) we give up */
if (length_read < length_to_read) {
memcpy(dest,streamfile->buffer,length_read);
-
-#if STREAMFILE_IGNORE_EOF
- memset(dest+length_read,0,length-length_read);
- return length_read_total + length; /* partially-read + 0-set buffer */
-#else
return length_read_total + length_read; /* partially-read buffer */
-#endif
}
/* use the new buffer */
@@ -110,38 +97,6 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST
return length_read_total;
}
-static size_t read_stdio(STDIOSTREAMFILE *streamfile,uint8_t * dest, off_t offset, size_t length) {
-
- if (!streamfile || !dest || length<=0)
- return 0;
-
- /* request outside file: ignore to avoid seek/read in read_the_rest() */
- if (offset > streamfile->filesize) {
- streamfile->offset = streamfile->filesize;
- VGM_LOG_ONCE("ERROR: offset over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length);
-
-#if STREAMFILE_IGNORE_EOF
- memset(dest,0,length);
- return length; /* 0-set buffer */
-#else
- return 0; /* nothing to read */
-#endif
- }
-
- /* just copy if entire request is within the buffer */
- if (offset >= streamfile->offset && offset + length <= streamfile->offset + streamfile->validsize) {
- off_t offset_into_buffer = offset - streamfile->offset;
- memcpy(dest,streamfile->buffer + offset_into_buffer,length);
- return length;
- }
-
- /* request outside buffer: new fread */
- {
- size_t length_read = read_the_rest(dest,offset,length,streamfile);
- return length_read;
- }
-}
-
static void close_stdio(STDIOSTREAMFILE * streamfile) {
fclose(streamfile->infile);
free(streamfile->buffer);
@@ -168,7 +123,7 @@ static STREAMFILE *open_stdio(STDIOSTREAMFILE *streamFile,const char * const fil
if (!filename)
return NULL;
-
+#if !defined (__ANDROID__)
// if same name, duplicate the file pointer we already have open
if (!strcmp(streamFile->name,filename)) {
if (((newfd = dup(fileno(streamFile->infile))) >= 0) &&
@@ -182,6 +137,7 @@ static STREAMFILE *open_stdio(STDIOSTREAMFILE *streamFile,const char * const fil
fclose(newfile);
}
}
+#endif
// a normal open, open a new file
return open_stdio_streamfile_buffer(filename,buffersize);
}
@@ -205,7 +161,6 @@ static STREAMFILE * open_stdio_streamfile_buffer_by_file(FILE *infile,const char
streamfile->sf.get_size = (void*)get_size_stdio;
streamfile->sf.get_offset = (void*)get_offset_stdio;
streamfile->sf.get_name = (void*)get_name_stdio;
- streamfile->sf.get_realname = (void*)get_name_stdio;
streamfile->sf.open = (void*)open_stdio;
streamfile->sf.close = (void*)close_stdio;
@@ -249,6 +204,145 @@ STREAMFILE * open_stdio_streamfile_by_file(FILE * file, const char * filename) {
/* **************************************************** */
+typedef struct {
+ STREAMFILE sf;
+
+ STREAMFILE *inner_sf;
+ off_t offset; /* current buffer data start */
+ uint8_t * buffer; /* data buffer */
+ size_t buffersize; /* max buffer size */
+ size_t validsize; /* current buffer size */
+ size_t filesize; /* buffered file size */
+} BUFFER_STREAMFILE;
+
+
+static size_t buffer_read(BUFFER_STREAMFILE *streamfile, uint8_t * dest, off_t offset, size_t length) {
+ size_t length_read_total = 0;
+
+ if (!streamfile || !dest || length <= 0 || offset < 0)
+ return 0;
+
+ /* is the part of the requested length in the buffer? */
+ if (offset >= streamfile->offset && offset < streamfile->offset + streamfile->validsize) {
+ size_t length_to_read;
+ off_t offset_into_buffer = offset - streamfile->offset;
+
+ length_to_read = streamfile->validsize - offset_into_buffer;
+ if (length_to_read > length)
+ length_to_read = length;
+
+ memcpy(dest,streamfile->buffer + offset_into_buffer,length_to_read);
+ length_read_total += length_to_read;
+ length -= length_to_read;
+ offset += length_to_read;
+ dest += length_to_read;
+ }
+
+ /* What would make more sense here is to read the whole request
+ * at once into the dest buffer, as it must be large enough, and then
+ * copy some part of that into our own buffer.
+ * The destination buffer is supposed to be much smaller than the
+ * STREAMFILE buffer, though. Maybe we should only ever return up
+ * to the buffer size to avoid having to deal with things like this
+ * which are outside of my intended use. */
+
+ /* read the rest of the requested length */
+ while (length > 0) {
+ size_t length_to_read, length_read;
+ streamfile->validsize = 0; /* buffer is empty now */
+
+ /* request outside file: ignore to avoid seek/read */
+ if (offset > streamfile->filesize) {
+ streamfile->offset = streamfile->filesize;
+ VGM_LOG_ONCE("ERROR: reading over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length);
+ return length_read_total; /* partially-read buffer */
+ }
+
+ streamfile->offset = offset;
+
+ /* decide how much must be read this time */
+ if (length > streamfile->buffersize)
+ length_to_read = streamfile->buffersize;
+ else
+ length_to_read = length;
+
+ /* fill the buffer */
+ length_read = streamfile->inner_sf->read(streamfile->inner_sf, streamfile->buffer, streamfile->offset, streamfile->buffersize);
+ streamfile->validsize = length_read;
+
+ /* if we can't get enough to satisfy the request (EOF) we give up */
+ if (length_read < length_to_read) {
+ memcpy(dest,streamfile->buffer,length_read);
+ return length_read_total + length_read; /* partially-read buffer */
+ }
+
+ /* use the new buffer */
+ memcpy(dest,streamfile->buffer,length_to_read);
+ length_read_total += length_to_read;
+ length -= length_to_read;
+ dest += length_to_read;
+ offset += length_to_read;
+ }
+
+ return length_read_total;
+}
+static size_t buffer_get_size(BUFFER_STREAMFILE * streamfile) {
+ return streamfile->filesize; /* cache */
+}
+static size_t buffer_get_offset(BUFFER_STREAMFILE * streamfile) {
+ return streamfile->offset; /* cache */ //todo internal offset?
+}
+static void buffer_get_name(BUFFER_STREAMFILE *streamfile, char *buffer, size_t length) {
+ streamfile->inner_sf->get_name(streamfile->inner_sf, buffer, length); /* default */
+}
+static STREAMFILE *buffer_open(BUFFER_STREAMFILE *streamfile, const char * const filename, size_t buffersize) {
+ STREAMFILE *new_inner_sf = streamfile->inner_sf->open(streamfile->inner_sf,filename,buffersize);
+ return open_buffer_streamfile(new_inner_sf, buffersize); /* original buffer size is preferable? */
+}
+static void buffer_close(BUFFER_STREAMFILE *streamfile) {
+ streamfile->inner_sf->close(streamfile->inner_sf);
+ free(streamfile->buffer);
+ free(streamfile);
+}
+
+STREAMFILE *open_buffer_streamfile(STREAMFILE *streamfile, size_t buffer_size) {
+ BUFFER_STREAMFILE *this_sf = NULL;
+
+ if (!streamfile) goto fail;
+
+ this_sf = calloc(1,sizeof(BUFFER_STREAMFILE));
+ if (!this_sf) goto fail;
+
+ this_sf->buffersize = buffer_size;
+ if (this_sf->buffersize == 0)
+ this_sf->buffersize = STREAMFILE_DEFAULT_BUFFER_SIZE;
+
+ this_sf->buffer = calloc(this_sf->buffersize,1);
+ if (!this_sf->buffer) goto fail;
+
+ /* set callbacks and internals */
+ this_sf->sf.read = (void*)buffer_read;
+ this_sf->sf.get_size = (void*)buffer_get_size;
+ this_sf->sf.get_offset = (void*)buffer_get_offset;
+ this_sf->sf.get_name = (void*)buffer_get_name;
+ this_sf->sf.open = (void*)buffer_open;
+ this_sf->sf.close = (void*)buffer_close;
+ this_sf->sf.stream_index = streamfile->stream_index;
+
+ this_sf->inner_sf = streamfile;
+
+ this_sf->filesize = streamfile->get_size(streamfile);
+
+ return &this_sf->sf;
+
+fail:
+ if (this_sf) free(this_sf->buffer);
+ free(this_sf);
+ return NULL;
+}
+
+/* **************************************************** */
+
//todo stream_index: copy? pass? funtion? external?
//todo use realnames on reopen? simplify?
//todo use safe string ops, this ain't easy
@@ -271,9 +365,6 @@ static size_t wrap_get_offset(WRAP_STREAMFILE * streamfile) {
static void wrap_get_name(WRAP_STREAMFILE *streamfile, char *buffer, size_t length) {
streamfile->inner_sf->get_name(streamfile->inner_sf, buffer, length); /* default */
}
-static void wrap_get_realname(WRAP_STREAMFILE *streamfile, char *buffer, size_t length) {
- streamfile->inner_sf->get_realname(streamfile->inner_sf, buffer, length); /* default */
-}
static void wrap_open(WRAP_STREAMFILE *streamfile, const char * const filename, size_t buffersize) {
streamfile->inner_sf->open(streamfile->inner_sf, filename, buffersize); /* default (don't wrap) */
}
@@ -295,7 +386,6 @@ STREAMFILE *open_wrap_streamfile(STREAMFILE *streamfile) {
this_sf->sf.get_size = (void*)wrap_get_size;
this_sf->sf.get_offset = (void*)wrap_get_offset;
this_sf->sf.get_name = (void*)wrap_get_name;
- this_sf->sf.get_realname = (void*)wrap_get_realname;
this_sf->sf.open = (void*)wrap_open;
this_sf->sf.close = (void*)wrap_close;
this_sf->sf.stream_index = streamfile->stream_index;
@@ -329,9 +419,6 @@ static off_t clamp_get_offset(CLAMP_STREAMFILE *streamfile) {
static void clamp_get_name(CLAMP_STREAMFILE *streamfile, char *buffer, size_t length) {
streamfile->inner_sf->get_name(streamfile->inner_sf, buffer, length); /* default */
}
-static void clamp_get_realname(CLAMP_STREAMFILE *streamfile, char *buffer, size_t length) {
- streamfile->inner_sf->get_realname(streamfile->inner_sf, buffer, length); /* default */
-}
static STREAMFILE *clamp_open(CLAMP_STREAMFILE *streamfile, const char * const filename, size_t buffersize) {
char original_filename[PATH_LIMIT];
STREAMFILE *new_inner_sf;
@@ -365,7 +452,6 @@ STREAMFILE *open_clamp_streamfile(STREAMFILE *streamfile, off_t start, size_t si
this_sf->sf.get_size = (void*)clamp_get_size;
this_sf->sf.get_offset = (void*)clamp_get_offset;
this_sf->sf.get_name = (void*)clamp_get_name;
- this_sf->sf.get_realname = (void*)clamp_get_realname;
this_sf->sf.open = (void*)clamp_open;
this_sf->sf.close = (void*)clamp_close;
this_sf->sf.stream_index = streamfile->stream_index;
@@ -383,16 +469,22 @@ typedef struct {
STREAMFILE sf;
STREAMFILE *inner_sf;
- void* data;
+ void* data; /* state for custom reads, malloc'ed + copied on open (to re-open streamfiles cleanly) */
size_t data_size;
- size_t (*read_callback)(STREAMFILE *, uint8_t *, off_t, size_t, void*);
+ size_t (*read_callback)(STREAMFILE *, uint8_t *, off_t, size_t, void*); /* custom read to modify data before copying into buffer */
+ size_t (*size_callback)(STREAMFILE *, void*); /* size when custom reads make data smaller/bigger than underlying streamfile */
+ //todo would need to make sure re-opened streamfiles work with this, maybe should use init_data_callback per call
+ //size_t (*close_data_callback)(STREAMFILE *, void*); /* called during close, allows to free stuff in data */
} IO_STREAMFILE;
static size_t io_read(IO_STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length) {
return streamfile->read_callback(streamfile->inner_sf, dest, offset, length, streamfile->data);
}
static size_t io_get_size(IO_STREAMFILE *streamfile) {
- return streamfile->inner_sf->get_size(streamfile->inner_sf); /* default */
+ if (streamfile->size_callback)
+ return streamfile->size_callback(streamfile->inner_sf, streamfile->data);
+ else
+ return streamfile->inner_sf->get_size(streamfile->inner_sf); /* default */
}
static off_t io_get_offset(IO_STREAMFILE *streamfile) {
return streamfile->inner_sf->get_offset(streamfile->inner_sf); /* default */
@@ -400,13 +492,10 @@ static off_t io_get_offset(IO_STREAMFILE *streamfile) {
static void io_get_name(IO_STREAMFILE *streamfile, char *buffer, size_t length) {
streamfile->inner_sf->get_name(streamfile->inner_sf, buffer, length); /* default */
}
-static void io_get_realname(IO_STREAMFILE *streamfile, char *buffer, size_t length) {
- streamfile->inner_sf->get_realname(streamfile->inner_sf, buffer, length); /* default */
-}
static STREAMFILE *io_open(IO_STREAMFILE *streamfile, const char * const filename, size_t buffersize) {
//todo should have some flag to decide if opening other files with IO
STREAMFILE *new_inner_sf = streamfile->inner_sf->open(streamfile->inner_sf,filename,buffersize);
- return open_io_streamfile(new_inner_sf, streamfile->data, streamfile->data_size, streamfile->read_callback);
+ return open_io_streamfile(new_inner_sf, streamfile->data, streamfile->data_size, streamfile->read_callback, streamfile->size_callback);
}
static void io_close(IO_STREAMFILE *streamfile) {
streamfile->inner_sf->close(streamfile->inner_sf);
@@ -414,7 +503,7 @@ static void io_close(IO_STREAMFILE *streamfile) {
free(streamfile);
}
-STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_size, void* read_callback) {
+STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_size, void* read_callback, void* size_callback) {
IO_STREAMFILE *this_sf;
if (!streamfile) return NULL;
@@ -428,7 +517,6 @@ STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_s
this_sf->sf.get_size = (void*)io_get_size;
this_sf->sf.get_offset = (void*)io_get_offset;
this_sf->sf.get_name = (void*)io_get_name;
- this_sf->sf.get_realname = (void*)io_get_realname;
this_sf->sf.open = (void*)io_open;
this_sf->sf.close = (void*)io_close;
this_sf->sf.stream_index = streamfile->stream_index;
@@ -444,6 +532,7 @@ STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_s
}
this_sf->data_size = data_size;
this_sf->read_callback = read_callback;
+ this_sf->size_callback = size_callback;
return &this_sf->sf;
}
@@ -470,9 +559,6 @@ static void fakename_get_name(FAKENAME_STREAMFILE *streamfile, char *buffer, siz
strncpy(buffer,streamfile->fakename,length);
buffer[length-1]='\0';
}
-static void fakename_get_realname(FAKENAME_STREAMFILE *streamfile, char *buffer, size_t length) {
- fakename_get_name(streamfile, buffer, length);
-}
static STREAMFILE *fakename_open(FAKENAME_STREAMFILE *streamfile, const char * const filename, size_t buffersize) {
/* detect re-opening the file */
if (strcmp(filename, streamfile->fakename) == 0) {
@@ -492,7 +578,7 @@ static void fakename_close(FAKENAME_STREAMFILE *streamfile) {
free(streamfile);
}
-STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, char * fakename, char* fakeext) {
+STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, const char * fakename, const char* fakeext) {
FAKENAME_STREAMFILE *this_sf;
if (!streamfile || (!fakename && !fakeext)) return NULL;
@@ -505,7 +591,6 @@ STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, char * fakename, ch
this_sf->sf.get_size = (void*)fakename_get_size;
this_sf->sf.get_offset = (void*)fakename_get_offset;
this_sf->sf.get_name = (void*)fakename_get_name;
- this_sf->sf.get_realname = (void*)fakename_get_realname;
this_sf->sf.open = (void*)fakename_open;
this_sf->sf.close = (void*)fakename_close;
this_sf->sf.stream_index = streamfile->stream_index;
@@ -586,9 +671,6 @@ static size_t multifile_get_offset(MULTIFILE_STREAMFILE * streamfile) {
static void multifile_get_name(MULTIFILE_STREAMFILE *streamfile, char *buffer, size_t length) {
streamfile->inner_sfs[0]->get_name(streamfile->inner_sfs[0], buffer, length);
}
-static void multifile_get_realname(MULTIFILE_STREAMFILE *streamfile, char *buffer, size_t length) {
- multifile_get_name(streamfile, buffer, length);
-}
static STREAMFILE *multifile_open(MULTIFILE_STREAMFILE *streamfile, const char * const filename, size_t buffersize) {
char original_filename[PATH_LIMIT];
STREAMFILE *new_sf = NULL;
@@ -628,8 +710,9 @@ fail:
static void multifile_close(MULTIFILE_STREAMFILE *streamfile) {
int i;
for (i = 0; i < streamfile->inner_sfs_size; i++) {
- for (i = 0; i < streamfile->inner_sfs_size; i++)
+ for (i = 0; i < streamfile->inner_sfs_size; i++) {
close_streamfile(streamfile->inner_sfs[i]);
+ }
}
free(streamfile->inner_sfs);
free(streamfile->sizes);
@@ -653,7 +736,6 @@ STREAMFILE *open_multifile_streamfile(STREAMFILE **streamfiles, size_t streamfil
this_sf->sf.get_size = (void*)multifile_get_size;
this_sf->sf.get_offset = (void*)multifile_get_offset;
this_sf->sf.get_name = (void*)multifile_get_name;
- this_sf->sf.get_realname = (void*)multifile_get_realname;
this_sf->sf.open = (void*)multifile_open;
this_sf->sf.close = (void*)multifile_close;
this_sf->sf.stream_index = streamfiles[0]->stream_index;
@@ -683,6 +765,37 @@ fail:
/* **************************************************** */
+STREAMFILE * open_streamfile_by_ext(STREAMFILE *streamFile, const char * ext) {
+ char filename_ext[PATH_LIMIT];
+
+ streamFile->get_name(streamFile,filename_ext,sizeof(filename_ext));
+ strcpy(filename_ext + strlen(filename_ext) - strlen(filename_extension(filename_ext)), ext);
+
+ return streamFile->open(streamFile,filename_ext,STREAMFILE_DEFAULT_BUFFER_SIZE);
+}
+
+STREAMFILE * open_streamfile_by_filename(STREAMFILE *streamFile, const char * name) {
+ char foldername[PATH_LIMIT];
+ char filename[PATH_LIMIT];
+ const char *path;
+
+ streamFile->get_name(streamFile,foldername,sizeof(foldername));
+
+ path = strrchr(foldername,DIR_SEPARATOR);
+ if (path!=NULL) path = path+1;
+
+ if (path) {
+ strcpy(filename, foldername);
+ filename[path-foldername] = '\0';
+ strcat(filename, name);
+ } else {
+ strcpy(filename, name);
+ }
+
+ return streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
+}
+
+
/* Read a line into dst. The source files are lines separated by CRLF (Windows) / LF (Unux) / CR (Mac).
* The line will be null-terminated and CR/LF removed if found.
*
@@ -739,17 +852,17 @@ size_t get_streamfile_text_line(int dst_length, char * dst, off_t offset, STREAM
}
-/* reads a c-string, up to maxsize or NULL, returning size. buf is optional. */
-int read_string(char * buf, size_t maxsize, off_t offset, STREAMFILE *streamFile) {
- int i;
+/* reads a c-string (ANSI only), up to maxsize or NULL, returning size. buf is optional (works as get_string_size). */
+size_t read_string(char * buf, size_t maxsize, off_t offset, STREAMFILE *streamFile) {
+ size_t pos;
- for (i=0; i < maxsize; i++) {
- char c = read_8bit(offset + i, streamFile);
- if (buf) buf[i] = c;
+ for (pos = 0; pos < maxsize; pos++) {
+ char c = read_8bit(offset + pos, streamFile);
+ if (buf) buf[pos] = c;
if (c == '\0')
- return i;
- if (i+1 == maxsize) { /* null at maxsize and don't validate (expected to be garbage) */
- if (buf) buf[i] = '\0';
+ return pos;
+ if (pos+1 == maxsize) { /* null at maxsize and don't validate (expected to be garbage) */
+ if (buf) buf[pos] = '\0';
return maxsize;
}
if (c < 0x20 || c > 0xA5)
@@ -761,37 +874,6 @@ fail:
return 0;
}
-/* Opens an stream using the base streamFile name plus a new extension (ex. for headers in a separate file) */
-STREAMFILE * open_stream_ext(STREAMFILE *streamFile, const char * ext) {
- char filename_ext[PATH_LIMIT];
-
- streamFile->get_name(streamFile,filename_ext,sizeof(filename_ext));
- strcpy(filename_ext + strlen(filename_ext) - strlen(filename_extension(filename_ext)), ext);
-
- return streamFile->open(streamFile,filename_ext,STREAMFILE_DEFAULT_BUFFER_SIZE);
-}
-
-/* Opens an stream using the passed name (in the same folder) */
-STREAMFILE * open_stream_name(STREAMFILE *streamFile, const char * name) {
- char foldername[PATH_LIMIT];
- char filename[PATH_LIMIT];
- const char *path;
-
- streamFile->get_name(streamFile,foldername,sizeof(foldername));
-
- path = strrchr(foldername,DIR_SEPARATOR);
- if (path!=NULL) path = path+1;
-
- if (path) {
- strcpy(filename, foldername);
- filename[path-foldername] = '\0';
- strcat(filename, name);
- } else {
- strcpy(filename, name);
- }
-
- return streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
-}
/* Opens a file containing decryption keys and copies to buffer.
* Tries combinations of keynames based on the original filename.
@@ -868,53 +950,10 @@ fail:
return 0;
}
-/**
- * open file containing looping data and copy to buffer
- *
- * returns true if found and copied
- */
-int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile) {
- char posname[PATH_LIMIT];
- char filename[PATH_LIMIT];
- /*size_t bytes_read;*/
- STREAMFILE * streamFilePos= NULL;
-
- streamFile->get_name(streamFile,filename,sizeof(filename));
-
- if (strlen(filename)+4 > sizeof(posname)) goto fail;
-
- /* try to open a posfile using variations: "(name.ext).pos" */
- {
- strcpy(posname, filename);
- strcat(posname, ".pos");
- streamFilePos = streamFile->open(streamFile,posname,STREAMFILE_DEFAULT_BUFFER_SIZE);
- if (streamFilePos) goto found;
-
- goto fail;
- }
-
-found:
- //if (get_streamfile_size(streamFilePos) != bufsize) goto fail;
-
- /* allow pos files to be of different sizes in case of new features, just fill all we can */
- memset(buf, 0, bufsize);
- read_streamfile(buf, 0, bufsize, streamFilePos);
-
- close_streamfile(streamFilePos);
-
- return 1;
-
-fail:
- if (streamFilePos) close_streamfile(streamFilePos);
-
- return 0;
-}
-
/**
- * checks if the stream filename is one of the extensions (comma-separated, ex. "adx" or "adx,aix")
- *
- * returns 0 on failure
+ * Checks if the stream filename is one of the extensions (comma-separated, ex. "adx" or "adx,aix").
+ * Empty is ok to accept files without extension ("", "adx,,aix"). Returns 0 on failure
*/
int check_extensions(STREAMFILE *streamFile, const char * cmp_exts) {
char filename[PATH_LIMIT];
@@ -989,11 +1028,32 @@ int find_chunk(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, in
return 0;
}
-int get_streamfile_name(STREAMFILE *streamFile, char * buffer, size_t size) {
+void get_streamfile_name(STREAMFILE *streamFile, char * buffer, size_t size) {
streamFile->get_name(streamFile,buffer,size);
- return 1;
}
-int get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size) {
+/* copies the filename without path */
+void get_streamfile_filename(STREAMFILE *streamFile, char * buffer, size_t size) {
+ char foldername[PATH_LIMIT];
+ const char *path;
+
+
+ streamFile->get_name(streamFile,foldername,sizeof(foldername));
+
+ //todo Windows CMD accepts both \\ and /, better way to handle this?
+ path = strrchr(foldername,'\\');
+ if (!path)
+ path = strrchr(foldername,'/');
+ if (path != NULL)
+ path = path+1;
+
+ //todo validate sizes and copy sensible max
+ if (path) {
+ strcpy(buffer, path);
+ } else {
+ strcpy(buffer, foldername);
+ }
+}
+void get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size) {
const char *path;
streamFile->get_name(streamFile,buffer,size);
@@ -1006,11 +1066,8 @@ int get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size) {
} else {
buffer[0] = '\0';
}
-
- return 1;
}
-int get_streamfile_ext(STREAMFILE *streamFile, char * filename, size_t size) {
+void get_streamfile_ext(STREAMFILE *streamFile, char * filename, size_t size) {
streamFile->get_name(streamFile,filename,size);
strcpy(filename, filename_extension(filename));
- return 1;
}
diff --git a/Frameworks/vgmstream/vgmstream/src/streamfile.h b/Frameworks/vgmstream/vgmstream/src/streamfile.h
index 49818e9ca..9e5333f4a 100644
--- a/Frameworks/vgmstream/vgmstream/src/streamfile.h
+++ b/Frameworks/vgmstream/vgmstream/src/streamfile.h
@@ -15,11 +15,8 @@
#include
#include "streamtypes.h"
#include "util.h"
-#if defined(ANDROID)
-#include
-#endif
-#if (defined(__MSVCRT__) || defined(_MSC_VER)) && !defined(ANDROID)
+#if defined(__MSVCRT__) || defined(_MSC_VER)
#include
#define fseeko fseek
#define ftello ftell
@@ -46,15 +43,14 @@
#endif
/* struct representing a file with callbacks. Code should use STREAMFILEs and not std C functions
- * to do file operations, as plugins may need to provide their own callbacks. */
+ * to do file operations, as plugins may need to provide their own callbacks.
+ * Reads from arbitrary offsets, meaning internally may need fseek equivalents during reads. */
typedef struct _STREAMFILE {
size_t (*read)(struct _STREAMFILE *,uint8_t * dest, off_t offset, size_t length);
size_t (*get_size)(struct _STREAMFILE *);
off_t (*get_offset)(struct _STREAMFILE *);
/* for dual-file support */
void (*get_name)(struct _STREAMFILE *,char *name,size_t length);
- /* for when the "name" is encoded specially, this is the actual user visible name */
- void (*get_realname)(struct _STREAMFILE *,char *name,size_t length);
struct _STREAMFILE * (*open)(struct _STREAMFILE *,const char * const filename,size_t buffersize);
void (*close)(struct _STREAMFILE *);
@@ -65,41 +61,56 @@ typedef struct _STREAMFILE {
} STREAMFILE;
-/* create a STREAMFILE from path */
-STREAMFILE * open_stdio_streamfile(const char * filename);
+/* Opens a standard STREAMFILE, opening from path.
+ * Uses stdio (FILE) for operations, thus plugins may not want to use it. */
+STREAMFILE *open_stdio_streamfile(const char * filename);
-/* create a STREAMFILE from pre-opened file path */
-STREAMFILE * open_stdio_streamfile_by_file(FILE * file, const char * filename);
+/* Opens a standard STREAMFILE from a pre-opened FILE. */
+STREAMFILE *open_stdio_streamfile_by_file(FILE * file, const char * filename);
-/* A STREAMFILE that doesn't close the underlying stream.
+/* Opens a STREAMFILE that does buffered IO.
+ * Can be used when the underlying IO may be slow (like when using custom IO).
+ * Buffer size is optional. */
+STREAMFILE *open_buffer_streamfile(STREAMFILE *streamfile, size_t buffer_size);
+
+/* Opens a STREAMFILE that doesn't close the underlying streamfile.
* Calls to open won't wrap the new SF (assumes it needs to be closed).
* Can be used in metas to test custom IO without closing the external SF. */
STREAMFILE *open_wrap_streamfile(STREAMFILE *streamfile);
-/* A STREAMFILE that clamps IO to a section of a larger stream.
- * Can be used with subfiles inside a bigger file, so it looks standard to a meta. */
+/* Opens a STREAMFILE that clamps reads to a section of a larger streamfile.
+ * Can be used with subfiles inside a bigger file (to fool metas, or to simplify custom IO). */
STREAMFILE *open_clamp_streamfile(STREAMFILE *streamfile, off_t start, size_t size);
-/* A STREAMFILE with custom IO, that clamps IO to a section of a larger stream.
- * Can be used with subfiles inside a bigger file, so it looks standard to a meta. */
-STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_size, void* read_callback);//void* size_callback, void* seek_callback);
+/* Opens a STREAMFILE that uses custom IO for streamfile reads.
+ * Can be used to modify data on the fly (ex. decryption), or even transform it from a format to another. */
+STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_size, void* read_callback, void* size_callback);
-/* A STREAMFILE that reports a fake name, but still re-opens itself properly.
+/* Opens a STREAMFILE that reports a fake name, but still re-opens itself properly.
* Can be used to trick a meta's extension check (to call from another, with a modified SF).
* When fakename isn't supplied it's read from the streamfile, and the extension swapped with fakeext.
* If the fakename is an existing file, open won't work on it as it'll reopen the fake-named streamfile. */
-STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, char * fakename, char * fakeext);
+STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, const char * fakename, const char * fakeext);
-/* A streamfile formed from multiple streamfiles, their data joined during reads.
+//todo probably could simply use custom IO
+/* Opens streamfile formed from multiple streamfiles, their data joined during reads.
* Can be used when data is segmented in multiple separate files.
* The first streamfile is used to get names, stream index and so on. */
STREAMFILE *open_multifile_streamfile(STREAMFILE **streamfiles, size_t streamfiles_size);
+/* Opens a STREAMFILE from a base pathname + new extension
+ * Can be used to get companion headers. */
+STREAMFILE * open_streamfile_by_ext(STREAMFILE *streamFile, const char * ext);
+
+/* Opens a STREAMFILE from a base path + new filename
+ * Can be used to get companion files. */
+STREAMFILE * open_streamfile_by_filename(STREAMFILE *streamFile, const char * filename);
+
/* close a file, destroy the STREAMFILE object */
static inline void close_streamfile(STREAMFILE * streamfile) {
- if (streamfile==NULL) return;
- streamfile->close(streamfile);
+ if (streamfile!=NULL)
+ streamfile->close(streamfile);
}
/* read from a file, returns number of bytes read */
@@ -164,13 +175,9 @@ static inline int8_t read_8bit(off_t offset, STREAMFILE * streamfile) {
size_t get_streamfile_text_line(int dst_length, char * dst, off_t offset, STREAMFILE * streamfile, int *line_done_ptr);
-STREAMFILE * open_stream_ext(STREAMFILE *streamFile, const char * ext);
-STREAMFILE * open_stream_name(STREAMFILE *streamFile, const char * ext);
-
-int read_string(char * buf, size_t bufsize, off_t offset, STREAMFILE *streamFile);
+size_t read_string(char * buf, size_t bufsize, off_t offset, STREAMFILE *streamFile);
size_t read_key_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile);
-int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile);
int check_extensions(STREAMFILE *streamFile, const char * cmp_exts);
@@ -178,7 +185,8 @@ int find_chunk_be(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset,
int find_chunk_le(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size);
int find_chunk(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int size_big_endian, int zero_size_end);
-int get_streamfile_name(STREAMFILE *streamFile, char * buffer, size_t size);
-int get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size);
-int get_streamfile_ext(STREAMFILE *streamFile, char * filename, size_t size);
+void get_streamfile_name(STREAMFILE *streamFile, char * buffer, size_t size);
+void get_streamfile_filename(STREAMFILE *streamFile, char * buffer, size_t size);
+void get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size);
+void get_streamfile_ext(STREAMFILE *streamFile, char * filename, size_t size);
#endif
diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c
index c9d883605..832b36b12 100644
--- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c
+++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c
@@ -30,6 +30,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_halpst,
init_vgmstream_rs03,
init_vgmstream_ngc_dsp_std,
+ init_vgmstream_ngc_dsp_std_le,
init_vgmstream_ngc_mdsp_std,
init_vgmstream_ngc_dsp_csmp,
init_vgmstream_cstr,
@@ -55,7 +56,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ps2_ild,
init_vgmstream_ps2_pnb,
init_vgmstream_xbox_wavm,
- init_vgmstream_xbox_xwav,
init_vgmstream_ngc_str,
init_vgmstream_ea_schl,
init_vgmstream_caf,
@@ -70,7 +70,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_mp4_aac,
#endif
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
- init_vgmstream_akb,
+ init_vgmstream_akb_mp4,
#endif
init_vgmstream_sadb,
init_vgmstream_ps2_bmdx,
@@ -119,7 +119,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_scd_pcm,
init_vgmstream_ps2_pcm,
init_vgmstream_ps2_rkv,
- init_vgmstream_ps2_psw,
init_vgmstream_ps2_vas,
init_vgmstream_ps2_tec,
init_vgmstream_ps2_enth,
@@ -155,6 +154,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ps2_ccc,
init_vgmstream_psx_fag,
init_vgmstream_ps2_mihb,
+ init_vgmstream_ngc_pdt_split,
init_vgmstream_ngc_pdt,
init_vgmstream_wii_mus,
init_vgmstream_dc_asd,
@@ -177,7 +177,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_bgw,
init_vgmstream_spw,
init_vgmstream_ps2_ass,
- init_vgmstream_waa_wac_wad_wam,
+ init_vgmstream_ubi_jade,
+ init_vgmstream_ubi_jade_container,
init_vgmstream_seg,
init_vgmstream_nds_strm_ffta2,
init_vgmstream_str_asr,
@@ -258,7 +259,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ps2_voi,
init_vgmstream_ps2_khv,
init_vgmstream_pc_smp,
- init_vgmstream_ngc_bo2,
+ init_vgmstream_ngc_rkv,
init_vgmstream_dsp_ddsp,
init_vgmstream_p3d,
init_vgmstream_ps2_tk1,
@@ -331,8 +332,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ps2_vds_vdm,
init_vgmstream_x360_cxs,
init_vgmstream_dsp_adx,
- init_vgmstream_akb_multi,
- init_vgmstream_akb2_multi,
+ init_vgmstream_akb,
+ init_vgmstream_akb2,
#ifdef VGM_USE_FFMPEG
init_vgmstream_mp4_aac_ffmpeg,
#endif
@@ -351,6 +352,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ta_aac_x360,
init_vgmstream_ta_aac_ps3,
init_vgmstream_ta_aac_mobile,
+ init_vgmstream_ta_aac_mobile_vorbis,
init_vgmstream_ps3_mta2,
init_vgmstream_ngc_ulw,
init_vgmstream_pc_xa30,
@@ -361,7 +363,10 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_stm,
init_vgmstream_ea_snu,
init_vgmstream_awc,
- init_vgmstream_nsw_opus,
+ init_vgmstream_opus_std,
+ init_vgmstream_opus_n1,
+ init_vgmstream_opus_capcom,
+ init_vgmstream_opus_nop,
init_vgmstream_pc_al2,
init_vgmstream_pc_ast,
init_vgmstream_naac,
@@ -376,10 +381,32 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_kma9,
init_vgmstream_fsb_encrypted,
init_vgmstream_xwc,
- init_vgmstream_atsl3,
+ init_vgmstream_atsl,
init_vgmstream_sps_n1,
init_vgmstream_atx,
init_vgmstream_sqex_sead,
+ init_vgmstream_waf,
+ init_vgmstream_wave,
+ init_vgmstream_wave_segmented,
+ init_vgmstream_rsd6at3p,
+ init_vgmstream_rsd6wma,
+ init_vgmstream_smv,
+ init_vgmstream_nxap,
+ init_vgmstream_ea_wve_au00,
+ init_vgmstream_ea_wve_ad10,
+ init_vgmstream_sthd,
+ init_vgmstream_pcm_sre,
+ init_vgmstream_dsp_mcadpcm,
+ init_vgmstream_ubi_lyn,
+ init_vgmstream_ubi_lyn_container,
+ init_vgmstream_msb_msh,
+ init_vgmstream_txtp,
+ init_vgmstream_smc_smh,
+ init_vgmstream_ea_sps_fb,
+ init_vgmstream_ppst,
+ init_vgmstream_opus_ppp,
+ init_vgmstream_ubi_bao_pk,
+ init_vgmstream_dsp_switch_audio,
init_vgmstream_txth, /* should go at the end (lower priority) */
#ifdef VGM_USE_FFMPEG
@@ -453,14 +480,16 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile) {
/* check FFmpeg streams here, for lack of a better place */
if (vgmstream->coding_type == coding_FFmpeg) {
ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data;
- if (data->streamCount && !vgmstream->num_streams) {
+ if (data && data->streamCount && !vgmstream->num_streams) {
vgmstream->num_streams = data->streamCount;
}
}
#endif
/* save info */
- vgmstream->stream_index = streamFile->stream_index;
+ /* stream_index 0 may be used by plugins to signal "vgmstream default" (IOW don't force to 1) */
+ if (!vgmstream->stream_index)
+ vgmstream->stream_index = streamFile->stream_index;
/* save start things so we can restart for seeking */
memcpy(vgmstream->start_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels);
@@ -503,7 +532,7 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
* really hit the loop start. */
#ifdef VGM_USE_VORBIS
- if (vgmstream->coding_type==coding_ogg_vorbis) {
+ if (vgmstream->coding_type==coding_OGG_VORBIS) {
reset_ogg_vorbis(vgmstream);
}
@@ -568,25 +597,13 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
#endif
if (vgmstream->coding_type==coding_ACM) {
- mus_acm_codec_data *data = vgmstream->codec_data;
- int i;
-
- data->current_file = 0;
- for (i=0;ifile_count;i++) {
- acm_reset(data->files[i]);
- }
+ reset_acm(vgmstream);
}
- if (
- vgmstream->coding_type == coding_NWA0 ||
- vgmstream->coding_type == coding_NWA1 ||
- vgmstream->coding_type == coding_NWA2 ||
- vgmstream->coding_type == coding_NWA3 ||
- vgmstream->coding_type == coding_NWA4 ||
- vgmstream->coding_type == coding_NWA5
- ) {
+ if (vgmstream->coding_type == coding_NWA) {
nwa_codec_data *data = vgmstream->codec_data;
- reset_nwa(data->nwa);
+ if (data)
+ reset_nwa(data->nwa);
}
@@ -600,23 +617,12 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
}
}
- if (vgmstream->layout_type==layout_aax) {
- aax_codec_data *data = vgmstream->codec_data;
- int i;
-
- data->current_segment = 0;
- for (i=0;i