VGMStream: Updated libvgmstream code base

Updated VGMStream to r1980-242-gfccbb05f

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2025-04-20 21:33:11 -07:00
parent baf8d1e745
commit 531c2b1468
88 changed files with 5949 additions and 5749 deletions

View file

@ -24,7 +24,7 @@
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 */; };
8306B0A720984552000302D4 /* blocked_vas_kceo.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B08C2098454D000302D4 /* blocked_vas_kceo.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 */; };
@ -41,7 +41,7 @@
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 */; };
8306B0BB20984552000302D4 /* blocked_gsnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0A020984551000302D4 /* blocked_gsnd.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 */; };
@ -185,6 +185,8 @@
8346D97C25BF838C00D1A8B0 /* mjb_mjh.c in Sources */ = {isa = PBXBuildFile; fileRef = 8346D97725BF838C00D1A8B0 /* mjb_mjh.c */; };
8346D97D25BF838C00D1A8B0 /* compresswave.c in Sources */ = {isa = PBXBuildFile; fileRef = 8346D97825BF838C00D1A8B0 /* compresswave.c */; };
834845782D27F2E9000E4928 /* decode_state.h in Headers */ = {isa = PBXBuildFile; fileRef = 834845772D27F2E9000E4928 /* decode_state.h */; };
834960FC2DB5FD430019C8CA /* ssp.c in Sources */ = {isa = PBXBuildFile; fileRef = 834960FB2DB5FD430019C8CA /* ssp.c */; };
834960FE2DB5FEF90019C8CA /* ualaw_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834960FD2DB5FEF90019C8CA /* ualaw_decoder.c */; };
8349A8E81FE6253900E26435 /* blocked_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8E21FE6253800E26435 /* blocked_dec.c */; };
8349A8E91FE6253900E26435 /* blocked_ea_1snh.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8E31FE6253800E26435 /* blocked_ea_1snh.c */; };
8349A8EA1FE6253900E26435 /* blocked_ea_schl.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8E41FE6253800E26435 /* blocked_ea_schl.c */; };
@ -192,7 +194,7 @@
8349A8ED1FE6253900E26435 /* blocked_ea_sns.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8E71FE6253900E26435 /* blocked_ea_sns.c */; };
8349A9071FE6258200E26435 /* dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8EE1FE6257C00E26435 /* dec.c */; };
8349A9081FE6258200E26435 /* ezw.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8EF1FE6257C00E26435 /* ezw.c */; };
8349A9091FE6258200E26435 /* pc_ast.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8F01FE6257C00E26435 /* pc_ast.c */; };
8349A9091FE6258200E26435 /* astl.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8F01FE6257C00E26435 /* astl.c */; };
8349A90A1FE6258200E26435 /* sab.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8F11FE6257D00E26435 /* sab.c */; };
8349A90B1FE6258200E26435 /* pcm_kceje.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8F21FE6257D00E26435 /* pcm_kceje.c */; };
8349A90D1FE6258200E26435 /* ubi_sb.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8F41FE6257D00E26435 /* ubi_sb.c */; };
@ -229,7 +231,7 @@
834F7D192C708701003AC386 /* awc_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D172C708701003AC386 /* awc_streamfile.h */; };
834F7D1C2C708719003AC386 /* cipher_xxtea.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D1A2C708719003AC386 /* cipher_xxtea.c */; };
834F7D1D2C708719003AC386 /* cipher_xxtea.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D1B2C708719003AC386 /* cipher_xxtea.h */; };
834F7D252C7088B9003AC386 /* cbx.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D242C7088B9003AC386 /* cbx.c */; };
834F7D252C7088B9003AC386 /* chatterbox.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D242C7088B9003AC386 /* chatterbox.c */; };
834F7D292C708A2F003AC386 /* vas_rockstar.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D282C708A2F003AC386 /* vas_rockstar.c */; };
834F7D2B2C708A5B003AC386 /* blocked_vas.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D2A2C708A5B003AC386 /* blocked_vas.c */; };
834F7D2F2C708D32003AC386 /* rage_aud_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D2E2C708D31003AC386 /* rage_aud_streamfile.h */; };
@ -420,7 +422,7 @@
834FE0F8215C79ED000A5D3D /* adpcm_capcom.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0CF215C79E8000A5D3D /* adpcm_capcom.c */; };
834FE0F9215C79ED000A5D3D /* wavebatch.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0D0215C79E8000A5D3D /* wavebatch.c */; };
834FE0FA215C79ED000A5D3D /* nus3bank.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0D1215C79E9000A5D3D /* nus3bank.c */; };
834FE0FB215C79ED000A5D3D /* xau_konami.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0D2215C79E9000A5D3D /* xau_konami.c */; };
834FE0FB215C79ED000A5D3D /* sfxb.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0D2215C79E9000A5D3D /* sfxb.c */; };
834FE0FC215C79ED000A5D3D /* vai.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0D3215C79E9000A5D3D /* vai.c */; };
834FE0FD215C79ED000A5D3D /* vpk.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0D4215C79E9000A5D3D /* vpk.c */; };
834FE0FE215C79ED000A5D3D /* ps_headerless.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0D5215C79E9000A5D3D /* ps_headerless.c */; };
@ -499,7 +501,7 @@
836F6F7F18BDC2190095E648 /* dmsg_segh.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4318BDC2180095E648 /* dmsg_segh.c */; };
836F6F8218BDC2190095E648 /* ea_schl.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4618BDC2180095E648 /* ea_schl.c */; };
836F6F8518BDC2190095E648 /* exakt_sc.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4918BDC2180095E648 /* exakt_sc.c */; };
836F6F8618BDC2190095E648 /* excitebots.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4A18BDC2180095E648 /* excitebots.c */; };
836F6F8618BDC2190095E648 /* sfx0_monster.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4A18BDC2180095E648 /* sfx0_monster.c */; };
836F6F8818BDC2190095E648 /* fsb.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4C18BDC2180095E648 /* fsb.c */; };
836F6F8918BDC2190095E648 /* gca.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4D18BDC2180095E648 /* gca.c */; };
836F6F8A18BDC2190095E648 /* gcsw.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4E18BDC2180095E648 /* gcsw.c */; };
@ -531,9 +533,9 @@
836F6FAE18BDC2190095E648 /* mpds.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7218BDC2180095E648 /* mpds.c */; };
836F6FAF18BDC2190095E648 /* ngc_dsp_std.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7318BDC2180095E648 /* ngc_dsp_std.c */; };
836F6FB018BDC2190095E648 /* dsp_kceje.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7418BDC2180095E648 /* dsp_kceje.c */; };
836F6FB118BDC2190095E648 /* ngc_ffcc_str.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7518BDC2180095E648 /* ngc_ffcc_str.c */; };
836F6FB318BDC2190095E648 /* ngc_lps.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7718BDC2180095E648 /* ngc_lps.c */; };
836F6FB418BDC2190095E648 /* ngc_nst_dsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7818BDC2180095E648 /* ngc_nst_dsp.c */; };
836F6FB118BDC2190095E648 /* str_sqex.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7518BDC2180095E648 /* str_sqex.c */; };
836F6FB318BDC2190095E648 /* lps.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7718BDC2180095E648 /* lps.c */; };
836F6FB418BDC2190095E648 /* nst_monster.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7818BDC2180095E648 /* nst_monster.c */; };
836F6FB518BDC2190095E648 /* ngc_pdt.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7918BDC2180095E648 /* ngc_pdt.c */; };
836F6FB618BDC2190095E648 /* ngc_sck_dsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7A18BDC2180095E648 /* ngc_sck_dsp.c */; };
836F6FB718BDC2190095E648 /* ngc_ssm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7B18BDC2180095E648 /* ngc_ssm.c */; };
@ -557,13 +559,12 @@
836F6FD918BDC2190095E648 /* mcg.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9D18BDC2180095E648 /* mcg.c */; };
836F6FDA18BDC2190095E648 /* hgc1.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9E18BDC2180095E648 /* hgc1.c */; };
836F6FDB18BDC2190095E648 /* ps2_hsf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9F18BDC2180095E648 /* ps2_hsf.c */; };
836F6FDC18BDC2190095E648 /* ps2_iab.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA018BDC2180095E648 /* ps2_iab.c */; };
836F6FDC18BDC2190095E648 /* iab.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA018BDC2180095E648 /* iab.c */; };
836F6FDE18BDC2190095E648 /* ild.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA218BDC2180095E648 /* ild.c */; };
836F6FE018BDC2190095E648 /* ps2_joe.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA418BDC2180095E648 /* ps2_joe.c */; };
836F6FE218BDC2190095E648 /* vig_kces.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA618BDC2180095E648 /* vig_kces.c */; };
836F6FE818BDC2190095E648 /* mic_koei.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EAC18BDC2180095E648 /* mic_koei.c */; };
836F6FEE18BDC2190095E648 /* p2bt_move_visa.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB218BDC2180095E648 /* p2bt_move_visa.c */; };
836F6FF218BDC2190095E648 /* ps2_rnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB618BDC2180095E648 /* ps2_rnd.c */; };
836F6FF418BDC2190095E648 /* rws_80d.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB818BDC2180095E648 /* rws_80d.c */; };
836F6FF618BDC2190095E648 /* ster.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBA18BDC2180095E648 /* ster.c */; };
836F6FF718BDC2190095E648 /* sl3.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBB18BDC2180095E648 /* sl3.c */; };
@ -575,7 +576,7 @@
836F700418BDC2190095E648 /* vas_kceo.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC818BDC2190095E648 /* vas_kceo.c */; };
836F700518BDC2190095E648 /* ps2_vbk.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC918BDC2190095E648 /* ps2_vbk.c */; };
836F700618BDC2190095E648 /* vgs_ps.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ECA18BDC2190095E648 /* vgs_ps.c */; };
836F700718BDC2190095E648 /* ps2_vgv.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ECB18BDC2190095E648 /* ps2_vgv.c */; };
836F700718BDC2190095E648 /* vgv.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ECB18BDC2190095E648 /* vgv.c */; };
836F700818BDC2190095E648 /* ps2_vms.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ECC18BDC2190095E648 /* ps2_vms.c */; };
836F700918BDC2190095E648 /* voi.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ECD18BDC2190095E648 /* voi.c */; };
836F700B18BDC2190095E648 /* ps2_wad.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ECF18BDC2190095E648 /* ps2_wad.c */; };
@ -612,7 +613,7 @@
836F703C18BDC2190095E648 /* bns.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0018BDC2190095E648 /* bns.c */; };
836F703D18BDC2190095E648 /* mus_krome.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0118BDC2190095E648 /* mus_krome.c */; };
836F703E18BDC2190095E648 /* ras.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0218BDC2190095E648 /* ras.c */; };
836F704018BDC2190095E648 /* wii_sng.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0418BDC2190095E648 /* wii_sng.c */; };
836F704018BDC2190095E648 /* song_monster.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0418BDC2190095E648 /* song_monster.c */; };
836F704218BDC2190095E648 /* sts.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0618BDC2190095E648 /* sts.c */; };
836F704318BDC2190095E648 /* wpd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0718BDC2190095E648 /* wpd.c */; };
836F704418BDC2190095E648 /* ws_aud.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F0818BDC2190095E648 /* ws_aud.c */; };
@ -632,7 +633,7 @@
836F705918BDC2190095E648 /* vgmstream.h in Headers */ = {isa = PBXBuildFile; fileRef = 836F6F1D18BDC2190095E648 /* vgmstream.h */; settings = {ATTRIBUTES = (Public, ); }; };
83709E051ECBC1A4005C03D3 /* ghs.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709DFF1ECBC1A4005C03D3 /* ghs.c */; };
83709E061ECBC1A4005C03D3 /* mpc3.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E001ECBC1A4005C03D3 /* mpc3.c */; };
83709E071ECBC1A4005C03D3 /* mss.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E011ECBC1A4005C03D3 /* mss.c */; };
83709E071ECBC1A4005C03D3 /* mcss.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E011ECBC1A4005C03D3 /* mcss.c */; };
83709E091ECBC1A4005C03D3 /* aac_triace.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E031ECBC1A4005C03D3 /* aac_triace.c */; };
8373342623F60CDC00DE14DC /* deblock_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8373341E23F60CDB00DE14DC /* deblock_streamfile.h */; };
8373342723F60CDC00DE14DC /* lrmd_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8373341F23F60CDB00DE14DC /* lrmd_streamfile.h */; };
@ -832,7 +833,7 @@
83E22FC12772FD06000015EE /* libbz2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 83E22FBD2772FD06000015EE /* libbz2.tbd */; };
83E22FC32772FD16000015EE /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83E22FC22772FD16000015EE /* AudioToolbox.framework */; };
83E7FD6525EF2B2400683FD2 /* tac.c in Sources */ = {isa = PBXBuildFile; fileRef = 83E7FD6425EF2B2400683FD2 /* tac.c */; };
83EDE5D81A70951A005F5D84 /* mca.c in Sources */ = {isa = PBXBuildFile; fileRef = 83EDE5D61A70951A005F5D84 /* mca.c */; };
83EDE5D81A70951A005F5D84 /* madp.c in Sources */ = {isa = PBXBuildFile; fileRef = 83EDE5D61A70951A005F5D84 /* madp.c */; };
83EDE5D91A70951A005F5D84 /* btsnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 83EDE5D71A70951A005F5D84 /* btsnd.c */; };
83EED5D3203A8BC7008BEB45 /* ea_swvr.c in Sources */ = {isa = PBXBuildFile; fileRef = 83EED5D1203A8BC7008BEB45 /* ea_swvr.c */; };
83EED5D4203A8BC7008BEB45 /* aus.c in Sources */ = {isa = PBXBuildFile; fileRef = 83EED5D2203A8BC7008BEB45 /* aus.c */; };
@ -977,7 +978,7 @@
8306B0892098454D000302D4 /* segmented.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = segmented.c; sourceTree = "<group>"; };
8306B08A2098454D000302D4 /* blocked_ea_wve_au00.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ea_wve_au00.c; sourceTree = "<group>"; };
8306B08B2098454D000302D4 /* blocked_ea_wve_ad10.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ea_wve_ad10.c; sourceTree = "<group>"; };
8306B08C2098454D000302D4 /* blocked_xvas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_xvas.c; sourceTree = "<group>"; };
8306B08C2098454D000302D4 /* blocked_vas_kceo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_vas_kceo.c; sourceTree = "<group>"; };
8306B08D2098454D000302D4 /* blocked_ps2_iab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ps2_iab.c; sourceTree = "<group>"; };
8306B08E2098454E000302D4 /* blocked_adm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_adm.c; sourceTree = "<group>"; };
8306B08F2098454E000302D4 /* blocked_sthd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_sthd.c; sourceTree = "<group>"; };
@ -994,7 +995,7 @@
8306B09D20984551000302D4 /* blocked_ws_aud.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ws_aud.c; sourceTree = "<group>"; };
8306B09E20984551000302D4 /* blocked_matx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_matx.c; sourceTree = "<group>"; };
8306B09F20984551000302D4 /* blocked_wsi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_wsi.c; sourceTree = "<group>"; };
8306B0A020984551000302D4 /* blocked_gsb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_gsb.c; sourceTree = "<group>"; };
8306B0A020984551000302D4 /* blocked_gsnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_gsnd.c; sourceTree = "<group>"; };
8306B0A120984551000302D4 /* blocked_vs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_vs.c; sourceTree = "<group>"; };
8306B0BD2098458B000302D4 /* ea_eaac_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ea_eaac_streamfile.h; sourceTree = "<group>"; };
8306B0BE2098458C000302D4 /* ngc_str_cauldron.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_str_cauldron.c; sourceTree = "<group>"; };
@ -1138,6 +1139,8 @@
8346D97725BF838C00D1A8B0 /* mjb_mjh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mjb_mjh.c; sourceTree = "<group>"; };
8346D97825BF838C00D1A8B0 /* compresswave.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compresswave.c; sourceTree = "<group>"; };
834845772D27F2E9000E4928 /* decode_state.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = decode_state.h; sourceTree = "<group>"; };
834960FB2DB5FD430019C8CA /* ssp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ssp.c; sourceTree = "<group>"; };
834960FD2DB5FEF90019C8CA /* ualaw_decoder.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ualaw_decoder.c; sourceTree = "<group>"; };
8349A8E21FE6253800E26435 /* blocked_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_dec.c; sourceTree = "<group>"; };
8349A8E31FE6253800E26435 /* blocked_ea_1snh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ea_1snh.c; sourceTree = "<group>"; };
8349A8E41FE6253800E26435 /* blocked_ea_schl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ea_schl.c; sourceTree = "<group>"; };
@ -1145,7 +1148,7 @@
8349A8E71FE6253900E26435 /* blocked_ea_sns.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ea_sns.c; sourceTree = "<group>"; };
8349A8EE1FE6257C00E26435 /* dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dec.c; sourceTree = "<group>"; };
8349A8EF1FE6257C00E26435 /* ezw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ezw.c; sourceTree = "<group>"; };
8349A8F01FE6257C00E26435 /* pc_ast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pc_ast.c; sourceTree = "<group>"; };
8349A8F01FE6257C00E26435 /* astl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = astl.c; sourceTree = "<group>"; };
8349A8F11FE6257D00E26435 /* sab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sab.c; sourceTree = "<group>"; };
8349A8F21FE6257D00E26435 /* pcm_kceje.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pcm_kceje.c; sourceTree = "<group>"; };
8349A8F41FE6257D00E26435 /* ubi_sb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ubi_sb.c; sourceTree = "<group>"; };
@ -1182,7 +1185,7 @@
834F7D172C708701003AC386 /* awc_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = awc_streamfile.h; sourceTree = "<group>"; };
834F7D1A2C708719003AC386 /* cipher_xxtea.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cipher_xxtea.c; sourceTree = "<group>"; };
834F7D1B2C708719003AC386 /* cipher_xxtea.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cipher_xxtea.h; sourceTree = "<group>"; };
834F7D242C7088B9003AC386 /* cbx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cbx.c; sourceTree = "<group>"; };
834F7D242C7088B9003AC386 /* chatterbox.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = chatterbox.c; sourceTree = "<group>"; };
834F7D282C708A2F003AC386 /* vas_rockstar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vas_rockstar.c; sourceTree = "<group>"; };
834F7D2A2C708A5B003AC386 /* blocked_vas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_vas.c; sourceTree = "<group>"; };
834F7D2E2C708D31003AC386 /* rage_aud_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rage_aud_streamfile.h; sourceTree = "<group>"; };
@ -1372,7 +1375,7 @@
834FE0CF215C79E8000A5D3D /* adpcm_capcom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adpcm_capcom.c; sourceTree = "<group>"; };
834FE0D0215C79E8000A5D3D /* wavebatch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wavebatch.c; sourceTree = "<group>"; };
834FE0D1215C79E9000A5D3D /* nus3bank.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nus3bank.c; sourceTree = "<group>"; };
834FE0D2215C79E9000A5D3D /* xau_konami.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xau_konami.c; sourceTree = "<group>"; };
834FE0D2215C79E9000A5D3D /* sfxb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sfxb.c; sourceTree = "<group>"; };
834FE0D3215C79E9000A5D3D /* vai.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vai.c; sourceTree = "<group>"; };
834FE0D4215C79E9000A5D3D /* vpk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vpk.c; sourceTree = "<group>"; };
834FE0D5215C79E9000A5D3D /* ps_headerless.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps_headerless.c; sourceTree = "<group>"; };
@ -1452,7 +1455,7 @@
836F6E4318BDC2180095E648 /* dmsg_segh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dmsg_segh.c; sourceTree = "<group>"; };
836F6E4618BDC2180095E648 /* ea_schl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_schl.c; sourceTree = "<group>"; };
836F6E4918BDC2180095E648 /* exakt_sc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exakt_sc.c; sourceTree = "<group>"; };
836F6E4A18BDC2180095E648 /* excitebots.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = excitebots.c; sourceTree = "<group>"; };
836F6E4A18BDC2180095E648 /* sfx0_monster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sfx0_monster.c; sourceTree = "<group>"; };
836F6E4C18BDC2180095E648 /* fsb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fsb.c; sourceTree = "<group>"; };
836F6E4D18BDC2180095E648 /* gca.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gca.c; sourceTree = "<group>"; };
836F6E4E18BDC2180095E648 /* gcsw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gcsw.c; sourceTree = "<group>"; };
@ -1484,9 +1487,9 @@
836F6E7218BDC2180095E648 /* mpds.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mpds.c; sourceTree = "<group>"; };
836F6E7318BDC2180095E648 /* ngc_dsp_std.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_dsp_std.c; sourceTree = "<group>"; };
836F6E7418BDC2180095E648 /* dsp_kceje.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dsp_kceje.c; sourceTree = "<group>"; };
836F6E7518BDC2180095E648 /* ngc_ffcc_str.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_ffcc_str.c; sourceTree = "<group>"; };
836F6E7718BDC2180095E648 /* ngc_lps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_lps.c; sourceTree = "<group>"; };
836F6E7818BDC2180095E648 /* ngc_nst_dsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_nst_dsp.c; sourceTree = "<group>"; };
836F6E7518BDC2180095E648 /* str_sqex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = str_sqex.c; sourceTree = "<group>"; };
836F6E7718BDC2180095E648 /* lps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lps.c; sourceTree = "<group>"; };
836F6E7818BDC2180095E648 /* nst_monster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nst_monster.c; sourceTree = "<group>"; };
836F6E7918BDC2180095E648 /* ngc_pdt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_pdt.c; sourceTree = "<group>"; };
836F6E7A18BDC2180095E648 /* ngc_sck_dsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_sck_dsp.c; sourceTree = "<group>"; };
836F6E7B18BDC2180095E648 /* ngc_ssm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_ssm.c; sourceTree = "<group>"; };
@ -1510,13 +1513,12 @@
836F6E9D18BDC2180095E648 /* mcg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mcg.c; sourceTree = "<group>"; };
836F6E9E18BDC2180095E648 /* hgc1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hgc1.c; sourceTree = "<group>"; };
836F6E9F18BDC2180095E648 /* ps2_hsf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_hsf.c; sourceTree = "<group>"; };
836F6EA018BDC2180095E648 /* ps2_iab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_iab.c; sourceTree = "<group>"; };
836F6EA018BDC2180095E648 /* iab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iab.c; sourceTree = "<group>"; };
836F6EA218BDC2180095E648 /* ild.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ild.c; sourceTree = "<group>"; };
836F6EA418BDC2180095E648 /* ps2_joe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_joe.c; sourceTree = "<group>"; };
836F6EA618BDC2180095E648 /* vig_kces.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vig_kces.c; sourceTree = "<group>"; };
836F6EAC18BDC2180095E648 /* mic_koei.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mic_koei.c; sourceTree = "<group>"; };
836F6EB218BDC2180095E648 /* p2bt_move_visa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = p2bt_move_visa.c; sourceTree = "<group>"; };
836F6EB618BDC2180095E648 /* ps2_rnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rnd.c; sourceTree = "<group>"; };
836F6EB818BDC2180095E648 /* rws_80d.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rws_80d.c; sourceTree = "<group>"; };
836F6EBA18BDC2180095E648 /* ster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ster.c; sourceTree = "<group>"; };
836F6EBB18BDC2180095E648 /* sl3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sl3.c; sourceTree = "<group>"; };
@ -1528,7 +1530,7 @@
836F6EC818BDC2190095E648 /* vas_kceo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vas_kceo.c; sourceTree = "<group>"; };
836F6EC918BDC2190095E648 /* ps2_vbk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_vbk.c; sourceTree = "<group>"; };
836F6ECA18BDC2190095E648 /* vgs_ps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vgs_ps.c; sourceTree = "<group>"; };
836F6ECB18BDC2190095E648 /* ps2_vgv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_vgv.c; sourceTree = "<group>"; };
836F6ECB18BDC2190095E648 /* vgv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vgv.c; sourceTree = "<group>"; };
836F6ECC18BDC2190095E648 /* ps2_vms.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_vms.c; sourceTree = "<group>"; };
836F6ECD18BDC2190095E648 /* voi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = voi.c; sourceTree = "<group>"; };
836F6ECF18BDC2190095E648 /* ps2_wad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_wad.c; sourceTree = "<group>"; };
@ -1565,7 +1567,7 @@
836F6F0018BDC2190095E648 /* bns.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bns.c; sourceTree = "<group>"; };
836F6F0118BDC2190095E648 /* mus_krome.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mus_krome.c; sourceTree = "<group>"; };
836F6F0218BDC2190095E648 /* ras.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ras.c; sourceTree = "<group>"; };
836F6F0418BDC2190095E648 /* wii_sng.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wii_sng.c; sourceTree = "<group>"; };
836F6F0418BDC2190095E648 /* song_monster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = song_monster.c; sourceTree = "<group>"; };
836F6F0618BDC2190095E648 /* sts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sts.c; sourceTree = "<group>"; };
836F6F0718BDC2190095E648 /* wpd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wpd.c; sourceTree = "<group>"; };
836F6F0818BDC2190095E648 /* ws_aud.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ws_aud.c; sourceTree = "<group>"; };
@ -1585,7 +1587,7 @@
836F6F1D18BDC2190095E648 /* vgmstream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vgmstream.h; sourceTree = "<group>"; };
83709DFF1ECBC1A4005C03D3 /* ghs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ghs.c; sourceTree = "<group>"; };
83709E001ECBC1A4005C03D3 /* mpc3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mpc3.c; sourceTree = "<group>"; };
83709E011ECBC1A4005C03D3 /* mss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mss.c; sourceTree = "<group>"; };
83709E011ECBC1A4005C03D3 /* mcss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mcss.c; sourceTree = "<group>"; };
83709E031ECBC1A4005C03D3 /* aac_triace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aac_triace.c; sourceTree = "<group>"; };
8373341E23F60CDB00DE14DC /* deblock_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = deblock_streamfile.h; sourceTree = "<group>"; };
8373341F23F60CDB00DE14DC /* lrmd_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lrmd_streamfile.h; sourceTree = "<group>"; };
@ -1785,7 +1787,7 @@
83E22FBD2772FD06000015EE /* libbz2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libbz2.tbd; path = usr/lib/libbz2.tbd; sourceTree = SDKROOT; };
83E22FC22772FD16000015EE /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
83E7FD6425EF2B2400683FD2 /* tac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tac.c; sourceTree = "<group>"; };
83EDE5D61A70951A005F5D84 /* mca.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mca.c; sourceTree = "<group>"; };
83EDE5D61A70951A005F5D84 /* madp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = madp.c; sourceTree = "<group>"; };
83EDE5D71A70951A005F5D84 /* btsnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = btsnd.c; sourceTree = "<group>"; };
83EED5D1203A8BC7008BEB45 /* ea_swvr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_swvr.c; sourceTree = "<group>"; };
83EED5D2203A8BC7008BEB45 /* aus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aus.c; sourceTree = "<group>"; };
@ -2048,6 +2050,7 @@
834F7D8D2C7093EA003AC386 /* tac_decoder.c */,
834F7D8E2C7093EA003AC386 /* tantalus_decoder.c */,
834F7D8F2C7093EA003AC386 /* tgcadpcm_decoder.c */,
834960FD2DB5FEF90019C8CA /* ualaw_decoder.c */,
834F7D902C7093EA003AC386 /* ubi_adpcm_decoder.c */,
83B73C342D8FEFFD00A57F08 /* ubi_mpeg_decoder.c */,
834F7D912C7093EA003AC386 /* vadpcm_decoder.c */,
@ -2236,6 +2239,7 @@
836F6DFF18BDC2180095E648 /* layout */ = {
isa = PBXGroup;
children = (
836F6E0418BDC2180095E648 /* blocked.c */,
8306B08E2098454E000302D4 /* blocked_adm.c */,
8306B0882098454C000302D4 /* blocked_ast.c */,
83AA5D1B1F6E2F7F0020821C /* blocked_awc.c */,
@ -2248,7 +2252,7 @@
8306B08B2098454D000302D4 /* blocked_ea_wve_ad10.c */,
8306B08A2098454D000302D4 /* blocked_ea_wve_au00.c */,
8306B0932098454F000302D4 /* blocked_filp.c */,
8306B0A020984551000302D4 /* blocked_gsb.c */,
8306B0A020984551000302D4 /* blocked_gsnd.c */,
8342469520C4D23D00926E48 /* blocked_h4m.c */,
8306B0962098454F000302D4 /* blocked_halpst.c */,
8306B09B20984550000302D4 /* blocked_hwas.c */,
@ -2264,19 +2268,18 @@
836F46AD28208735005B9B87 /* blocked_tt_ad.c */,
83031ECA243C50CB00C3F3E0 /* blocked_ubi_sce.c */,
834F7D2A2C708A5B003AC386 /* blocked_vas.c */,
8306B08C2098454D000302D4 /* blocked_vas_kceo.c */,
83AA5D1A1F6E2F7F0020821C /* blocked_vgs.c */,
83031ECB243C50CB00C3F3E0 /* blocked_vid1.c */,
8306B0A120984551000302D4 /* blocked_vs.c */,
832BF80321E050DC006F50F1 /* blocked_vs_square.c */,
832BF80421E050DC006F50F1 /* blocked_vs_str.c */,
8306B0A120984551000302D4 /* blocked_vs.c */,
8306B09D20984551000302D4 /* blocked_ws_aud.c */,
8306B09F20984551000302D4 /* blocked_wsi.c */,
834FE0BC215C79A8000A5D3D /* blocked_xa_aiff.c */,
8306B0912098454E000302D4 /* blocked_xa.c */,
834FE0BC215C79A8000A5D3D /* blocked_xa_aiff.c */,
83A21F7A201D895B000F04B9 /* blocked_xvag.c */,
8306B08C2098454D000302D4 /* blocked_xvas.c */,
83A8BADE256679E3000F5F3F /* blocked_xwav.c */,
836F6E0418BDC2180095E648 /* blocked.c */,
834FE0BD215C79A9000A5D3D /* flat.c */,
836F6E0D18BDC2180095E648 /* interleave.c */,
8306B0902098454E000302D4 /* layered.c */,
@ -2332,6 +2335,7 @@
835B9B8B2730BF2C00F87EE3 /* ast_mmv.c */,
835B9B8A2730BF2C00F87EE3 /* ast_mv.c */,
83AB8C741E8072A100086084 /* astb.c */,
8349A8F01FE6257C00E26435 /* astl.c */,
8306B0D520984590000302D4 /* atsl.c */,
83EED5D2203A8BC7008BEB45 /* aus.c */,
83A16D2722D2ADE700B90C4C /* awb.c */,
@ -2365,7 +2369,7 @@
83B69B212845A26600D2435A /* bw_mp3_riff.c */,
835C883122CC17BD001B4B3F /* bwav.c */,
8306B0CF2098458F000302D4 /* caf.c */,
834F7D242C7088B9003AC386 /* cbx.c */,
834F7D242C7088B9003AC386 /* chatterbox.c */,
834FE0E8215C79EC000A5D3D /* ck.c */,
8346D97825BF838C00D1A8B0 /* compresswave.c */,
83A8BAE425667AA7000F5F3F /* cpk.c */,
@ -2415,7 +2419,6 @@
832FC36E278FAE3E0056A860 /* encrypted_mc161_streamfile.h */,
836F46B02820874D005B9B87 /* esf.c */,
836F6E4918BDC2180095E648 /* exakt_sc.c */,
836F6E4A18BDC2180095E648 /* excitebots.c */,
83AF2CC626226BA400538240 /* exst.c */,
8349A8EF1FE6257C00E26435 /* ezw.c */,
832BF80821E05135006F50F1 /* fag.c */,
@ -2455,6 +2458,7 @@
836F6E5318BDC2180095E648 /* his.c */,
836F6E9818BDC2180095E648 /* hxd.c */,
83CBF5402D4631F300AA2D75 /* i3ds.c */,
836F6EA018BDC2180095E648 /* iab.c */,
834FE0E0215C79EB000A5D3D /* idsp_ie.c */,
8346D97425BF838C00D1A8B0 /* idtech.c */,
8346D97525BF838C00D1A8B0 /* idtech_streamfile.h */,
@ -2487,13 +2491,15 @@
83A8BAE125667AA7000F5F3F /* lp_ap_lep_streamfile.h */,
839C3D22270D49FF00E13653 /* lpcm_fb.c */,
835B9B8E2730BF2D00F87EE3 /* lpcm_shade.c */,
836F6E7718BDC2180095E648 /* lps.c */,
8373342223F60CDB00DE14DC /* lrmd.c */,
8373341F23F60CDB00DE14DC /* lrmd_streamfile.h */,
836F6E5A18BDC2180095E648 /* lsf.c */,
83EDE5D61A70951A005F5D84 /* madp.c */,
836F6E5C18BDC2180095E648 /* mattel_hyperscan.c */,
836F6E5D18BDC2180095E648 /* maxis_xa.c */,
83EDE5D61A70951A005F5D84 /* mca.c */,
836F6E9D18BDC2180095E648 /* mcg.c */,
83709E011ECBC1A4005C03D3 /* mcss.c */,
836F6E5E18BDC2180095E648 /* meta.h */,
834FE0DE215C79EB000A5D3D /* mib_mih.c */,
836F6EAC18BDC2180095E648 /* mic_koei.c */,
@ -2512,7 +2518,6 @@
832BF81721E0514A006F50F1 /* msf_banpresto.c */,
83C7280D22BC893D00678B4A /* msf_konami.c */,
832BF80B21E05148006F50F1 /* msf_tamasoft.c */,
83709E011ECBC1A4005C03D3 /* mss.c */,
834FE0E7215C79EC000A5D3D /* msv.c */,
83C727FF22BC893900678B4A /* mta2.c */,
83C7280E22BC893D00678B4A /* mta2_streamfile.h */,
@ -2535,14 +2540,12 @@
836F6E6D18BDC2180095E648 /* ngc_adpdtk.c */,
834F7D322C70932C003AC386 /* ngc_dsp_asura.c */,
836F6E7318BDC2180095E648 /* ngc_dsp_std.c */,
836F6E7518BDC2180095E648 /* ngc_ffcc_str.c */,
836F6E7718BDC2180095E648 /* ngc_lps.c */,
836F6E7818BDC2180095E648 /* ngc_nst_dsp.c */,
836F6E7918BDC2180095E648 /* ngc_pdt.c */,
836F6E7A18BDC2180095E648 /* ngc_sck_dsp.c */,
836F6E7B18BDC2180095E648 /* ngc_ssm.c */,
8306B0BE2098458C000302D4 /* ngc_str_cauldron.c */,
83C727FC22BC893900678B4A /* npsf.c */,
836F6E7818BDC2180095E648 /* nst_monster.c */,
837CEAE223487F2A00E62A4A /* nub.c */,
832BF81B21E0514B006F50F1 /* nus3audio.c */,
834FE0D1215C79E9000A5D3D /* nus3bank.c */,
@ -2565,7 +2568,6 @@
836F6E8418BDC2180095E648 /* p3d.c */,
831BA6171EAC61A500CF89B0 /* pasx.c */,
8349A8FE1FE6257F00E26435 /* pc_adp_otns.c */,
8349A8F01FE6257C00E26435 /* pc_ast.c */,
836F6E8618BDC2180095E648 /* pc_mxst.c */,
8349A8F21FE6257D00E26435 /* pcm_kceje.c */,
8306B0D12098458F000302D4 /* pcm_sre.c */,
@ -2582,14 +2584,11 @@
836F6E9418BDC2180095E648 /* ps2_b1s.c */,
836F6E9618BDC2180095E648 /* ps2_bmdx.c */,
836F6E9F18BDC2180095E648 /* ps2_hsf.c */,
836F6EA018BDC2180095E648 /* ps2_iab.c */,
836F6EA418BDC2180095E648 /* ps2_joe.c */,
836F6EB618BDC2180095E648 /* ps2_rnd.c */,
836F6EBD18BDC2180095E648 /* ps2_snd.c */,
836F6EBF18BDC2190095E648 /* ps2_sps.c */,
836F6EC518BDC2190095E648 /* ps2_tec.c */,
836F6EC918BDC2190095E648 /* ps2_vbk.c */,
836F6ECB18BDC2190095E648 /* ps2_vgv.c */,
836F6ECC18BDC2190095E648 /* ps2_vms.c */,
836F6ECF18BDC2190095E648 /* ps2_wad.c */,
8315868326F586E200803A3A /* psb.c */,
@ -2640,6 +2639,8 @@
83C7280822BC893C00678B4A /* sfh.c */,
83C7280422BC893B00678B4A /* sfh_streamfile.h */,
836F6EF118BDC2190095E648 /* sfl.c */,
836F6E4A18BDC2180095E648 /* sfx0_monster.c */,
834FE0D2215C79E9000A5D3D /* sfxb.c */,
831BA6111EAC61A500CF89B0 /* sgxd.c */,
83B8FE2C2D5AB2A5005854C1 /* shaa.c */,
83AA7F782519C042004C5298 /* silence.c */,
@ -2657,6 +2658,7 @@
83C0C7622AA436B90056AFD8 /* snds.c */,
831BA6121EAC61A500CF89B0 /* sndx.c */,
835559FB2869102B005FE93A /* sndz.c */,
836F6F0418BDC2190095E648 /* song_monster.c */,
836F6EBE18BDC2190095E648 /* spm.c */,
83A21F82201D8981000F04B9 /* sps_n1.c */,
836F6E6718BDC2180095E648 /* spsd.c */,
@ -2668,6 +2670,7 @@
834FE0D6215C79E9000A5D3D /* sscf.c */,
8396BE792935FC2F00CD0580 /* sscf_encrypted.h */,
8396BE782935FC2F00CD0580 /* sscf_encrypted.c */,
834960FB2DB5FD430019C8CA /* ssp.c */,
8339B322280FDF250076F74B /* sspf.c */,
8317C24826982CC1007DD0B8 /* sspr.c */,
836F6EBA18BDC2180095E648 /* ster.c */,
@ -2675,6 +2678,7 @@
83AA5D231F6E2F9C0020821C /* stma.c */,
836F6E4118BDC2180095E648 /* str_sega.c */,
836F6EF718BDC2190095E648 /* str_snds.c */,
836F6E7518BDC2180095E648 /* str_sqex.c */,
834FE0C2215C79E6000A5D3D /* str_wav.c */,
834F7CFF2C7085EA003AC386 /* str_wav_streamfile.h */,
83C7280722BC893B00678B4A /* strm_abylight.c */,
@ -2720,6 +2724,7 @@
831BA6101EAC61A500CF89B0 /* vds_vdm.c */,
836F6EFD18BDC2190095E648 /* vgs.c */,
836F6ECA18BDC2190095E648 /* vgs_ps.c */,
836F6ECB18BDC2190095E648 /* vgv.c */,
83031ED7243C510400C3F3E0 /* vid1.c */,
836F6EA618BDC2180095E648 /* vig_kces.c */,
834FE0CE215C79E8000A5D3D /* vis.c */,
@ -2740,7 +2745,6 @@
834FE0D0215C79E8000A5D3D /* wavebatch.c */,
836F6ED018BDC2190095E648 /* wb.c */,
83349715275DD2AC00302E21 /* wbk.c */,
836F6F0418BDC2190095E648 /* wii_sng.c */,
836F6F0718BDC2190095E648 /* wpd.c */,
836F6F0818BDC2190095E648 /* ws_aud.c */,
834FE0CB215C79E8000A5D3D /* wsi.c */,
@ -2754,7 +2758,6 @@
83FBB16E2A4FF4EC00CD0580 /* xa2_acclaim.c */,
83CBF53C2D46318F00AA2D75 /* xabp.c */,
833A7A2D1ED11961003EC53E /* xau.c */,
834FE0D2215C79E9000A5D3D /* xau_konami.c */,
837CEAE423487F2A00E62A4A /* xavs.c */,
837CEAEE23487F2C00E62A4A /* xavs_streamfile.h */,
836F6F0C18BDC2190095E648 /* xbox_ims.c */,
@ -3390,14 +3393,13 @@
834F7E072C7093EA003AC386 /* vorbis_custom_utils_sk.c in Sources */,
836F6FD818BDC2190095E648 /* gbts.c in Sources */,
831BA61A1EAC61A500CF89B0 /* vds_vdm.c in Sources */,
836F6FF218BDC2190095E648 /* ps2_rnd.c in Sources */,
832BF80521E050DC006F50F1 /* blocked_mul.c in Sources */,
8306B0D920984590000302D4 /* ngc_str_cauldron.c in Sources */,
83CBF53B2D46314900AA2D75 /* pphd.c in Sources */,
834F7DCF2C7093EA003AC386 /* hca_decoder.c in Sources */,
83CBF5352D46309100AA2D75 /* ka1a_dec.c in Sources */,
83CBF53D2D46318F00AA2D75 /* xabp.c in Sources */,
834FE0FB215C79ED000A5D3D /* xau_konami.c in Sources */,
834FE0FB215C79ED000A5D3D /* sfxb.c in Sources */,
83F0AA6121E2028C004BBC04 /* vsv.c in Sources */,
8351F32F2212B57000A606E4 /* dsf.c in Sources */,
837CEAF723487F2C00E62A4A /* nub.c in Sources */,
@ -3437,7 +3439,7 @@
836F6F8A18BDC2190095E648 /* gcsw.c in Sources */,
836F6F9C18BDC2190095E648 /* mp4.c in Sources */,
834FE101215C79ED000A5D3D /* csmp.c in Sources */,
8306B0A720984552000302D4 /* blocked_xvas.c in Sources */,
8306B0A720984552000302D4 /* blocked_vas_kceo.c in Sources */,
8349A9101FE6258200E26435 /* ea_eaac.c in Sources */,
835B9B912730BF2D00F87EE3 /* lopu_fb.c in Sources */,
8319017C28F67EE100B70711 /* miniz.c in Sources */,
@ -3457,12 +3459,14 @@
839FBFFC26C354E70016A78A /* mp4_faac.c in Sources */,
832BF81D21E0514B006F50F1 /* msf_tamasoft.c in Sources */,
83C0C75D2AA435C60056AFD8 /* squeak.c in Sources */,
83709E071ECBC1A4005C03D3 /* mss.c in Sources */,
83709E071ECBC1A4005C03D3 /* mcss.c in Sources */,
836F6F8F18BDC2190095E648 /* his.c in Sources */,
834960FE2DB5FEF90019C8CA /* ualaw_decoder.c in Sources */,
834FE0E9215C79ED000A5D3D /* ao.c in Sources */,
834F7D112C7085EB003AC386 /* ea_eaac_tmx.c in Sources */,
836F6FE218BDC2190095E648 /* vig_kces.c in Sources */,
836F6FCB18BDC2190095E648 /* ads.c in Sources */,
834960FC2DB5FD430019C8CA /* ssp.c in Sources */,
834FE108215C79ED000A5D3D /* hd3_bd3.c in Sources */,
834F7DF42C7093EA003AC386 /* SASSC_decoder.c in Sources */,
83C7281C22BC893D00678B4A /* sfh.c in Sources */,
@ -3488,7 +3492,7 @@
836F6F7318BDC2190095E648 /* bcstm.c in Sources */,
834F7DBB2C7093EA003AC386 /* dsa_decoder.c in Sources */,
83299FD11E7660C7003A3242 /* dsp_adx.c in Sources */,
836F704018BDC2190095E648 /* wii_sng.c in Sources */,
836F704018BDC2190095E648 /* song_monster.c in Sources */,
834F7E0A2C7093EA003AC386 /* vorbis_custom_utils.c in Sources */,
834F7DFD2C7093EA003AC386 /* tgcadpcm_decoder.c in Sources */,
834FE10D215C79ED000A5D3D /* vag.c in Sources */,
@ -3570,14 +3574,14 @@
836F6F8818BDC2190095E648 /* fsb.c in Sources */,
83F2CCE525A5B41600F46FA8 /* acx.c in Sources */,
83FC176D23AC58D100E1025F /* xma_ue3.c in Sources */,
836F6FB318BDC2190095E648 /* ngc_lps.c in Sources */,
836F6FB318BDC2190095E648 /* lps.c in Sources */,
836F6FC018BDC2190095E648 /* p3d.c in Sources */,
834F7CFD2C70834D003AC386 /* nxof.c in Sources */,
836F6FC718BDC2190095E648 /* pona.c in Sources */,
8306B0B820984552000302D4 /* blocked_ws_aud.c in Sources */,
83B73C5C2D8FF37700A57F08 /* codec_info.c in Sources */,
83B73C5D2D8FF37700A57F08 /* api_libsf_cache.c in Sources */,
834F7D252C7088B9003AC386 /* cbx.c in Sources */,
834F7D252C7088B9003AC386 /* chatterbox.c in Sources */,
83AA5D241F6E2F9C0020821C /* awc.c in Sources */,
8349A8E91FE6253900E26435 /* blocked_ea_1snh.c in Sources */,
8306B0E620984590000302D4 /* msb_msh.c in Sources */,
@ -3616,7 +3620,7 @@
836F6F4A18BDC2190095E648 /* interleave.c in Sources */,
834F7EDC2C70A786003AC386 /* streamfile_buffer.c in Sources */,
83C7281F22BC893D00678B4A /* xwma_konami.c in Sources */,
83EDE5D81A70951A005F5D84 /* mca.c in Sources */,
83EDE5D81A70951A005F5D84 /* madp.c in Sources */,
834FE0F3215C79ED000A5D3D /* bnk_sony.c in Sources */,
8306B0AE20984552000302D4 /* blocked_filp.c in Sources */,
831BA61B1EAC61A500CF89B0 /* sgxd.c in Sources */,
@ -3631,7 +3635,7 @@
83C7281B22BC893D00678B4A /* strm_abylight.c in Sources */,
834D3A6E19F47C98001C54F6 /* g1l.c in Sources */,
832BF82A21E0514B006F50F1 /* vs_square.c in Sources */,
8349A9091FE6258200E26435 /* pc_ast.c in Sources */,
8349A9091FE6258200E26435 /* astl.c in Sources */,
83B73C442D8FF15700A57F08 /* mio_erisacontext.c in Sources */,
83B73C452D8FF15700A57F08 /* mio_erisafile.c in Sources */,
83B73C462D8FF15700A57F08 /* mio_erisamatrix.c in Sources */,
@ -3662,7 +3666,7 @@
834FE0FE215C79ED000A5D3D /* ps_headerless.c in Sources */,
834F7ED72C70A786003AC386 /* render.c in Sources */,
83AF2CCB26226BA500538240 /* ogv_3rdeye.c in Sources */,
8306B0BB20984552000302D4 /* blocked_gsb.c in Sources */,
8306B0BB20984552000302D4 /* blocked_gsnd.c in Sources */,
83031ECC243C50CC00C3F3E0 /* blocked_ubi_sce.c in Sources */,
8315868A26F586F900803A3A /* m2_psb.c in Sources */,
836F6FB018BDC2190095E648 /* dsp_kceje.c in Sources */,
@ -3677,7 +3681,7 @@
834FE0BE215C79A9000A5D3D /* blocked_xa_aiff.c in Sources */,
835B9B902730BF2D00F87EE3 /* ast_mmv.c in Sources */,
836F702A18BDC2190095E648 /* sd9.c in Sources */,
836F6FB418BDC2190095E648 /* ngc_nst_dsp.c in Sources */,
836F6FB418BDC2190095E648 /* nst_monster.c in Sources */,
834F7DB92C7093EA003AC386 /* derf_decoder.c in Sources */,
83B73C4B2D8FF19800A57F08 /* mio.c in Sources */,
836F6FDB18BDC2190095E648 /* ps2_hsf.c in Sources */,
@ -3708,7 +3712,7 @@
83B73C492D8FF17900A57F08 /* mio_decoder.c in Sources */,
834F7DBC2C7093EA003AC386 /* ea_mt_decoder.c in Sources */,
837CEAFA23487F2C00E62A4A /* xa_04sw.c in Sources */,
836F6F8618BDC2190095E648 /* excitebots.c in Sources */,
836F6F8618BDC2190095E648 /* sfx0_monster.c in Sources */,
8385D4E6245174C700FF8E67 /* diva.c in Sources */,
836F6FF418BDC2190095E648 /* rws_80d.c in Sources */,
834FE100215C79ED000A5D3D /* svgp.c in Sources */,
@ -3737,7 +3741,7 @@
83852B0B2680247900378854 /* rxws.c in Sources */,
831BA6181EAC61A500CF89B0 /* adx.c in Sources */,
832BF82321E0514B006F50F1 /* imc.c in Sources */,
836F6FB118BDC2190095E648 /* ngc_ffcc_str.c in Sources */,
836F6FB118BDC2190095E648 /* str_sqex.c in Sources */,
8306B0B620984552000302D4 /* blocked_hwas.c in Sources */,
836F6FC218BDC2190095E648 /* pc_mxst.c in Sources */,
8375737621F950ED00F01AF5 /* gin.c in Sources */,
@ -3772,7 +3776,7 @@
83D2007D248DDB770048BD24 /* kat.c in Sources */,
836F6F7618BDC2190095E648 /* brstm.c in Sources */,
834F7E0E2C7093EA003AC386 /* xmd_decoder.c in Sources */,
836F700718BDC2190095E648 /* ps2_vgv.c in Sources */,
836F700718BDC2190095E648 /* vgv.c in Sources */,
834F7D0A2C7085EB003AC386 /* gwb_gwd.c in Sources */,
836F704F18BDC2190095E648 /* xwb.c in Sources */,
834F7DE52C7093EA003AC386 /* ngc_dtk_decoder.c in Sources */,
@ -3783,7 +3787,7 @@
8306B0AA20984552000302D4 /* blocked_sthd.c in Sources */,
834F7D292C708A2F003AC386 /* vas_rockstar.c in Sources */,
836F6FA918BDC2190095E648 /* ngc_adpdtk.c in Sources */,
836F6FDC18BDC2190095E648 /* ps2_iab.c in Sources */,
836F6FDC18BDC2190095E648 /* iab.c in Sources */,
83C7282122BC893D00678B4A /* msf_konami.c in Sources */,
833E82F72A2858EF00CD0580 /* reader.c in Sources */,
83B69B222845A26600D2435A /* bw_mp3_riff.c in Sources */,

View file

@ -118,18 +118,24 @@ libvgmstream_sfmt_t api_get_output_sample_type(libvgmstream_priv_t* priv) {
switch(format) {
case SFMT_S16: return LIBVGMSTREAM_SFMT_PCM16;
case SFMT_FLT: return LIBVGMSTREAM_SFMT_FLOAT;
case SFMT_F32: return LIBVGMSTREAM_SFMT_FLOAT; //shouldn't happen?
case SFMT_S32: return LIBVGMSTREAM_SFMT_PCM32;
case SFMT_O24: return LIBVGMSTREAM_SFMT_PCM24;
// internal use only, shouldn't happen (misconfigured, see prepare_mixing)
case SFMT_S24:
case SFMT_F16:
default:
return 0x00; //???
return 0x00;
}
}
int api_get_sample_size(libvgmstream_sfmt_t sample_format) {
switch(sample_format) {
//case LIBVGMSTREAM_SFMT_PCM24:
//case LIBVGMSTREAM_SFMT_PCM32:
case LIBVGMSTREAM_SFMT_FLOAT:
case LIBVGMSTREAM_SFMT_PCM32:
return 0x04;
case LIBVGMSTREAM_SFMT_PCM24:
return 0x03;
case LIBVGMSTREAM_SFMT_PCM16:
default:
return 0x02;

View file

@ -52,6 +52,8 @@ static void prepare_mixing(libvgmstream_priv_t* priv) {
switch(cfg->force_sfmt) {
case LIBVGMSTREAM_SFMT_PCM16: force_sfmt = SFMT_S16; break;
case LIBVGMSTREAM_SFMT_FLOAT: force_sfmt = SFMT_FLT; break;
case LIBVGMSTREAM_SFMT_PCM24: force_sfmt = SFMT_O24; break;
case LIBVGMSTREAM_SFMT_PCM32: force_sfmt = SFMT_S32; break;
default: break;
}
@ -60,10 +62,10 @@ static void prepare_mixing(libvgmstream_priv_t* priv) {
else {
// internal force, swap certain internal bufs into standard output
sfmt_t force_sfmt = SFMT_NONE;
sfmt_t input_sfmt = mixing_get_input_sample_type(priv->vgmstream);
switch(input_sfmt) {
case SFMT_F32: force_sfmt = SFMT_FLT; break;
case SFMT_F16: force_sfmt = SFMT_FLT; break;
case SFMT_S24: force_sfmt = SFMT_O24; break;
default: break;
}

View file

@ -5,6 +5,7 @@ extern const codec_info_t ka1a_decoder;
extern const codec_info_t ubimpeg_decoder;
extern const codec_info_t hca_decoder;
#ifdef VGM_USE_VORBIS
extern const codec_info_t ogg_vorbis_decoder;
extern const codec_info_t vorbis_custom_decoder;
#endif
extern const codec_info_t tac_decoder;
@ -12,6 +13,9 @@ extern const codec_info_t compresswave_decoder;
extern const codec_info_t speex_decoder;
extern const codec_info_t imuse_decoder;
extern const codec_info_t mio_decoder;
extern const codec_info_t pcm32_decoder;
extern const codec_info_t pcm24_decoder;
extern const codec_info_t pcmfloat_decoder;
const codec_info_t* codec_get_info(VGMSTREAM* v) {
switch(v->coding_type) {
@ -22,6 +26,8 @@ const codec_info_t* codec_get_info(VGMSTREAM* v) {
case coding_UBI_MPEG:
return &ubimpeg_decoder;
#ifdef VGM_USE_VORBIS
case coding_OGG_VORBIS:
return &ogg_vorbis_decoder;
case coding_VORBIS_custom:
return &vorbis_custom_decoder;
#endif
@ -37,6 +43,13 @@ const codec_info_t* codec_get_info(VGMSTREAM* v) {
return &imuse_decoder;
case coding_MIO:
return &mio_decoder;
case coding_PCM32LE:
return &pcm32_decoder;
case coding_PCM24LE:
case coding_PCM24BE:
return &pcm24_decoder;
case coding_PCMFLOAT:
return &pcmfloat_decoder;
default:
return NULL;
}

View file

@ -18,6 +18,8 @@ typedef struct {
void (*reset)(void* codec_data);
void (*seek)(VGMSTREAM* v, int32_t num_sample);
bool (*decode_buf)(VGMSTREAM* v, sbuf_t* sdst); // alternate decoding for codecs that don't provide their own buffer
// info for vgmstream
//uint32_t flags;
// alloc size of effect's private data (don't set to manage manually in init/free)

View file

@ -46,12 +46,6 @@ void decode_free(VGMSTREAM* vgmstream) {
return;
}
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type == coding_OGG_VORBIS) {
free_ogg_vorbis(vgmstream->codec_data);
}
#endif
if (vgmstream->coding_type == coding_CIRCUS_VQ) {
free_circus_vq(vgmstream->codec_data);
}
@ -170,12 +164,6 @@ void decode_seek(VGMSTREAM* vgmstream) {
seek_ea_mt(vgmstream, vgmstream->loop_current_sample);
}
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type == coding_OGG_VORBIS) {
seek_ogg_vorbis(vgmstream->codec_data, vgmstream->loop_current_sample);
}
#endif
#ifdef VGM_USE_FFMPEG
if (vgmstream->coding_type == coding_FFmpeg) {
seek_ffmpeg(vgmstream->codec_data, vgmstream->loop_current_sample);
@ -228,12 +216,6 @@ void decode_reset(VGMSTREAM* vgmstream) {
return;
}
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type == coding_OGG_VORBIS) {
reset_ogg_vorbis(vgmstream->codec_data);
}
#endif
if (vgmstream->coding_type == coding_CIRCUS_VQ) {
reset_circus_vq(vgmstream->codec_data);
}
@ -360,9 +342,6 @@ int decode_get_samples_per_frame(VGMSTREAM* vgmstream) {
case coding_PCM24BE:
case coding_PCM32LE:
return 1;
#ifdef VGM_USE_VORBIS
case coding_OGG_VORBIS:
#endif
#ifdef VGM_USE_MPEG
case coding_MPEG_custom:
case coding_MPEG_ealayer3:
@ -784,13 +763,23 @@ bool decode_uses_internal_offset_updates(VGMSTREAM* vgmstream) {
// decode frames for decoders which decode frame by frame and have their own sample buffer
static void decode_frames(sbuf_t* sdst, VGMSTREAM* vgmstream) {
static void decode_frames(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do) {
const int max_empty = 1000;
int num_empty = 0;
decode_state_t* ds = vgmstream->decode_state;
sbuf_t* ssrc = &ds->sbuf;
const codec_info_t* codec_info = codec_get_info(vgmstream);
ds->samples_left = samples_to_do; //sdst->samples; // TODO this can be slow for interleaved decoders
// old-style decoding
if (codec_info && codec_info->decode_buf) {
bool ok = codec_info->decode_buf(vgmstream, sdst);
if (!ok) goto decode_fail;
sdst->filled += ds->samples_left;
return;
}
// fill the external buf by decoding N times; may read partially that buf
while (sdst->filled < sdst->samples) {
@ -838,6 +827,8 @@ static void decode_frames(sbuf_t* sdst, VGMSTREAM* vgmstream) {
sbuf_copy_segments(sdst, ssrc, samples_copy);
sbuf_consume(ssrc, samples_copy);
ds->samples_left -= samples_copy;
}
}
@ -864,7 +855,7 @@ void decode_vgmstream(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do) {
switch (vgmstream->coding_type) {
case coding_SILENCE:
sbuf_silence_s16(buffer, samples_to_do, vgmstream->channels, 0);
sbuf_silence_rest(sdst);
break;
case coding_CRI_ADX:
@ -972,35 +963,6 @@ void decode_vgmstream(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do) {
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
}
break;
case coding_PCMFLOAT:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_pcmfloat(&vgmstream->ch[ch], buffer+ch,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do,
vgmstream->codec_endian);
}
break;
case coding_PCM24LE:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_pcm24le(&vgmstream->ch[ch], buffer+ch,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
}
break;
case coding_PCM24BE:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_pcm24be(&vgmstream->ch[ch], buffer + ch,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
}
break;
case coding_PCM32LE:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_pcm32le(&vgmstream->ch[ch], buffer+ch,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
}
break;
case coding_NDS_IMA:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_nds_ima(&vgmstream->ch[ch], buffer+ch,
@ -1148,11 +1110,6 @@ void decode_vgmstream(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do) {
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
}
break;
#ifdef VGM_USE_VORBIS
case coding_OGG_VORBIS:
decode_ogg_vorbis(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels);
break;
#endif
case coding_CIRCUS_VQ:
decode_circus_vq(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels);
break;
@ -1574,7 +1531,7 @@ void decode_vgmstream(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do) {
sbuf_t stmp = *sdst;
stmp.samples = stmp.filled + samples_to_do; //TODO improve
decode_frames(&stmp, vgmstream);
decode_frames(&stmp, vgmstream, samples_to_do);
break;
}
}

View file

@ -6,6 +6,7 @@
typedef struct {
int discard;
sbuf_t sbuf;
int samples_left; //info for some decoders
} decode_state_t;
#endif

View file

@ -176,8 +176,11 @@ void describe_vgmstream(VGMSTREAM* vgmstream, char* desc, int length) {
const char* sfmt_desc;
switch(sfmt) {
case SFMT_FLT: sfmt_desc = "float"; break;
case SFMT_F32: sfmt_desc = "float32"; break;
case SFMT_F16: sfmt_desc = "float16"; break;
case SFMT_S16: sfmt_desc = "pcm16"; break;
case SFMT_S24: sfmt_desc = "pcm24"; break;
case SFMT_S32: sfmt_desc = "pcm32"; break;
case SFMT_O24: sfmt_desc = "pcm24"; break;
default: sfmt_desc = "???";
}

View file

@ -74,11 +74,12 @@ bool mixer_is_active(mixer_t* mixer) {
static void setup_mixbuf(mixer_t* mixer, sbuf_t* sbuf) {
sbuf_t* smix = &mixer->smix;
// mixbuf can be interpreted as FLT or F32; try to use src's to keep buf as-is (less rounding errors)
if (sbuf->fmt == SFMT_F32 || sbuf->fmt == SFMT_FLT)
sbuf_init(smix, sbuf->fmt, mixer->mixbuf, sbuf->filled, sbuf->channels); //mixer->input_channels
// mixbuf (float) can be interpreted as F16, for 1:1 mapping with PCM16 (and possibly less rounding errors with mixops)
// for PCM24 regular float seems ok and 1:1 as well
if (sbuf->fmt == SFMT_S16)
sbuf_init(smix, SFMT_F16, mixer->mixbuf, sbuf->filled, sbuf->channels);
else
sbuf_init(smix, SFMT_F32, mixer->mixbuf, sbuf->filled, sbuf->channels);
sbuf_init(smix, sbuf->fmt, mixer->mixbuf, sbuf->filled, sbuf->channels);
// remix to temp buf (somehow using float buf rather than int32 is faster?)
sbuf_copy_segments(smix, sbuf, sbuf->filled);
@ -100,12 +101,20 @@ static void setup_outbuf(mixer_t* mixer, sbuf_t* sbuf) {
void mixer_process(mixer_t* mixer, sbuf_t* sbuf, int32_t current_pos) {
/* external */
// external
//if (!mixer_is_active(mixer))
// return;
/* try to skip if no fades apply (set but does nothing yet) + only has fades
* (could be done in mix op but avoids upgrading bufs in some cases) */
#if 0
// TODO: not possible to copy from src to dst directly at the moment, since src doubles as dst
// optimize copy only ops to skip temp buffer
if (mixer->chain_count == 0 && mixer->force_type != SFMT_NONE) {
...
}
#endif
// try to skip if no fades apply (set but does nothing yet) + only has fades
// (could be done in mix op but avoids upgrading bufs in some cases)
if (mixer->has_fade) {
//;VGM_LOG("MIX: fade test %i, %i\n", data->has_non_fade, mixer_op_fade_is_active(data, current_pos, current_pos + sample_count));
if (!mixer->has_non_fade && !mixer_op_fade_is_active(mixer, current_pos, current_pos + sbuf->filled))

View file

@ -107,8 +107,8 @@ int render_layout(sbuf_t* sbuf, VGMSTREAM* vgmstream) {
case layout_blocked_dec:
case layout_blocked_vs_mh:
case layout_blocked_mul:
case layout_blocked_gsb:
case layout_blocked_xvas:
case layout_blocked_gsnd:
case layout_blocked_vas_kceo:
case layout_blocked_thp:
case layout_blocked_filp:
case layout_blocked_rage_aud:

View file

@ -12,6 +12,119 @@
#include <math.h>
#endif
/* when casting float to int, value is simply truncated:
* - (int)1.7 = 1, (int)-1.7 = -1
* alts for more accurate rounding could be:
* - (int)floor(f)
* - (int)(f < 0 ? f - 0.5f : f + 0.5f)
* - (((int) (f1 + 32767.5)) - 32767)
* - etc
* but since +-1 isn't really audible we'll just cast, as it's the fastest
*
* Regular C float-to-int casting ("int i = (int)f") is somewhat slow due to IEEE
* float requirements, but C99 adds some faster-but-less-precise casting functions.
* MSVC added this in VS2015 (_MSC_VER 1900) but doesn't seem inlined and is very slow.
* It's slightly faster (~5%) but causes fuzzy PCM<>float<>PCM conversions.
*/
static inline int float_to_int(float val) {
#if PCM16_ROUNDING_LRINT
return lrintf(val);
#elif defined(_MSC_VER)
return (int)val;
#else
return (int)val;
#endif
}
#if 0
static inline int double_to_int(double val) {
#if PCM16_ROUNDING_LRINT
return lrint(val);
#elif defined(_MSC_VER)
return (int)val;
#else
return (int)val;
#endif
}
static inline float double_to_float(double val) {
return (float)val;
}
#endif
static inline int64_t float_to_i64(float val) {
return (int64_t)val;
}
// TO-DO: investigate if BE machines need BE 24-bit
static inline int32_t get_s24ne(const uint8_t* p) {
#if PCM24_BIG_ENDIAN
return (((int32_t)p[0]<<24) | ((int32_t)p[1]<<16) | ((int32_t)p[2]<<8)) >> 8; //force signedness
#else
return (((int32_t)p[0]<<8) | ((int32_t)p[1]<<16) | ((int32_t)p[2]<<24)) >> 8; //force signedness
#endif
}
static void put_u24ne(uint8_t* buf, uint32_t v) {
#if PCM24_BIG_ENDIAN
buf[0] = (uint8_t)((v >> 16) & 0xFF);
buf[1] = (uint8_t)((v >> 8) & 0xFF);
buf[2] = (uint8_t)((v >> 0) & 0xFF);
#else
buf[0] = (uint8_t)((v >> 0) & 0xFF);
buf[1] = (uint8_t)((v >> 8) & 0xFF);
buf[2] = (uint8_t)((v >> 16) & 0xFF);
#endif
}
static inline int clamp_pcm16(int32_t val) {
return clamp16(val);
}
static inline int clamp_pcm24(int32_t val) {
if (val > 8388607) return 8388607;
else if (val < -8388608) return -8388608;
else return val;
}
static inline int clamp_pcm32(int64_t val) {
if (val > 2147483647) return 2147483647;
else if (val < -2147483648) return -2147483648;
else return val;
}
//TODO float can't fully represent s32, but since it mainly affects lower bytes (noise) it may be ok
#define CONV_NOOP(x) (x)
#define CONV_S16_FLT(x) (x * (1.0f / 32767.0f))
#define CONV_S16_S24(x) (x << 8)
#define CONV_S16_S32(x) (x << 16)
#define CONV_F16_S16(x) (clamp_pcm16(float_to_int(x)))
#define CONV_F16_FLT(x) (x * (1.0f / 32767.0f))
#define CONV_F16_S24(x) (clamp_pcm16(float_to_int(x)) << 8)
#define CONV_F16_S32(x) (clamp_pcm16(float_to_int(x)) << 16)
#ifdef PCM16_ROUNDING_HALF
#define CONV_FLT_S16(x) (clamp_pcm16(float_to_int( floor(x * 32767.0f + 0.5f) )))
#else
#define CONV_FLT_S16(x) (clamp_pcm16(float_to_int(x * 32767.0f)))
#endif
#define CONV_FLT_F16(x) (x * 32767.0f)
#define CONV_FLT_S24(x) (clamp_pcm24(float_to_int(x * 8388607.0f)))
#define CONV_FLT_S32(x) (clamp_pcm32(float_to_i64(x * 2147483647)))
#define CONV_S24_S16(x) (x >> 8)
#define CONV_S24_F16(x) (x >> 8)
#define CONV_S24_S32(x) (x << 8)
#define CONV_S24_FLT(x) (x * (1.0f / 8388607.0f))
#define CONV_S32_S16(x) (x >> 16)
#define CONV_S32_F16(x) (x >> 16)
#define CONV_S32_FLT(x) (x * (1.0f / 2147483647.0f))
#define CONV_S32_S24(x) (x >> 8)
void sbuf_init(sbuf_t* sbuf, sfmt_t format, void* buf, int samples, int channels) {
memset(sbuf, 0, sizeof(sbuf_t));
sbuf->buf = buf;
@ -24,8 +137,8 @@ void sbuf_init_s16(sbuf_t* sbuf, int16_t* buf, int samples, int channels) {
sbuf_init(sbuf, SFMT_S16, buf, samples, channels);
}
void sbuf_init_f32(sbuf_t* sbuf, float* buf, int samples, int channels) {
sbuf_init(sbuf, SFMT_F32, buf, samples, channels);
void sbuf_init_f16(sbuf_t* sbuf, float* buf, int samples, int channels) {
sbuf_init(sbuf, SFMT_F16, buf, samples, channels);
}
void sbuf_init_flt(sbuf_t* sbuf, float* buf, int samples, int channels) {
@ -35,13 +148,18 @@ void sbuf_init_flt(sbuf_t* sbuf, float* buf, int samples, int channels) {
int sfmt_get_sample_size(sfmt_t fmt) {
switch(fmt) {
case SFMT_F32:
case SFMT_F16:
case SFMT_FLT:
case SFMT_S24:
case SFMT_S32:
return 0x04;
case SFMT_S16:
return 0x02;
case SFMT_O24:
return 0x03;
default:
return 0;
VGM_LOG("SBUF: undefined sample format %i found\n", fmt);
return 0; //TODO return 4 to avoid crashes?
}
}
@ -70,102 +188,6 @@ void sbuf_consume(sbuf_t* sbuf, int samples) {
sbuf->samples -= samples;
}
/* when casting float to int, value is simply truncated:
* - (int)1.7 = 1, (int)-1.7 = -1
* alts for more accurate rounding could be:
* - (int)floor(f)
* - (int)(f < 0 ? f - 0.5f : f + 0.5f)
* - (((int) (f1 + 32767.5)) - 32767)
* - etc
* but since +-1 isn't really audible we'll just cast, as it's the fastest
*
* Regular C float-to-int casting ("int i = (int)f") is somewhat slow due to IEEE
* float requirements, but C99 adds some faster-but-less-precise casting functions.
* MSVC added this in VS2015 (_MSC_VER 1900) but doesn't seem inlined and is very slow.
* It's slightly faster (~5%) but causes fuzzy PCM<>float<>PCM conversions.
*/
static inline int float_to_int(float val) {
#if PCM16_ROUNDING_LRINT
return lrintf(val);
#elif defined(_MSC_VER)
return (int)val;
#else
return (int)val;
#endif
}
static inline int double_to_int(double val) {
#if PCM16_ROUNDING_LRINT
return lrint(val);
#elif defined(_MSC_VER)
return (int)val;
#else
return (int)val;
#endif
}
static inline float double_to_float(double val) {
return (float)val;
}
//TODO decide if using float 1.0 style or 32767 style (fuzzy PCM when doing that)
//TODO: maybe use macro-style templating (but kinda ugly)
void sbuf_copy_to_f32(float* dst, sbuf_t* sbuf) {
switch(sbuf->fmt) {
case SFMT_S16: {
int16_t* src = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = (float)src[s]; // / 32767.0f
}
break;
}
case SFMT_F32: {
float* src = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = src[s];
}
break;
}
case SFMT_FLT: {
float* src = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = src[s] * 32767.0f;
}
break;
}
default:
break;
}
}
void sbuf_copy_from_f32(sbuf_t* sbuf, float* src) {
switch(sbuf->fmt) {
case SFMT_S16: {
int16_t* dst = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = clamp16(float_to_int(src[s]));
}
break;
}
case SFMT_F32: {
float* dst = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = src[s];
}
break;
}
case SFMT_FLT: {
float* dst = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = src[s] / 32767.0f;
}
break;
}
default:
break;
}
}
// max samples to copy from ssrc to sdst, considering that dst may be partially filled
int sbuf_get_copy_max(sbuf_t* sdst, sbuf_t* ssrc) {
@ -176,252 +198,6 @@ int sbuf_get_copy_max(sbuf_t* sdst, sbuf_t* ssrc) {
return samples_copy;
}
/* ugly thing to avoid repeating functions */
#define sbuf_copy_segments_internal(dst, src, src_pos, dst_pos, src_max) \
while (src_pos < src_max) { \
dst[dst_pos++] = src[src_pos++]; \
}
#define sbuf_copy_segments_internal_f16(dst, src, src_pos, dst_pos, src_max) \
while (src_pos < src_max) { \
dst[dst_pos++] = clamp16(float_to_int(src[src_pos++])); \
}
#ifdef PCM16_ROUNDING_HALF
#define sbuf_copy_segments_internal_s16(dst, src, src_pos, dst_pos, src_max, value) \
while (src_pos < src_max) { \
dst[dst_pos++] = clamp16(float_to_int( floor(src[src_pos++] * value + 0.5f) )); \
}
#else
#define sbuf_copy_segments_internal_s16(dst, src, src_pos, dst_pos, src_max, value) \
while (src_pos < src_max) { \
dst[dst_pos++] = clamp16(float_to_int(src[src_pos++] * value)); \
}
#endif
#define sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, value) \
while (src_pos < src_max) { \
dst[dst_pos++] = (src[src_pos++] * value); \
}
// copy N samples from ssrc into dst (should be clamped externally)
void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int samples_copy) {
if (ssrc->channels != sdst->channels) {
// 0'd other channels first (uncommon so probably fine albeit slower-ish)
sbuf_silence_part(sdst, sdst->filled, samples_copy);
sbuf_copy_layers(sdst, ssrc, 0, samples_copy);
#if 0
// "faster" but lots of extra ifs per sample format, not worth it
while (src_pos < src_max) {
for (int ch = 0; ch < dst_channels; ch++) {
dst[dst_pos++] = ch >= src_channels ? 0 : src[src_pos++];
}
}
#endif
//TODO: may want to handle externally?
sdst->filled += samples_copy;
return;
}
int src_pos = 0;
int dst_pos = sdst->filled * sdst->channels;
int src_max = samples_copy * ssrc->channels;
// define all posible combos, probably there is a better way to handle this but...
// s16 > s16
if (ssrc->fmt == SFMT_S16 && sdst->fmt == SFMT_S16) {
int16_t* src = ssrc->buf;
int16_t* dst = sdst->buf;
sbuf_copy_segments_internal(dst, src, src_pos, dst_pos, src_max);
}
// s16 > f32
else if (ssrc->fmt == SFMT_S16 && sdst->fmt == SFMT_F32) {
int16_t* src = ssrc->buf;
float* dst = sdst->buf;
sbuf_copy_segments_internal(dst, src, src_pos, dst_pos, src_max);
}
// s16 > flt
else if (ssrc->fmt == SFMT_S16 && sdst->fmt == SFMT_FLT) {
int16_t* src = ssrc->buf;
float* dst = sdst->buf;
sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, (1.0f / 32767.0f));
}
// f32 > f32 / flt > flt
else if ((ssrc->fmt == SFMT_F32 && sdst->fmt == SFMT_F32) ||
(ssrc->fmt == SFMT_FLT && sdst->fmt == SFMT_FLT)) {
float* src = ssrc->buf;
float* dst = sdst->buf;
sbuf_copy_segments_internal(dst, src, src_pos, dst_pos, src_max);
}
// f32 > s16
else if (ssrc->fmt == SFMT_F32 && sdst->fmt == SFMT_S16) {
float* src = ssrc->buf;
int16_t* dst = sdst->buf;
sbuf_copy_segments_internal_f16(dst, src, src_pos, dst_pos, src_max);
}
// flt > s16
else if (ssrc->fmt == SFMT_FLT && sdst->fmt == SFMT_S16) {
float* src = ssrc->buf;
int16_t* dst = sdst->buf;
sbuf_copy_segments_internal_s16(dst, src, src_pos, dst_pos, src_max, 32767.0f);
}
// f32 > flt
else if (ssrc->fmt == SFMT_F32 && sdst->fmt == SFMT_FLT) {
float* src = ssrc->buf;
float* dst = sdst->buf;
sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, (1.0f / 32767.0f));
}
// flt > f32
else if (ssrc->fmt == SFMT_FLT && sdst->fmt == SFMT_F32) {
float* src = ssrc->buf;
float* dst = sdst->buf;
sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, 32767.0f);
}
//TODO: may want to handle externally?
sdst->filled += samples_copy;
}
#define sbuf_copy_layers_internal_blank(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step) \
for (int s = src_filled; s < dst_expected; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = 0; \
} \
dst_pos += dst_ch_step; \
}
//TODO fix missing ->channels
/* ugly thing to avoid repeating functions */
#define sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step) \
for (int s = 0; s < src_filled; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = src[src_pos++]; \
} \
dst_pos += dst_ch_step; \
} \
\
sbuf_copy_layers_internal_blank(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
// float +-1.0 <> pcm +-32767.0
#define sbuf_copy_layers_internal_f16(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step) \
for (int s = 0; s < src_filled; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = clamp16(float_to_int(src[src_pos++])); \
} \
dst_pos += dst_ch_step; \
} \
\
sbuf_copy_layers_internal_blank(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
#ifdef PCM16_ROUNDING_HALF
// float +-1.0 <> pcm +-32767.0
#define sbuf_copy_layers_internal_s16(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, value) \
for (int s = 0; s < src_filled; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = clamp16(float_to_int( floor(src[src_pos++] * value + 0.5f) )); \
} \
dst_pos += dst_ch_step; \
} \
\
sbuf_copy_layers_internal_blank(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
#else
// float +-1.0 <> pcm +-32767.0
#define sbuf_copy_layers_internal_s16(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, value) \
for (int s = 0; s < src_filled; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = clamp16(float_to_int(src[src_pos++] * value)); \
} \
dst_pos += dst_ch_step; \
} \
\
sbuf_copy_layers_internal_blank(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
#endif
// float +-1.0 <> pcm +-32767.0
#define sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, value) \
for (int s = 0; s < src_filled; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = float_to_int(src[src_pos++] * value); \
} \
dst_pos += dst_ch_step; \
} \
\
sbuf_copy_layers_internal_blank(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
// copy interleaving: dst ch1 ch2 ch3 ch4 w/ src ch1 ch2 ch1 ch2 = only fill dst ch1 ch2
// dst_channels == src_channels isn't likely so ignore that optimization (dst must be >= than src).
// dst_ch_start indicates it should write to dst's chN,chN+1,etc
// sometimes one layer has less samples than others and need to 0-fill rest
void sbuf_copy_layers(sbuf_t* sdst, sbuf_t* ssrc, int dst_ch_start, int dst_max) {
int src_copy = dst_max;
int src_channels = ssrc->channels;
int dst_ch_step = (sdst->channels - ssrc->channels);
int src_pos = 0;
int dst_pos = sdst->filled * sdst->channels + dst_ch_start;
if (src_copy > ssrc->filled)
src_copy = ssrc->filled;
if (ssrc->channels > sdst->channels) {
VGM_LOG("SBUF: wrong copy\n");
return;
}
// define all posible combos, probably there is a better way to handle this but...
// 1:1
if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_S16) {
int16_t* dst = sdst->buf;
int16_t* src = ssrc->buf;
sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step);
}
else if (sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_S16) {
float* dst = sdst->buf;
int16_t* src = ssrc->buf;
sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step);
}
else if ((sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_F32) || (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_FLT)) {
float* dst = sdst->buf;
float* src = ssrc->buf;
sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step);
}
// to s16
else if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_F32) {
int16_t* dst = sdst->buf;
float* src = ssrc->buf;
sbuf_copy_layers_internal_f16(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step);
}
else if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_FLT) {
int16_t* dst = sdst->buf;
float* src = ssrc->buf;
sbuf_copy_layers_internal_s16(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step, 32767.0f);
}
// to f32
else if (sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_FLT) {
float* dst = sdst->buf;
float* src = ssrc->buf;
sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step, 32767.0f);
}
// to flt
else if (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_S16) {
float* dst = sdst->buf;
int16_t* src = ssrc->buf;
sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step, (1.0f / 32767.0f));
}
else if (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_F32) {
float* dst = sdst->buf;
float* src = ssrc->buf;
sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step, (1.0f / 32767.0f));
}
}
void sbuf_silence_s16(sample_t* dst, int samples, int channels, int filled) {
memset(dst + filled * channels, 0, (samples - filled) * channels * sizeof(sample_t));
}
void sbuf_silence_part(sbuf_t* sbuf, int from, int count) {
int sample_size = sfmt_get_sample_size(sbuf->fmt);
@ -434,44 +210,291 @@ void sbuf_silence_rest(sbuf_t* sbuf) {
sbuf_silence_part(sbuf, sbuf->filled, sbuf->samples - sbuf->filled);
}
typedef void (*sbuf_copy_t)(void* vsrc, void* vdst, int src_pos, int dst_pos, int src_max);
// Ugly generic copy function definition with different parameters, to avoid repeating code.
// Must define various functions below, to be set in the copy matrix.
// Uses void params to allow callbacks.
#define DEFINE_SBUF_COPY(suffix, srctype, dsttype, func) \
static void sbuf_copy_##suffix(void* vsrc, void* vdst, int src_pos, int dst_pos, int src_max) { \
srctype* src = vsrc; \
dsttype* dst = vdst; \
while (src_pos < src_max) { \
dst[dst_pos++] = func(src[src_pos++]); \
} \
}
#define DEFINE_SBUF_CP24(suffix, srctype, dsttype, func) \
static void sbuf_copy_##suffix(void* vsrc, void* vdst, int src_pos, int dst_pos, int src_max) { \
srctype* src = vsrc; \
dsttype* dst = vdst; \
while (src_pos < src_max) { \
put_u24ne(dst + dst_pos, func(src[src_pos++]) ); \
dst_pos += 3; \
} \
}
DEFINE_SBUF_COPY(s16_s16, int16_t, int16_t, CONV_NOOP);
DEFINE_SBUF_COPY(s16_f16, int16_t, float, CONV_NOOP);
DEFINE_SBUF_COPY(s16_flt, int16_t, float, CONV_S16_FLT);
DEFINE_SBUF_COPY(s16_s24, int16_t, int32_t, CONV_S16_S24);
DEFINE_SBUF_COPY(s16_s32, int16_t, int32_t, CONV_S16_S32);
DEFINE_SBUF_CP24(s16_o24, int16_t, uint8_t, CONV_S16_S24);
DEFINE_SBUF_COPY(f16_s16, float, int16_t, CONV_F16_S16);
DEFINE_SBUF_COPY(f16_f16, float, float, CONV_NOOP);
DEFINE_SBUF_COPY(f16_flt, float, float, CONV_F16_FLT);
DEFINE_SBUF_COPY(f16_s24, float, int32_t, CONV_F16_S24);
DEFINE_SBUF_COPY(f16_s32, float, int32_t, CONV_F16_S32);
DEFINE_SBUF_CP24(f16_o24, float, uint8_t, CONV_F16_S24);
DEFINE_SBUF_COPY(flt_s16, float, int16_t, CONV_FLT_S16);
DEFINE_SBUF_COPY(flt_f16, float, float, CONV_FLT_F16);
DEFINE_SBUF_COPY(flt_flt, float, float, CONV_NOOP);
DEFINE_SBUF_COPY(flt_s24, float, int32_t, CONV_FLT_S24);
DEFINE_SBUF_COPY(flt_s32, float, int32_t, CONV_FLT_S32);
DEFINE_SBUF_CP24(flt_o24, float, uint8_t, CONV_FLT_S24);
DEFINE_SBUF_COPY(s24_s16, int32_t, int16_t, CONV_S24_S16);
DEFINE_SBUF_COPY(s24_f16, int32_t, float, CONV_S24_F16);
DEFINE_SBUF_COPY(s24_flt, int32_t, float, CONV_S24_FLT);
DEFINE_SBUF_COPY(s24_s24, int32_t, int32_t, CONV_NOOP);
DEFINE_SBUF_COPY(s24_s32, int32_t, int32_t, CONV_S24_S32);
DEFINE_SBUF_CP24(s24_o24, int32_t, uint8_t, CONV_NOOP);
DEFINE_SBUF_COPY(s32_s16, int32_t, int16_t, CONV_S32_S16);
DEFINE_SBUF_COPY(s32_f16, int32_t, float, CONV_S32_F16);
DEFINE_SBUF_COPY(s32_flt, int32_t, float, CONV_S32_FLT);
DEFINE_SBUF_COPY(s32_s24, int32_t, int32_t, CONV_S32_S24);
DEFINE_SBUF_COPY(s32_s32, int32_t, int32_t, CONV_NOOP);
DEFINE_SBUF_CP24(s32_o24, int32_t, uint8_t, CONV_S32_S24);
static sbuf_copy_t copy_matrix[SFMT_MAX][SFMT_MAX] = {
{ NULL, NULL, NULL, NULL, NULL }, //NONE
{ NULL, sbuf_copy_s16_s16, sbuf_copy_s16_f16, sbuf_copy_s16_flt, sbuf_copy_s16_s24, sbuf_copy_s16_s32, sbuf_copy_s16_o24 },
{ NULL, sbuf_copy_f16_s16, sbuf_copy_f16_f16, sbuf_copy_f16_flt, sbuf_copy_f16_s24, sbuf_copy_f16_s32, sbuf_copy_f16_o24 },
{ NULL, sbuf_copy_flt_s16, sbuf_copy_flt_f16, sbuf_copy_flt_flt, sbuf_copy_flt_s24, sbuf_copy_flt_s32, sbuf_copy_flt_o24 },
{ NULL, sbuf_copy_s24_s16, sbuf_copy_s24_f16, sbuf_copy_s24_flt, sbuf_copy_s24_s24, sbuf_copy_s24_s32, sbuf_copy_s24_o24 },
{ NULL, sbuf_copy_s32_s16, sbuf_copy_s32_f16, sbuf_copy_s32_flt, sbuf_copy_s32_s24, sbuf_copy_s32_s32, sbuf_copy_s32_o24 },
{ NULL, NULL, NULL, NULL, NULL }, //O24
};
// copy N samples from ssrc into dst (should be clamped externally)
//TODO: may want to handle sdst->flled + samples externally?
void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int samples) {
// rarely when decoding with empty frames, may not setup ssrc
if (samples == 0)
return;
if (ssrc->channels != sdst->channels) {
// 0'd other channels first (uncommon so probably fine albeit slower-ish)
sbuf_silence_part(sdst, sdst->filled, samples);
sbuf_copy_layers(sdst, ssrc, 0, samples);
#if 0
// "faster" but lots of extra ifs per sample format, not worth it
while (src_pos < src_max) {
for (int ch = 0; ch < dst_channels; ch++) {
dst[dst_pos++] = ch >= src_channels ? 0 : src[src_pos++];
}
}
#endif
sdst->filled += samples;
return;
}
sbuf_copy_t sbuf_copy_src_dst = copy_matrix[ssrc->fmt][sdst->fmt];
if (!sbuf_copy_src_dst) {
VGM_LOG("SBUF: undefined copy function sfmt %i to %i\n", ssrc->fmt, sdst->fmt);
sdst->filled += samples;
return;
}
int src_pos = 0;
int dst_pos = sdst->filled * sdst->channels;
int src_max = samples * ssrc->channels;
sbuf_copy_src_dst(ssrc->buf, sdst->buf, src_pos, dst_pos, src_max);
sdst->filled += samples;
}
typedef void (*sbuf_layer_t)(void* vsrc, void* vdst, int src_pos, int dst_pos, int src_max, int dst_expected, int src_channels, int dst_channels);
// See above
#define DEFINE_SBUF_LAYER(suffix, srctype, dsttype, func) \
static void sbuf_layer_##suffix(void* vsrc, void* vdst, int src_pos, int dst_pos, int src_filled, int dst_expected, int src_channels, int dst_channels) { \
srctype* src = vsrc; \
dsttype* dst = vdst; \
int dst_ch_step = (dst_channels - src_channels); \
for (int s = 0; s < src_filled; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = func(src[src_pos++]); \
} \
dst_pos += dst_ch_step; \
} \
\
for (int s = src_filled; s < dst_expected; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = 0; \
} \
dst_pos += dst_ch_step; \
} \
}
#define DEFINE_SBUF_LYR24(suffix, srctype, dsttype, func) \
static void sbuf_layer_##suffix(void* vsrc, void* vdst, int src_pos, int dst_pos, int src_filled, int dst_expected, int src_channels, int dst_channels) { \
srctype* src = vsrc; \
dsttype* dst = vdst; \
int dst_ch_step = (dst_channels - src_channels); \
for (int s = 0; s < src_filled; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
put_u24ne(dst + dst_pos, func(src[src_pos++]) ); \
dst_pos += 3; \
} \
dst_pos += dst_ch_step * 3; \
} \
\
for (int s = src_filled; s < dst_expected; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
put_u24ne(dst + dst_pos, 0); \
dst_pos += 3; \
} \
dst_pos += dst_ch_step * 3; \
} \
}
DEFINE_SBUF_LAYER(s16_s16, int16_t, int16_t, CONV_NOOP);
DEFINE_SBUF_LAYER(s16_f16, int16_t, float, CONV_NOOP);
DEFINE_SBUF_LAYER(s16_flt, int16_t, float, CONV_S16_FLT);
DEFINE_SBUF_LAYER(s16_s24, int16_t, int32_t, CONV_S16_S24);
DEFINE_SBUF_LAYER(s16_s32, int16_t, int32_t, CONV_S16_S32);
DEFINE_SBUF_LYR24(s16_o24, int16_t, uint8_t, CONV_S16_S24);
DEFINE_SBUF_LAYER(f16_s16, float, int16_t, CONV_F16_S16);
DEFINE_SBUF_LAYER(f16_f16, float, float, CONV_NOOP);
DEFINE_SBUF_LAYER(f16_flt, float, float, CONV_F16_FLT);
DEFINE_SBUF_LAYER(f16_s24, float, int32_t, CONV_F16_S24);
DEFINE_SBUF_LAYER(f16_s32, float, int32_t, CONV_F16_S32);
DEFINE_SBUF_LYR24(f16_o24, float, uint8_t, CONV_F16_S24);
DEFINE_SBUF_LAYER(flt_s16, float, int16_t, CONV_FLT_S16);
DEFINE_SBUF_LAYER(flt_f16, float, float, CONV_FLT_F16);
DEFINE_SBUF_LAYER(flt_flt, float, float, CONV_NOOP);
DEFINE_SBUF_LAYER(flt_s24, float, int32_t, CONV_FLT_S24);
DEFINE_SBUF_LAYER(flt_s32, float, int32_t, CONV_FLT_S32);
DEFINE_SBUF_LYR24(flt_o24, float, uint8_t, CONV_FLT_S24);
DEFINE_SBUF_LAYER(s24_s16, int32_t, int16_t, CONV_S24_S16);
DEFINE_SBUF_LAYER(s24_f16, int32_t, float, CONV_S24_F16);
DEFINE_SBUF_LAYER(s24_flt, int32_t, float, CONV_S24_FLT);
DEFINE_SBUF_LAYER(s24_s24, int32_t, int32_t, CONV_NOOP);
DEFINE_SBUF_LAYER(s24_s32, int32_t, int32_t, CONV_S24_S32);
DEFINE_SBUF_LYR24(s24_o24, int32_t, uint8_t, CONV_NOOP);
DEFINE_SBUF_LAYER(s32_s16, int32_t, int16_t, CONV_S32_S16);
DEFINE_SBUF_LAYER(s32_f16, int32_t, float, CONV_S32_F16);
DEFINE_SBUF_LAYER(s32_flt, int32_t, float, CONV_S32_FLT);
DEFINE_SBUF_LAYER(s32_s24, int32_t, int32_t, CONV_S32_S24);
DEFINE_SBUF_LAYER(s32_s32, int32_t, int32_t, CONV_NOOP);
DEFINE_SBUF_LYR24(s32_o24, int32_t, uint8_t, CONV_NOOP);
static sbuf_layer_t layer_matrix[SFMT_MAX][SFMT_MAX] = {
{ NULL, NULL, NULL, NULL, NULL }, //NONE
{ NULL, sbuf_layer_s16_s16, sbuf_layer_s16_f16, sbuf_layer_s16_flt, sbuf_layer_s16_s24, sbuf_layer_s16_s32, sbuf_layer_s16_o24 },
{ NULL, sbuf_layer_f16_s16, sbuf_layer_f16_f16, sbuf_layer_f16_flt, sbuf_layer_f16_s24, sbuf_layer_f16_s32, sbuf_layer_f16_o24 },
{ NULL, sbuf_layer_flt_s16, sbuf_layer_flt_f16, sbuf_layer_flt_flt, sbuf_layer_flt_s24, sbuf_layer_flt_s32, sbuf_layer_flt_o24 },
{ NULL, sbuf_layer_s24_s16, sbuf_layer_s24_f16, sbuf_layer_s24_flt, sbuf_layer_s24_s24, sbuf_layer_s24_s32, sbuf_layer_s24_o24 },
{ NULL, sbuf_layer_s32_s16, sbuf_layer_s32_f16, sbuf_layer_s32_flt, sbuf_layer_s32_s24, sbuf_layer_s32_s32, sbuf_layer_s32_o24 },
{ NULL, NULL, NULL, NULL, NULL }, //O32
};
// copy interleaving: dst ch1 ch2 ch3 ch4 w/ src ch1 ch2 ch1 ch2 = only fill dst ch1 ch2
// dst_channels == src_channels isn't likely so ignore that optimization (dst must be >= than src).
// dst_ch_start indicates it should write to dst's chN,chN+1,etc
// sometimes one layer has less samples than others and need to 0-fill rest up to dst_max
void sbuf_copy_layers(sbuf_t* sdst, sbuf_t* ssrc, int dst_ch_start, int dst_max) {
int src_pos = 0;
int dst_pos = sdst->filled * sdst->channels + dst_ch_start;
int src_copy = dst_max;
if (src_copy > ssrc->filled)
src_copy = ssrc->filled;
if (ssrc->channels > sdst->channels) {
VGM_LOG("SBUF: src channels bigger than dst\n");
return;
}
sbuf_layer_t sbuf_layer_src_dst = layer_matrix[ssrc->fmt][sdst->fmt];
if (!sbuf_layer_src_dst) {
VGM_LOG("SBUF: undefined layer function sfmt %i to %i\n", ssrc->fmt, sdst->fmt);
return;
}
sbuf_layer_src_dst(ssrc->buf, sdst->buf, src_pos, dst_pos, src_copy, dst_max, ssrc->channels, sdst->channels);
}
typedef void (*sbuf_fade_t)(void* vsrc, int start, int to_do, int fade_pos, int fade_duration);
#define DEFINE_SBUF_FADE(suffix, buftype) \
static void sbuf_fade_##suffix(sbuf_t* sbuf, int start, int to_do, int fade_pos, int fade_duration) { \
buftype* buf = sbuf->buf; \
int s = start * sbuf->channels; \
int s_end = (start + to_do) * sbuf->channels; \
while (s < s_end) { \
float fadedness = (float)(fade_duration - fade_pos) / fade_duration; \
for (int i = 0; i < sbuf->channels; i++) { \
buf[s] = float_to_int(buf[s] * fadedness); \
s++; \
} \
fade_pos++; \
} \
}
#define DEFINE_SBUF_FD24(suffix, buftype) \
static void sbuf_fade_##suffix(sbuf_t* sbuf, int start, int to_do, int fade_pos, int fade_duration) { \
buftype* buf = sbuf->buf; \
int s = start * sbuf->channels; \
int s_end = (start + to_do) * sbuf->channels; \
while (s < s_end) { \
float fadedness = (float)(fade_duration - fade_pos) / fade_duration; \
for (int i = 0; i < sbuf->channels; i++) { \
put_u24ne(buf + s * 3, float_to_int(get_s24ne(buf + s * 3) * fadedness) ); \
s++; \
} \
fade_pos++; \
} \
}
DEFINE_SBUF_FADE(i16, int16_t);
DEFINE_SBUF_FADE(i32, int32_t);
DEFINE_SBUF_FADE(flt, float);
DEFINE_SBUF_FD24(o24, uint8_t);
void sbuf_fadeout(sbuf_t* sbuf, int start, int to_do, int fade_pos, int fade_duration) {
//TODO: use interpolated fadedness to improve performance?
//TODO: use float fadedness?
int s = start * sbuf->channels;
int s_end = (start + to_do) * sbuf->channels;
switch(sbuf->fmt) {
case SFMT_S16: {
int16_t* buf = sbuf->buf;
while (s < s_end) {
double fadedness = (double)(fade_duration - fade_pos) / fade_duration;
fade_pos++;
for (int ch = 0; ch < sbuf->channels; ch++) {
buf[s] = double_to_int(buf[s] * fadedness);
s++;
}
}
case SFMT_S16:
sbuf_fade_i16(sbuf, start, to_do, fade_pos, fade_duration);
break;
case SFMT_S24:
case SFMT_S32:
sbuf_fade_i32(sbuf, start, to_do, fade_pos, fade_duration);
break;
}
case SFMT_FLT:
case SFMT_F32: {
float* buf = sbuf->buf;
while (s < s_end) {
double fadedness = (double)(fade_duration - fade_pos) / fade_duration;
fade_pos++;
for (int ch = 0; ch < sbuf->channels; ch++) {
buf[s] = double_to_float(buf[s] * fadedness);
s++;
}
}
case SFMT_F16:
sbuf_fade_flt(sbuf, start, to_do, fade_pos, fade_duration);
break;
case SFMT_O24:
sbuf_fade_o24(sbuf, start, to_do, fade_pos, fade_duration);
break;
}
default:
VGM_LOG("SBUF: missing fade for fmt=%i\n", sbuf->fmt);
break;
}
@ -505,3 +528,46 @@ void sbuf_interleave(sbuf_t* sbuf, float** ibuf) {
}
}
}
/* vorbis encodes channels in non-standard order, so we remap during conversion to fix this oddity.
* (feels a bit weird as one would think you could leave as-is and set the player's output order,
* but that isn't possible and remapping like this is what FFmpeg and every other plugin does). */
static const int xiph_channel_map[8][8] = {
{ 0 }, // 1ch: FC > same
{ 0, 1 }, // 2ch: FL FR > same
{ 0, 2, 1 }, // 3ch: FL FC FR > FL FR FC
{ 0, 1, 2, 3 }, // 4ch: FL FR BL BR > same
{ 0, 2, 1, 3, 4 }, // 5ch: FL FC FR BL BR > FL FR FC BL BR
{ 0, 2, 1, 5, 3, 4 }, // 6ch: FL FC FR BL BR LFE > FL FR FC LFE BL BR
{ 0, 2, 1, 6, 5, 3, 4 }, // 7ch: FL FC FR SL SR BC LFE > FL FR FC LFE BC SL SR
{ 0, 2, 1, 7, 5, 6, 3, 4 }, // 8ch: FL FC FR SL SR BL BR LFE > FL FR FC LFE BL BR SL SR
};
// converts from internal Vorbis format to standard PCM and remaps (mostly from Xiph's decoder_example.c)
void sbuf_interleave_vorbis(sbuf_t* sbuf, float** src) {
if (sbuf->fmt != SFMT_FLT)
return;
int channels = sbuf->channels;
/* convert float PCM (multichannel float array, with pcm[0]=ch0, pcm[1]=ch1, pcm[2]=ch0, etc)
* to 16 bit signed PCM ints (host order) and interleave + fix clipping */
for (int ch = 0; ch < channels; ch++) {
int ch_map = (channels > 8) ? ch : xiph_channel_map[channels - 1][ch]; // put Vorbis' ch to other outbuf's ch
float* ptr = sbuf->buf;
float* channel = src[ch_map];
ptr += ch;
for (int s = 0; s < sbuf->filled; s++) {
float val = channel[s];
#if 0 //to pcm16 from vorbis
int val = (int)floor(channel[s] * 32767.0f + 0.5f);
if (val > 32767) val = 32767;
else if (val < -32768) val = -32768;
#endif
*ptr = val;
ptr += channels;
}
}
}

View file

@ -11,29 +11,33 @@
* rather than planar (buffer per channel = [ch][s] = c1 c1 c1 c1 ... c2 c2 c2 c2 ...) */
typedef enum {
SFMT_NONE,
SFMT_S16, /* standard PCM16 */
//SFMT_S24,
//SFMT_S32,
SFMT_F32, /* pcm-like float (+-32768), for internal use (simpler pcm > f32 plus some decoders use this) */
SFMT_FLT, /* standard float (+-1.0), for external players */
SFMT_S16, // PCM16
SFMT_F16, // PCM16-like float (+-32767.0f), for internal use (simpler s16 <> f16, plus some decoders use it)
SFMT_FLT, // standard float (+-1.0), for external players
SFMT_S24, // PCM24 for internal use (32-bit buffers)
SFMT_S32, // PCM32
SFMT_O24, // PCM24 LE for output (24-bit buffers), for external use only (can't handle as a regular buf internally)
SFMT_MAX,
} sfmt_t;
/* simple buffer info to pass around, for internal mixing
* meant to held existing sound buffer pointers rather than alloc'ing directly (some ops will swap/move its internals) */
typedef struct {
void* buf; /* current sample buffer */
sfmt_t fmt; /* buffer type */
int channels; /* interleaved step or planar buffers */
int samples; /* max samples */
int filled; /* samples in buffer */
void* buf; // current sample buffer
sfmt_t fmt; // buffer type
int channels; // interleaved step or planar buffers
int samples; // max samples
int filled; // samples in buffer
} sbuf_t;
/* it's probably slightly faster to make some function inline'd, but aren't called that often to matter (given big enough total samples) */
void sbuf_init(sbuf_t* sbuf, sfmt_t format, void* buf, int samples, int channels);
void sbuf_init_s16(sbuf_t* sbuf, int16_t* buf, int samples, int channels);
void sbuf_init_f32(sbuf_t* sbuf, float* buf, int samples, int channels);
void sbuf_init_f16(sbuf_t* sbuf, float* buf, int samples, int channels);
void sbuf_init_flt(sbuf_t* sbuf, float* buf, int samples, int channels);
int sfmt_get_sample_size(sfmt_t fmt);
@ -46,17 +50,15 @@ void sbuf_consume(sbuf_t* sbuf, int count);
/* helpers to copy between buffers; note they assume dst and src aren't the same buf */
int sbuf_get_copy_max(sbuf_t* sdst, sbuf_t* ssrc);
void sbuf_copy_to_f32(float* dst, sbuf_t* sbuf);
void sbuf_copy_from_f32(sbuf_t* sbuf, float* src);
void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int samples_copy);
void sbuf_copy_layers(sbuf_t* sdst, sbuf_t* ssrc, int dst_ch_start, int expected);
void sbuf_silence_s16(sample_t* dst, int samples, int channels, int filled);
void sbuf_silence_rest(sbuf_t* sbuf);
void sbuf_silence_part(sbuf_t* sbuf, int from, int count);
void sbuf_fadeout(sbuf_t* sbuf, int start, int to_do, int fade_pos, int fade_duration);
void sbuf_interleave(sbuf_t* sbuf, float** ibuf);
void sbuf_interleave_vorbis(sbuf_t* sbuf, float** ibuf);
#endif

View file

@ -92,18 +92,15 @@ void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int ch
void decode_pcm8_sb(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm4(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_pcm4_unsigned(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_ulaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ulaw_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_alaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcmfloat(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
void decode_pcm24le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm24be(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm32le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
int32_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
int32_t pcm24_bytes_to_samples(size_t bytes, int channels);
int32_t pcm16_bytes_to_samples(size_t bytes, int channels);
int32_t pcm8_bytes_to_samples(size_t bytes, int channels);
/* pcm_decoder */
void decode_ulaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ulaw_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_alaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* psx_decoder */
void decode_psx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int is_badflags, int config);
@ -382,6 +379,7 @@ void* init_mio(STREAMFILE* sf, int* p_loop_point);
#ifdef VGM_USE_VORBIS
/* ogg_vorbis_decoder */
typedef struct ogg_vorbis_codec_data ogg_vorbis_codec_data;
typedef struct { //todo simplify
STREAMFILE *streamfile;
int64_t start; /* file offset where the Ogg starts */
@ -396,16 +394,12 @@ typedef struct { //todo simplify
} ogg_vorbis_io;
ogg_vorbis_codec_data* init_ogg_vorbis(STREAMFILE* sf, off_t start, off_t size, ogg_vorbis_io* io);
void decode_ogg_vorbis(ogg_vorbis_codec_data* data, sample_t* outbuf, int32_t samples_to_do, int channels);
void reset_ogg_vorbis(ogg_vorbis_codec_data* data);
void seek_ogg_vorbis(ogg_vorbis_codec_data* data, int32_t num_sample);
void free_ogg_vorbis(ogg_vorbis_codec_data* data);
int ogg_vorbis_get_comment(ogg_vorbis_codec_data* data, const char** comment);
void ogg_vorbis_get_info(ogg_vorbis_codec_data* data, int* p_channels, int* p_sample_rate);
void ogg_vorbis_get_samples(ogg_vorbis_codec_data* data, int* p_samples);
void ogg_vorbis_set_disable_reordering(ogg_vorbis_codec_data* data, int set);
void ogg_vorbis_set_force_seek(ogg_vorbis_codec_data* data, int set);
void ogg_vorbis_set_disable_reordering(ogg_vorbis_codec_data* data, bool set);
void ogg_vorbis_set_force_seek(ogg_vorbis_codec_data* data, bool set);
STREAMFILE* ogg_vorbis_get_streamfile(ogg_vorbis_codec_data* data);
@ -699,7 +693,7 @@ typedef struct {
int frame_samples;
} mp4_custom_t;
ffmpeg_codec_data* init_ffmpeg_mp4_custom_std(STREAMFILE* sf, mp4_custom_t* mp4);
ffmpeg_codec_data* init_ffmpeg_mp4_custom_ktac(STREAMFILE* sf, mp4_custom_t* mp4);
ffmpeg_codec_data* init_ffmpeg_mp4_custom_lyn(STREAMFILE* sf, mp4_custom_t* mp4);
#endif

View file

@ -763,7 +763,7 @@ static void samples_dblp_to_s16(sample_t* obuf, double** inbuf, int ichs, int sa
}
}
static void copy_samples(ffmpeg_codec_data* data, sample_t* outbuf, int samples_to_do) {
static void copy_samples(ffmpeg_codec_data* data, sample_t* outbuf, int samples_to_do, int max_channels) {
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 24, 100)
int channels = data->codecCtx->channels;
#else
@ -779,6 +779,12 @@ static void copy_samples(ffmpeg_codec_data* data, sample_t* outbuf, int samples_
ibuf = data->frame->data[0];
}
// decoder may return more channels than expected in rare/buggy cases
if (channels > max_channels) {
VGM_LOG_ONCE("FFMPEG: buggy channels\n");
channels = max_channels;
}
switch (data->codecCtx->sample_fmt) {
/* unused? */
case AV_SAMPLE_FMT_U8P: if (is_planar) { samples_u8p_to_s16(outbuf, ibuf, channels, samples_to_do, data->samples_consumed); break; }
@ -835,7 +841,7 @@ void decode_ffmpeg(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do
if (samples_to_get > samples_to_do)
samples_to_get = samples_to_do;
copy_samples(data, outbuf, samples_to_get);
copy_samples(data, outbuf, samples_to_get, channels);
samples_to_do -= samples_to_get;
outbuf += samples_to_get * channels;

View file

@ -4,7 +4,7 @@
#ifdef VGM_USE_FFMPEG
typedef enum { MP4_STD, MP4_LYN } mp4_type_t;
typedef enum { MP4_KTAC, MP4_LYN } mp4_type_t;
/**
* Makes a MP4 header for MP4 raw data with a separate frame table, simulating a real MP4 that
@ -54,7 +54,7 @@ static void add_u16b(m4a_header_t* h, uint16_t value) {
h->bytes += 0x02;
}
static void add_u8(m4a_header_t* h, uint32_t value) {
static void add_u8b(m4a_header_t* h, uint32_t value) {
put_u8(h->out, value);
h->out += 0x01;
h->bytes += 0x01;
@ -77,7 +77,7 @@ static void save_atom(m4a_header_t* h, m4a_state_t* s) {
s->bytes = h->bytes;
}
static void load_atom(m4a_header_t* h, m4a_state_t* s) {
static void mend_atom(m4a_header_t* h, m4a_state_t* s) {
put_u32be(s->out, h->bytes - s->bytes);
}
@ -172,6 +172,7 @@ static void add_stts(m4a_header_t* h) {
/* from mpeg4audio.c (also see ff_mp4_read_dec_config_descr) */
static const int m4a_sample_rates[16] = {
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350
// index 15 means sample rate is stored in 24-bit after index
};
static const uint8_t m4a_channels[14] = {
0,
@ -191,64 +192,88 @@ static const uint8_t m4a_channels[14] = {
};
static void add_esds(m4a_header_t* h) {
uint16_t config = 0;
/* ES_descriptor (TLV format see ISO 14496-1) and DecSpecificInfoTag define actual decoding
- config (channels/rate/etc), other atoms with the same stuff is just info
* - http://ecee.colorado.edu/~ecen5653/ecen5653/papers/ISO%2014496-1%202004.PDF */
{
uint8_t object_type = 0x02; /* 0x00=none, 0x01=AAC main, 0x02=AAC LC */
* config (channels/rate/etc), other atoms with the same stuff is just info
* - see ISO/IEC 14496-3:2001 > 1.6.2. Syntax (AudioSpecificConfig + GASpecificConfig) */
uint16_t config = 0;
uint8_t object_type = 0x02; /* 0x00=none, 0x01=AAC main, 0x02=AAC LC, etc */
uint8_t sr_index = 0;
uint8_t ch_index = 0;
uint8_t unknown = 0;
int i;
for (i = 0; i < 16; i++) {
uint8_t extra = 0;
for (int i = 0; i < 16; i++) {
if (m4a_sample_rates[i] == h->mp4->sample_rate) {
sr_index = i;
break;
}
}
for (i = 0; i < 8; i++) {
for (int i = 0; i < 8; i++) {
if (m4a_channels[i] == h->mp4->channels) {
ch_index = i;
break;
}
}
extra = 0 ; // frameLength (1b) + dependsOnCoreCoder (1b) + extensionFlag (1b)
// KTAC uses 'quad' (2/2) rather than standard 4.0 (3/1) [Winning Post 9 2022 (PC)]
if (h->mp4->channels == 4 && h->type == MP4_KTAC) {
ch_index = 0;
}
config |= (object_type & 0x1F) << 11; /* 5b */
config |= (sr_index & 0x0F) << 7; /* 4b */
config |= (ch_index & 0x0F) << 3; /* 4b */
config |= (unknown & 0x07) << 0; /* 3b */
}
config |= (extra & 0x07) << 0; /* 3b */
add_atom(h, "esds", 0x33);
uint8_t slcfg_size = 0x01;
uint8_t config_size = 0x02 + (ch_index == 0 ? 0x07 : 0x00);
uint8_t deccfg_size = 0x14;
uint8_t descr_size = 0x03 + 0x08 + deccfg_size + config_size + slcfg_size;
m4a_state_t s;
save_atom(h, &s);
add_atom(h, "esds", 0x00);
add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */
add_u8 (h, 0x03); /* ES_DescrTag */
add_u32b(h, 0x80808022); /* size 0x22 */
add_u8b (h, 0x03); /* ES_DescrTag */
add_u32b(h, 0x80808000 + descr_size); /* tag size (all subtags) */
add_u16b(h, 0x0000); /* stream Id */
add_u8 (h, 0x00); /* flags */
add_u8b (h, 0x00); /* flags */
add_u8 (h, 0x04); /* DecoderConfigDescrTag */
add_u32b(h, 0x80808014); /* size 0x14 */
add_u8 (h, 0x40); /* object type (0x40=audio) */
add_u8 (h, 0x15); /* stream type (6b: 0x5=audio) + upstream (1b) + reserved (1b: const 1) */
add_u8b (h, 0x04); /* DecoderConfigDescrTag */
add_u32b(h, 0x80808000 + deccfg_size); /* subtag size */
add_u8b (h, 0x40); /* object type (0x40=audio) */
add_u8b (h, 0x15); /* stream type (6b: 0x5=audio) + upstream (1b) + reserved (1b: const 1) */
add_u24b(h, 0x000000); /* buffer size */
add_u32b(h, 0); /* max bitrate (256000?)*/
add_u32b(h, 0); /* average bitrate (256000?) */
add_u8 (h, 0x05); /* DecSpecificInfoTag */
add_u32b(h, 0x80808002); /* size 0x02 */
add_u8b (h, 0x05); /* DecSpecificInfoTag */
add_u32b(h, 0x80808000 + config_size); /* subtag size */
add_u16b(h, config); /* actual decoder info */
add_u8 (h, 0x06); /* SLConfigDescrTag */
add_u32b(h, 0x80808001); /* size 0x01 */
add_u8 (h, 0x02); /* predefined (2=default) */
// config for quad, abridged (see spec's program_config_element)
if (ch_index == 0 && h->mp4->channels == 4) {
uint16_t ch_config1 = 0x0004 | (object_type << 10) | (sr_index << 6); // config + channel info (part 1)
uint32_t ch_config2 = 0x04002110; // channel info (part 2)
uint8_t comment_len = 0x00;
add_u16b(h, ch_config1);
add_u32b(h, ch_config2);
add_u8b (h, comment_len);
}
add_u8b (h, 0x06); /* SLConfigDescrTag */
add_u32b(h, 0x80808000 + slcfg_size); /* tag size */
add_u8b (h, 0x02); /* predefined (2=default) */
mend_atom(h, &s);
}
static void add_mp4a(m4a_header_t* h) {
add_atom(h, "mp4a", 0x57);
m4a_state_t s;
save_atom(h, &s);
add_atom(h, "mp4a", 0x00);
add_u32b(h, 0); /* ? */
add_u32b(h, 1); /* Data reference index */
add_u32b(h, 0); /* Reserved */
@ -259,13 +284,18 @@ static void add_mp4a(m4a_header_t* h) {
add_u16b(h, h->mp4->sample_rate); /* Sample rate */
add_u16b(h, 0); /* ? */
add_esds(h); /* elementary stream descriptor */
mend_atom(h, &s);
}
static void add_stsd(m4a_header_t* h) {
add_atom(h, "stsd", 0x67);
m4a_state_t s;
save_atom(h, &s);
add_atom(h, "stsd", 0x00);
add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */
add_u32b(h, 1); /* Number of entries */
add_mp4a(h);
mend_atom(h, &s);
}
static void add_stbl(m4a_header_t* h) {
@ -278,7 +308,7 @@ static void add_stbl(m4a_header_t* h) {
add_stsc(h); /* Sample-to-chunk */
add_stsz(h); /* Sample size */
add_stco(h); /* Chunk offset */
load_atom(h, &s);
mend_atom(h, &s);
}
static void add_dinf(m4a_header_t* h) {
@ -305,7 +335,7 @@ static void add_minf(m4a_header_t* h) {
add_smhd(h);
add_dinf(h);
add_stbl(h);
load_atom(h, &s);
mend_atom(h, &s);
}
static void add_hdlr(m4a_header_t* h) {
@ -338,7 +368,7 @@ static void add_mdia(m4a_header_t* h) {
add_mdhd(h);
add_hdlr(h);
add_minf(h);
load_atom(h, &s);
mend_atom(h, &s);
}
static void add_tkhd(m4a_header_t* h) {
@ -375,7 +405,7 @@ static void add_trak(m4a_header_t* h) {
add_atom(h, "trak", 0x00);
add_tkhd(h);
add_mdia(h);
load_atom(h, &s);
mend_atom(h, &s);
}
static void add_mvhd(m4a_header_t* h) {
@ -416,7 +446,7 @@ static void add_moov(m4a_header_t* h) {
add_mvhd(h);
add_trak(h);
//add_udta(h);
load_atom(h, &s);
mend_atom(h, &s);
}
/* *** */
@ -494,7 +524,7 @@ static ffmpeg_codec_data* init_ffmpeg_mp4_custom(STREAMFILE* sf, mp4_custom_t* m
bytes = make_m4a_header(buf, buf_len, mp4, sf, type); /* before changing stream_offset/size */
switch(type) {
case MP4_STD: /* regular raw data */
case MP4_KTAC: /* regular raw data */
temp_sf = sf;
break;
case MP4_LYN: /* frames have size before them, but also a seek table */
@ -523,8 +553,8 @@ fail:
return NULL;
}
ffmpeg_codec_data* init_ffmpeg_mp4_custom_std(STREAMFILE* sf, mp4_custom_t* mp4) {
return init_ffmpeg_mp4_custom(sf, mp4, MP4_STD);
ffmpeg_codec_data* init_ffmpeg_mp4_custom_ktac(STREAMFILE* sf, mp4_custom_t* mp4) {
return init_ffmpeg_mp4_custom(sf, mp4, MP4_KTAC);
}
ffmpeg_codec_data* init_ffmpeg_mp4_custom_lyn(STREAMFILE* sf, mp4_custom_t* mp4) {

View file

@ -2,9 +2,33 @@
#include "../base/decode_state.h"
#include "../base/codec_info.h"
#include "libs/mio_xerisa.h"
//#include "Source/reader_get.h"
#include "../util/io_callback_sf.h"
/* Decodes MIO ("Music Interleaved and Orthogonal transformed") audio files.
* Adapted to C from original C++ lib source by Leshade Entis:
* - http://www.entis.jp/eridev/download/
* - http://www.amatsukami.jp/entis/bin/erinalib.lzh
* (licensed under a custom license somewhat equivalent to GPL).
*
* Full lib is called "ERINA-Library" (2000~2022) / "ERISA-Library" (2004~2005), and handles various
* Entis's formats, while this code just handles "MIO" (audio) decoding. "ERISA" uses a new coding
* type but also handles older files.
*
* MIO has a RIFF-like chunk header, and then is divided into big-ish VBR blocks. "Lead" blocks
* (first one, but also others that act as "keyframes") setup code model, which can be huffman (ERINA)
* or arithmetic (ERISA) coding depending on header. Lib reads per-block config then codes, then
* dequantizes per sub-band with iLOT (lapped orthogonal transform) and iDCT after some
* pre/post-processing. There is a lossless mode with huffman codes + PCM16/8 as well.
*
* Original C++ lib audio parts has roughly 4 modules, adapted and simplified to C like this:
* - erisafile (MIOFile): file ops like parsing header and reading blocks
* - erisacontext (MIOContext): bitreading from blocks and code unpacking (huffman/arithmetical decoding)
* - erisasound (MIODecoder): decodes audio context data into samples
* - erisamatrix (EMT_eri*): iDTC/iLOT/etc helper functions
*
* (this conversion removes encoder/non-MIO parts, hides non-public methods, unifies dupes, tweaks exceptions, improves errors, etc)
*/
/* opaque struct */
typedef struct {

View file

@ -1,37 +1,53 @@
#include <math.h>
#include "coding.h"
#include "../base/decode_state.h"
#include "../base/sbuf.h"
#include "../base/codec_info.h"
#include "../util.h"
#ifdef VGM_USE_VORBIS
#define OV_EXCLUDE_STATIC_CALLBACKS
#include <vorbis/vorbisfile.h>
#define VORBIS_CALL_SAMPLES 1024 // allowed frame 'blocksizes' range from 2^6 ~ 2^13 (64 ~ 8192) but we can return partial samples
#define OGG_DEFAULT_BITSTREAM 0
/* opaque struct */
struct ogg_vorbis_codec_data {
OggVorbis_File ogg_vorbis_file;
int ovf_init;
int bitstream;
int disable_reordering; /* Xiph Ogg must reorder channels on output, but some pre-ordered games don't need it */
int force_seek; /* Ogg with wrong granules can't seek correctly */
int bitstream; // special flag for current stream (in practice can be ignored)
bool ovf_init;
bool disable_reordering; /* Xiph Ogg must reorder channels on output, but some pre-ordered games don't need it */
bool force_seek; /* Ogg with wrong granules can't seek correctly */
int32_t discard;
ogg_vorbis_io io;
vorbis_comment* comment;
int comment_number;
vorbis_info* info;
float* fbuf;
};
static void pcm_convert_float_to_16(int channels, sample_t* outbuf, int start_sample, int samples_to_do, float** pcm, int disable_ordering);
static size_t ov_read_func(void* ptr, size_t size, size_t nmemb, void* datasource);
static int ov_seek_func(void* datasource, ogg_int64_t offset, int whence);
static long ov_tell_func(void* datasource);
static int ov_close_func(void* datasource);
static void free_ogg_vorbis(void* priv_data) {
ogg_vorbis_codec_data* data = priv_data;
if (!data) return;
if (data->ovf_init) {
ov_clear(&data->ogg_vorbis_file);
}
close_streamfile(data->io.streamfile);
free(data->fbuf);
free(data);
}
ogg_vorbis_codec_data* init_ogg_vorbis(STREAMFILE* sf, off_t start, off_t size, ogg_vorbis_io* io) {
ogg_vorbis_codec_data* data = NULL;
@ -98,7 +114,7 @@ ogg_vorbis_codec_data* init_ogg_vorbis(STREAMFILE* sf, off_t start, off_t size,
/* open the ogg vorbis file for real */
if (ov_open_callbacks(&data->io, &data->ogg_vorbis_file, NULL, 0, callbacks))
goto fail;
data->ovf_init = 1;
data->ovf_init = true;
}
//todo could set bitstreams as subsongs?
@ -179,106 +195,48 @@ static int ov_close_func(void* datasource) {
/* ********************************************** */
void decode_ogg_vorbis(ogg_vorbis_codec_data* data, sample_t* outbuf, int32_t samples_to_do, int channels) {
int samples_done = 0;
long start, rc;
float** pcm_channels; /* pointer to Xiph's double array buffer */
static bool decode_frame_ogg_vorbis(VGMSTREAM* v) {
ogg_vorbis_codec_data* data = v->codec_data;
decode_state_t* ds = v->decode_state;
float** pcm_channels;
while (samples_done < samples_to_do) {
rc = ov_read_float(
&data->ogg_vorbis_file, /* context */
&pcm_channels, /* buffer pointer */
(samples_to_do - samples_done), /* samples to produce */
&data->bitstream); /* bitstream */
if (rc <= 0) goto fail; /* rc is samples done */
//TODO: helper? maybe should init in init_vorbis_custom but right now not all vorbises pass channels
if (data->fbuf == NULL) {
data->fbuf = malloc(VORBIS_CALL_SAMPLES * sizeof(float) * v->channels);
if (!data->fbuf) return -1;
}
// Ogg frame samples vary per frame, and API allows to ask for arbitrary max (may return less).
// Limit totals as loop end needs to stop at exact point, since seeking is smoothed between current + loop start
// (decoding a bit more than loop end results in slightly different loops, very minor but done to match older code).
int max_samples = ds->samples_left;
if (max_samples > VORBIS_CALL_SAMPLES)
max_samples = VORBIS_CALL_SAMPLES;
long rc = ov_read_float(&data->ogg_vorbis_file, &pcm_channels, max_samples, &data->bitstream);
if (rc <= 0) // rc is samples done
return false;
sbuf_init_flt(&ds->sbuf, data->fbuf, rc, v->channels);
ds->sbuf.filled = rc;
if (data->disable_reordering)
sbuf_interleave(&ds->sbuf, pcm_channels);
else
sbuf_interleave_vorbis(&ds->sbuf, pcm_channels);
if (data->discard) {
start = data->discard;
if (start > rc)
start = rc;
data->discard -= start;
if (start == rc) /* consume all */
continue;
}
else {
start = 0;
ds->discard = data->discard;
data->discard = 0;
}
pcm_convert_float_to_16(channels, outbuf, start, rc, pcm_channels, data->disable_reordering);
outbuf += (rc - start) * channels;
samples_done += (rc - start);
#if 0 // alt decoding
/* we use ov_read_float as to reuse the xiph's buffer for easier remapping,
* but seems ov_read is slightly faster due to optimized (asm) float-to-int. */
rc = ov_read(
&data->ogg_vorbis_file, /* context */
(char *)(outbuf), /* buffer */
(samples_to_do - samples_done) * sizeof(sample_t) * channels, /* length in bytes */
0, /* pcm endianness */
sizeof(sample_t), /* pcm size */
1, /* pcm signedness */
&data->bitstream); /* bitstream */
if (rc <= 0) goto fail; /* rc is bytes done (for all channels) */
swap_samples_le(outbuf, rc / sizeof(sample_t)); /* endianness is a bit weird with ov_read though */
outbuf += rc / sizeof(sample_t);
samples_done += rc / sizeof(sample_t) / channels;
#endif
}
return;
fail:
VGM_LOG("OGG: error %lx during decode\n", rc);
memset(outbuf, 0, (samples_to_do - samples_done) * channels * sizeof(sample_t));
}
/* vorbis encodes channels in non-standard order, so we remap during conversion to fix this oddity.
* (feels a bit weird as one would think you could leave as-is and set the player's output order,
* but that isn't possible and remapping like this is what FFmpeg and every other plugin does). */
static const int xiph_channel_map[8][8] = {
{ 0 }, /* 1ch: FC > same */
{ 0, 1 }, /* 2ch: FL FR > same */
{ 0, 2, 1 }, /* 3ch: FL FC FR > FL FR FC */
{ 0, 1, 2, 3 }, /* 4ch: FL FR BL BR > same */
{ 0, 2, 1, 3, 4 }, /* 5ch: FL FC FR BL BR > FL FR FC BL BR */
{ 0, 2, 1, 5, 3, 4 }, /* 6ch: FL FC FR BL BR LFE > FL FR FC LFE BL BR */
{ 0, 2, 1, 6, 5, 3, 4 }, /* 7ch: FL FC FR SL SR BC LFE > FL FR FC LFE BC SL SR */
{ 0, 2, 1, 7, 5, 6, 3, 4 }, /* 8ch: FL FC FR SL SR BL BR LFE > FL FR FC LFE BL BR SL SR */
};
/* converts from internal Vorbis format to standard PCM and remaps (mostly from Xiph's decoder_example.c) */
static void pcm_convert_float_to_16(int channels, sample_t* outbuf, int start_sample, int samples_to_do, float** pcm, int disable_ordering) {
int ch, s, ch_map;
sample_t *ptr;
float *channel;
/* convert float PCM (multichannel float array, with pcm[0]=ch0, pcm[1]=ch1, pcm[2]=ch0, etc)
* to 16 bit signed PCM ints (host order) and interleave + fix clipping */
for (ch = 0; ch < channels; ch++) {
ch_map = disable_ordering ?
ch :
(channels > 8) ? ch : xiph_channel_map[channels - 1][ch]; /* put Vorbis' ch to other outbuf's ch */
ptr = outbuf + ch;
channel = pcm[ch_map];
for (s = start_sample; s < samples_to_do; s++) {
int val = (int)floor(channel[s] * 32767.0f + 0.5f); /* use floorf? doesn't seem any faster */
if (val > 32767) val = 32767;
else if (val < -32768) val = -32768;
*ptr = val;
ptr += channels;
}
}
return true;
}
/* ********************************************** */
void reset_ogg_vorbis(ogg_vorbis_codec_data* data) {
static void reset_ogg_vorbis(void* priv_data) {
ogg_vorbis_codec_data* data = priv_data;
if (!data) return;
/* this raw seek cleans internal buffers, and it's preferable to
@ -289,7 +247,8 @@ void reset_ogg_vorbis(ogg_vorbis_codec_data* data) {
data->discard = 0;
}
void seek_ogg_vorbis(ogg_vorbis_codec_data* data, int32_t num_sample) {
static void seek_ogg_vorbis(VGMSTREAM* v, int32_t num_sample) {
ogg_vorbis_codec_data* data = v->codec_data;
if (!data) return;
/* special seek for games with bad granule positions (since ov_*_seek uses granules to seek) */
@ -305,16 +264,6 @@ void seek_ogg_vorbis(ogg_vorbis_codec_data* data, int32_t num_sample) {
//VGM_ASSERT(res != 0, "OGG: bad seek=%i\n", res); /* not seen, in theory could give error */
}
void free_ogg_vorbis(ogg_vorbis_codec_data* data) {
if (!data) return;
if (data->ovf_init)
ov_clear(&data->ogg_vorbis_file);
close_streamfile(data->io.streamfile);
free(data);
}
/* ********************************************** */
int ogg_vorbis_get_comment(ogg_vorbis_codec_data* data, const char** comment) {
@ -354,13 +303,13 @@ void ogg_vorbis_get_samples(ogg_vorbis_codec_data* data, int* p_samples) {
if (p_samples) *p_samples = ov_pcm_total(&data->ogg_vorbis_file,-1);
}
void ogg_vorbis_set_disable_reordering(ogg_vorbis_codec_data* data, int set) {
void ogg_vorbis_set_disable_reordering(ogg_vorbis_codec_data* data, bool set) {
if (!data) return;
data->disable_reordering = set;
}
void ogg_vorbis_set_force_seek(ogg_vorbis_codec_data* data, int set) {
void ogg_vorbis_set_force_seek(ogg_vorbis_codec_data* data, bool set) {
if (!data) return;
data->force_seek = set;
@ -371,4 +320,13 @@ STREAMFILE* ogg_vorbis_get_streamfile(ogg_vorbis_codec_data* data) {
return data->io.streamfile;
}
const codec_info_t ogg_vorbis_decoder = {
.sample_type = SFMT_FLT,
.decode_frame = decode_frame_ogg_vorbis,
.free = free_ogg_vorbis,
.reset = reset_ogg_vorbis,
.seek = seek_ogg_vorbis,
};
#endif

View file

@ -1,6 +1,9 @@
#include "coding.h"
#include "../util.h"
#include <math.h>
#include "../base/decode_state.h"
#include "../base/codec_info.h"
#include "../util/endianness.h"
void decode_pcm16le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i;
@ -124,139 +127,173 @@ void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL* stream, sampl
}
}
static int expand_ulaw(uint8_t ulawbyte) {
int sign, segment, quantization, sample;
const int bias = 0x84;
ulawbyte = ~ulawbyte; /* stored in complement */
sign = (ulawbyte & 0x80);
segment = (ulawbyte & 0x70) >> 4; /* exponent */
quantization = ulawbyte & 0x0F; /* mantissa */
sample = (quantization << 3) + bias; /* add bias */
sample <<= segment;
sample = (sign) ? (bias - sample) : (sample - bias); /* remove bias */
#if 0 // the above follows Sun's implementation, but this works too
{
static int exp_lut[8] = {0,132,396,924,1980,4092,8316,16764}; /* precalcs from bias */
new_sample = exp_lut[segment] + (quantization << (segment + 3));
if (sign != 0) new_sample = -new_sample;
}
#endif
return sample;
}
/* decodes u-law (ITU G.711 non-linear PCM), from g711.c */
void decode_ulaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t ulawbyte = read_8bit(stream->offset+i,stream->streamfile);
outbuf[sample_count] = expand_ulaw(ulawbyte);
}
}
void decode_ulaw_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t ulawbyte = read_8bit(stream->offset+i*channelspacing,stream->streamfile);
outbuf[sample_count] = expand_ulaw(ulawbyte);
}
}
static int expand_alaw(uint8_t alawbyte) {
int sign, segment, quantization, sample;
alawbyte ^= 0x55;
sign = (alawbyte & 0x80);
segment = (alawbyte & 0x70) >> 4; /* exponent */
quantization = alawbyte & 0x0F; /* mantissa */
sample = (quantization << 4);
switch (segment) {
case 0:
sample += 8;
break;
case 1:
sample += 0x108;
break;
default:
sample += 0x108;
sample <<= segment - 1;
break;
}
sample = (sign) ? sample : -sample;
return sample;
}
/* decodes a-law (ITU G.711 non-linear PCM), from g711.c */
void decode_alaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t alawbyte = read_8bit(stream->offset+i,stream->streamfile);
outbuf[sample_count] = expand_alaw(alawbyte);;
}
}
void decode_pcmfloat(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) {
int i, sample_count;
float (*read_f32)(off_t,STREAMFILE*) = big_endian ? read_f32be : read_f32le;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
float sample_float = read_f32(stream->offset+i*4,stream->streamfile);
// TODO: remove after public API is used
static void decode_pcmfloat_i16(VGMSTREAMCHANNEL* stream, int16_t* outbuf, int channels, int samples_to_do, bool big_endian) {
read_f32_t read_f32 = big_endian ? read_f32be : read_f32le;
int s = 0;
off_t offset = stream->offset;
while (s < samples_to_do) {
float sample_float = read_f32(offset, stream->streamfile);
int sample_pcm = (int)floor(sample_float * 32767.f + .5f);
outbuf[sample_count] = clamp16(sample_pcm);
outbuf[s] = clamp16(sample_pcm);
s += channels;
offset += 0x04;
}
}
void decode_pcm24be(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i;
int32_t sample_count;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count += channelspacing) {
off_t offset = stream->offset + i * 0x03;
int v = read_u8(offset+0x02, stream->streamfile) | (read_s16be(offset + 0x00, stream->streamfile) << 8);
outbuf[sample_count] = (v >> 8);
static void decode_pcmfloat(VGMSTREAMCHANNEL* stream, float* buf, int channels, int samples_to_do, bool big_endian) {
read_f32_t read_f32 = big_endian ? read_f32be : read_f32le;
int s = 0;
off_t offset = stream->offset;
while (s < samples_to_do) {
buf[s] = read_f32(offset, stream->streamfile);
s += channels;
offset += 0x04;
}
}
void decode_pcm24le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i;
int32_t sample_count;
bool decode_buf_pcmfloat(VGMSTREAM* v, sbuf_t* sdst) {
decode_state_t* ds = v->decode_state;
bool big_endian = v->codec_endian;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t offset = stream->offset + i * 0x03;
int v = read_u8(offset+0x00, stream->streamfile) | (read_s16le(offset + 0x01, stream->streamfile) << 8);
outbuf[sample_count] = (v >> 8);
if (sdst->fmt == SFMT_S16) {
//TODO remove
// using vgmstream without API (render_vgmstream) usually passes a S16 buf
// could handle externally but blah blah, allow as-is for now
int16_t* buffer = sdst->buf;
buffer += sdst->filled * v->channels;
for (int ch = 0; ch < v->channels; ch++) {
decode_pcmfloat_i16(&v->ch[ch], buffer + ch, v->channels, ds->samples_left, big_endian);
}
}
else {
float* buffer = sdst->buf;
buffer += sdst->filled * v->channels;
for (int ch = 0; ch < v->channels; ch++) {
decode_pcmfloat(&v->ch[ch], buffer + ch, v->channels, ds->samples_left, big_endian);
}
}
void decode_pcm32le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i;
int32_t sample_count;
return true;
}
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t offset = stream->offset + i * 0x04;
int32_t v = read_s32le(offset, stream->streamfile);
outbuf[sample_count] = (v >> 16);
static inline int32_t read_s24be(off_t offset, STREAMFILE* sf) {
return (read_s16be(offset + 0x00, sf) << 8) | read_u8(offset + 0x02, sf);
}
static inline int32_t read_s24le(off_t offset, STREAMFILE* sf) {
return read_u8(offset + 0x00, sf) | (read_s16le(offset + 0x01, sf) << 8);
}
// TODO: remove after public API is used
static void decode_pcm24_i16(VGMSTREAMCHANNEL* stream, int16_t* buf, int channels, int samples_to_do, bool big_endian) {
read_s32_t read_s24 = big_endian ? read_s24be : read_s24le;
int s = 0;
off_t offset = stream->offset;
while (s < samples_to_do) {
buf[s] = read_s24(offset, stream->streamfile) >> 8;
s += channels;
offset += 0x03;
}
}
static void decode_pcm24(VGMSTREAMCHANNEL* stream, int32_t* buf, int channels, int samples_to_do, bool big_endian) {
read_s32_t read_s24 = big_endian ? read_s24be : read_s24le;
int s = 0;
off_t offset = stream->offset;
while (s < samples_to_do) {
buf[s] = read_s24(offset, stream->streamfile);
s += channels;
offset += 0x03;
}
}
bool decode_buf_pcm24(VGMSTREAM* v, sbuf_t* sdst) {
decode_state_t* ds = v->decode_state;
bool big_endian = v->coding_type == coding_PCM24BE;
if (sdst->fmt == SFMT_S16) {
//TODO remove
// using vgmstream without API (render_vgmstream) usually passes a S16 buf
// could handle externally but blah blah, allow as-is for now
int16_t* buffer = sdst->buf;
buffer += sdst->filled * v->channels;
for (int ch = 0; ch < v->channels; ch++) {
decode_pcm24_i16(&v->ch[ch], buffer + ch, v->channels, ds->samples_left, big_endian);
}
}
else {
int32_t* buffer = sdst->buf;
buffer += sdst->filled * v->channels;
for (int ch = 0; ch < v->channels; ch++) {
decode_pcm24(&v->ch[ch], buffer + ch, v->channels, ds->samples_left, big_endian);
}
}
return true;
}
// TODO: remove after public API is used
static void decode_pcm32_i16(VGMSTREAMCHANNEL* stream, int16_t* buf, int channels, int samples_to_do, bool big_endian) {
read_s32_t read_s32 = big_endian ? read_s32be : read_s32le;
int s = 0;
off_t offset = stream->offset;
while (s < samples_to_do) {
buf[s] = read_s32(offset, stream->streamfile) >> 16;
s += channels;
offset += 0x04;
}
}
static void decode_pcm32(VGMSTREAMCHANNEL* stream, int32_t* buf, int channels, int samples_to_do, bool big_endian) {
read_s32_t read_s32 = big_endian ? read_s32be : read_s32le;
int s = 0;
off_t offset = stream->offset;
while (s < samples_to_do) {
buf[s] = read_s32(offset, stream->streamfile);
s += channels;
offset += 0x04;
}
}
bool decode_buf_pcm32(VGMSTREAM* v, sbuf_t* sdst) {
decode_state_t* ds = v->decode_state;
bool big_endian = false;
if (sdst->fmt == SFMT_S16) {
//TODO remove
// using vgmstream without API (render_vgmstream) usually passes a S16 buf
// could handle externally but blah blah, allow as-is for now
int16_t* buffer = sdst->buf;
buffer += sdst->filled * v->channels;
for (int ch = 0; ch < v->channels; ch++) {
decode_pcm32_i16(&v->ch[ch], buffer + ch, v->channels, ds->samples_left, big_endian);
}
}
else {
int32_t* buffer = sdst->buf;
buffer += sdst->filled * v->channels;
for (int ch = 0; ch < v->channels; ch++) {
decode_pcm32(&v->ch[ch], buffer + ch, v->channels, ds->samples_left, big_endian);
}
}
return true;
}
int32_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample) {
if (channels <= 0 || bits_per_sample <= 0) return 0;
return ((int64_t)bytes * 8) / channels / bits_per_sample;
}
#if 0
int32_t pcm32_bytes_to_samples(size_t bytes, int channels) {
return pcm_bytes_to_samples(bytes, channels, 32);
}
#endif
int32_t pcm24_bytes_to_samples(size_t bytes, int channels) {
return pcm_bytes_to_samples(bytes, channels, 24);
@ -269,3 +306,18 @@ int32_t pcm16_bytes_to_samples(size_t bytes, int channels) {
int32_t pcm8_bytes_to_samples(size_t bytes, int channels) {
return pcm_bytes_to_samples(bytes, channels, 8);
}
const codec_info_t pcm32_decoder = {
.sample_type = SFMT_S32,
.decode_buf = decode_buf_pcm32,
};
const codec_info_t pcm24_decoder = {
.sample_type = SFMT_S24,
.decode_buf = decode_buf_pcm24,
};
const codec_info_t pcmfloat_decoder = {
.sample_type = SFMT_FLT,
.decode_buf = decode_buf_pcmfloat,
};

View file

@ -97,7 +97,7 @@ bool decode_frame_tac(VGMSTREAM* v) {
if (samples < 0)
return false;
sbuf_init_f32(&ds->sbuf, data->fbuf, samples, v->channels);
sbuf_init_f16(&ds->sbuf, data->fbuf, samples, v->channels);
ds->sbuf.filled = samples;
// copy and let decoder handle
@ -146,7 +146,7 @@ static void seek_tac(VGMSTREAM* v, int32_t num_sample) {
}
const codec_info_t tac_decoder = {
.sample_type = SFMT_F32,
.sample_type = SFMT_F16,
.decode_frame = decode_frame_tac,
.free = free_tac,
.reset = reset_tac,

View file

@ -0,0 +1,84 @@
#include "coding.h"
#include "../util.h"
#include <math.h>
static int expand_ulaw(uint8_t ulawbyte) {
int sign, segment, quantization, sample;
const int bias = 0x84;
ulawbyte = ~ulawbyte; /* stored in complement */
sign = (ulawbyte & 0x80);
segment = (ulawbyte & 0x70) >> 4; /* exponent */
quantization = ulawbyte & 0x0F; /* mantissa */
sample = (quantization << 3) + bias; /* add bias */
sample <<= segment;
sample = (sign) ? (bias - sample) : (sample - bias); /* remove bias */
#if 0 // the above follows Sun's implementation, but this works too
{
static int exp_lut[8] = {0,132,396,924,1980,4092,8316,16764}; /* precalcs from bias */
new_sample = exp_lut[segment] + (quantization << (segment + 3));
if (sign != 0) new_sample = -new_sample;
}
#endif
return sample;
}
/* decodes u-law (ITU G.711 non-linear PCM), from g711.c */
void decode_ulaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t ulawbyte = read_u8(stream->offset+i,stream->streamfile);
outbuf[sample_count] = expand_ulaw(ulawbyte);
}
}
void decode_ulaw_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t ulawbyte = read_u8(stream->offset+i*channelspacing,stream->streamfile);
outbuf[sample_count] = expand_ulaw(ulawbyte);
}
}
static int expand_alaw(uint8_t alawbyte) {
int sign, segment, quantization, sample;
alawbyte ^= 0x55;
sign = (alawbyte & 0x80);
segment = (alawbyte & 0x70) >> 4; /* exponent */
quantization = alawbyte & 0x0F; /* mantissa */
sample = (quantization << 4);
switch (segment) {
case 0:
sample += 8;
break;
case 1:
sample += 0x108;
break;
default:
sample += 0x108;
sample <<= segment - 1;
break;
}
sample = (sign) ? sample : -sample;
return sample;
}
/* decodes a-law (ITU G.711 non-linear PCM), from g711.c */
void decode_alaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t alawbyte = read_8bit(stream->offset+i,stream->streamfile);
outbuf[sample_count] = expand_alaw(alawbyte);;
}
}

View file

@ -422,6 +422,7 @@ static const char* extension_list[] = {
"oor",
"opu",
//"opus", //common
"opusnx",
"opusx",
"oto", //txth/reserved [Vampire Savior (SAT)]
"ovb", //txth/semi [namCollection: Tekken (PS2), Tekken 5: Tekken 1-3 (PS2)]
@ -460,7 +461,6 @@ static const char* extension_list[] = {
"rda", //FFmpeg/reserved [Rhythm Destruction (PC)]
"res", //txth/reserved [Spider-Man: Web of Shadows (PSP)]
"rkv",
"rnd",
"rof",
"rpgmvo",
"rrds",
@ -501,7 +501,7 @@ static const char* extension_list[] = {
"sbr",
"sbv",
"sig",
"slb", //txth/reserved [Vingt-et-un Systems PS2 games (Last Escort, etc]
"slb", //txth/reserved [Vingt-et-un Systems PS2 games (Last Escort, etc)]
"sm0",
"sm1",
"sm2",
@ -540,6 +540,7 @@ static const char* extension_list[] = {
"smk",
"smp",
"smv",
"sn0",
"snb",
"snd",
"snds",
@ -559,6 +560,7 @@ static const char* extension_list[] = {
"srsa",
"ss2",
"ssd", //txth/reserved [Zack & Wiki (Wii)]
"ssf",
"ssm",
"sspr",
"ssp",
@ -617,7 +619,6 @@ static const char* extension_list[] = {
"vai",
"vam", //txth/reserved [Rocket Power: Beach Bandits (PS2)]
"vas",
"vawx",
"vb", //txth/reserved [Tantei Jinguji Saburo: Mikan no Rupo (PS1)]
"vbk",
"vbx", //txth/reserved [THE Taxi 2 (PS2)]
@ -703,6 +704,7 @@ static const char* extension_list[] = {
"xnb",
"xsh",
"xsf",
"xst",
"xse",
"xsew",
"xss",
@ -978,13 +980,13 @@ static const layout_info layout_info_list[] = {
{layout_blocked_ea_1snh, "blocked (EA 1SNh)"},
{layout_blocked_caf, "blocked (CAF)"},
{layout_blocked_wsi, "blocked (WSI)"},
{layout_blocked_xvas, "blocked (.vas)"},
{layout_blocked_vas_kceo, "blocked (.vas)"},
{layout_blocked_str_snds, "blocked (.str SNDS)"},
{layout_blocked_ws_aud, "blocked (Westwood Studios .aud)"},
{layout_blocked_dec, "blocked (DEC)"},
{layout_blocked_vs_mh, "blocked (Melbourne House VS)"},
{layout_blocked_mul, "blocked (MUL)"},
{layout_blocked_gsb, "blocked (GSB)"},
{layout_blocked_gsnd, "blocked (GSND)"},
{layout_blocked_thp, "blocked (THP)"},
{layout_blocked_filp, "blocked (FILP)"},
{layout_blocked_ea_swvr, "blocked (EA SWVR)"},
@ -1163,7 +1165,7 @@ static const meta_info meta_info_list[] = {
{meta_YDSP, "Yuke's YDSP Header"},
{meta_SSM, "HAL Laboratory .SSM Header"},
{meta_PS2_JOE, "Asobo Studio .JOE header"},
{meta_VGS, "Guitar Hero VGS Header"},
{meta_VGS, "Harmonix VGS Header"},
{meta_DCS_WAV, "In Utero DCS+WAV header"},
{meta_SMP, "Infernal Engine .smp header"},
{meta_MUL, "Crystal Dynamics .MUL header"},
@ -1173,7 +1175,7 @@ static const meta_info meta_info_list[] = {
{meta_GBTS, "Konami GBTS header"},
{meta_NGC_DSP_IADP, "IADP Header"},
{meta_RIFF_WAVE_ctrl, "RIFF WAVE header (ctrl looping)"},
{meta_FFCC_STR, "Final Fantasy: Crystal Chronicles STR header"},
{meta_STR_SQEX, "Square Enix STR header"},
{meta_SAT_BAKA, "Konami BAKA header"},
{meta_SWAV, "Nintendo SWAV header"},
{meta_VSF, "Square Enix VSF header"},
@ -1188,12 +1190,12 @@ static const meta_info meta_info_list[] = {
{meta_WII_NDP, "Icon Games NDP header"},
{meta_PS2_SPS, "Ape Escape 2 SPS Header"},
{meta_NDS_HWAS, "Vicarious Visions HWAS header"},
{meta_NGC_LPS, "Rave Master LPS Header"},
{meta_LPS, "Konami .LPS Header"},
{meta_NAOMI_ADPCM, "NAOMI/NAOMI2 Arcade games ADPCM header"},
{meta_SD9, "Konami SD9 header"},
{meta_2DX9, "Konami 2DX9 header"},
{meta_DSP_KCEJE, "Konami .DSP Header"},
{meta_PS2_VGV, "Rune: Viking Warlord VGV Header"},
{meta_VGV, "Human Head .VGV header"},
{meta_GCUB, "Sega GCub header"},
{meta_NGC_SCK_DSP, "The Scorpion King SCK Header"},
{meta_CAFF, "Apple Core Audio Format File header"},
@ -1239,7 +1241,7 @@ static const meta_info meta_info_list[] = {
{meta_XVAG, "Sony XVAG header"},
{meta_CPS, "tri-Crescendo CPS Header"},
{meta_SQEX_SCD, "Square Enix SCD header"},
{meta_NGC_NST_DSP, "Animaniacs NST header"},
{meta_NST_MONSTER, "Monster .NST header"},
{meta_BAF, "Bizarre Creations .baf header"},
{meta_MSF, "Sony MSF header"},
{meta_SNDP, "Premium Agency SNDP header"},
@ -1247,7 +1249,7 @@ static const meta_info meta_info_list[] = {
{meta_RAS, "Retro RAS_ header"},
{meta_SPM, "Square SPM header"},
{meta_VGS_PS, "Princess Soft VGS header"},
{meta_PS2_IAB, "Runtime .IAB header"},
{meta_IAB, "Runtime .IAB header"},
{meta_VS_STR, "Square .VS STRx header"},
{meta_LSF_N1NJ4N, "Gizmondo Studios Helsingborg LSF header"},
{meta_XWAV, "feelplus XWAV header"},
@ -1256,13 +1258,13 @@ static const meta_info meta_info_list[] = {
{meta_PSND, "Polarbit PSND header"},
{meta_ADP_WILDFIRE, "Wildfire ADP! header"},
{meta_QD_ADP, "Quantic Dream .ADP header"},
{meta_EB_SFX, "Excitebots .sfx header"},
{meta_EB_SF0, "assumed Excitebots .sf0 by extension"},
{meta_SFX0_MONSTER, "Monster SFX0 header"},
{meta_SONG_MONSTER, "Monster SONG header"},
{meta_MTAF, "Konami MTAF header"},
{meta_ALP, "High Voltage ALP header"},
{meta_WPD, "Navel WPD header"},
{meta_MN_STR, "Mini Ninjas 'STR' header"},
{meta_MSS, "Guerilla MCSS header"},
{meta_MCSS, "Guerilla MCSS header"},
{meta_PS2_HSF, "Lowrider 'HSF' header"},
{meta_IVAG, "Namco IVAG header"},
{meta_2PFS, "Konami 2PFS header"},
@ -1275,7 +1277,7 @@ static const meta_info meta_info_list[] = {
{meta_KTSS, "Koei Tecmo KTSS header"},
{meta_IDSP_NAMCO, "Namco IDSP header"},
{meta_BTSND, "Nintendo Wii U Menu Boot Sound header"},
{meta_MCA, "Capcom MCA header"},
{meta_MADP, "Capcom MADP header"},
{meta_ADX_MONSTER, "Monster Games .ADX header"},
{meta_HCA, "CRI HCA header"},
{meta_SVAG_SNK, "SNK SVAG header"},
@ -1306,11 +1308,11 @@ static const meta_info meta_info_list[] = {
{meta_EA_SNU, "Electronic Arts SNU header"},
{meta_AWC, "Rockstar AWC header"},
{meta_OPUS, "Nintendo Switch OPUS header"},
{meta_PC_AST, "Capcom AST (PC) header"},
{meta_ASTL, "Capcom ASTL header"},
{meta_UBI_SB, "Ubisoft SBx header"},
{meta_UBI_APM, "Ubisoft APM header"},
{meta_NAAC, "Namco NAAC header"},
{meta_EZW, "EZ2DJ EZWAVE header"},
{meta_EZW, "AmuseWorld EZW header"},
{meta_VXN, "Gameloft VXN header"},
{meta_EA_SNR_SNS, "Electronic Arts SNR+SNS header"},
{meta_EA_SPS, "Electronic Arts SPS header"},
@ -1367,7 +1369,7 @@ static const meta_info meta_info_list[] = {
{meta_AO, "AlphaOgg .AO header"},
{meta_APC, "Cryo APC header"},
{meta_WAV2, "Infogrames North America WAV2 header"},
{meta_XAU_KONAMI, "Konami XAU header"},
{meta_SFXB, "Konami SFXB header"},
{meta_DERF, "Xilam DERF header"},
{meta_UTK, "Maxis UTK header"},
{meta_NXA1, "Entergram NXA1 header"},
@ -1462,7 +1464,7 @@ static const meta_info meta_info_list[] = {
{meta_SNDS, "Sony SNDS header"},
{meta_NXOF, "Nihon Falcom FDK header"},
{meta_GWB_GWD, "Ubisoft GWB+GWD header"},
{meta_CBX, "Traveller's Tales CBX header"},
{meta_CBX, "Traveller's Tales/Warthog Chatterbox header"},
{meta_VAS_ROCKSTAR, "Rockstar .VAS header"},
{meta_EA_SBK, "Electronic Arts SBK header"},
{meta_DSP_ASURA, "Rebellion DSP header"},

View file

@ -133,14 +133,14 @@ void block_update(off_t block_offset, VGMSTREAM* vgmstream) {
case layout_blocked_mul:
block_update_mul(block_offset,vgmstream);
break;
case layout_blocked_gsb:
block_update_gsb(block_offset,vgmstream);
case layout_blocked_gsnd:
block_update_gsnd(block_offset,vgmstream);
break;
case layout_blocked_vs_mh:
block_update_vs_mh(block_offset,vgmstream);
break;
case layout_blocked_xvas:
block_update_xvas(block_offset,vgmstream);
case layout_blocked_vas_kceo:
block_update_vas_kceo(block_offset,vgmstream);
break;
case layout_blocked_thp:
block_update_thp(block_offset,vgmstream);

View file

@ -3,17 +3,14 @@
/* set up for the block at the given offset */
void block_update_filp(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
STREAMFILE* sf = vgmstream->ch[0].streamfile;
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = read_32bitLE(
vgmstream->current_block_offset+0x18,
vgmstream->ch[0].streamfile)-0x800;
vgmstream->next_block_offset = vgmstream->current_block_offset+vgmstream->current_block_size+0x800;
vgmstream->current_block_size = read_u32le(block_offset + 0x18,sf) - 0x800;
vgmstream->next_block_offset = block_offset + vgmstream->current_block_size + 0x800;
vgmstream->current_block_size /= vgmstream->channels;
for (i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].offset = vgmstream->current_block_offset+0x800+(vgmstream->current_block_size*i);
for (int i = 0; i < vgmstream->channels; i++) {
vgmstream->ch[i].offset = block_offset + 0x800+(vgmstream->current_block_size*i);
}
}

View file

@ -1,28 +0,0 @@
#include "layout.h"
#include "../vgmstream.h"
/* set up for the block at the given offset */
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*/
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = block_channel_size;
vgmstream->next_block_offset = vgmstream->current_block_offset
+ block_header_size
+ block_channel_size * vgmstream->channels;
for (i=0;i<vgmstream->channels;i++) {
int interleave;
int filesize = vgmstream->ch[i].streamfile->get_size(vgmstream->ch[i].streamfile);
if (vgmstream->next_block_offset > filesize)
interleave = (filesize - vgmstream->current_block_offset - block_header_size) / vgmstream->channels;
else
interleave = block_channel_size;
vgmstream->ch[i].offset = vgmstream->current_block_offset
+ block_header_size
+ (interleave*i);
}
}

View file

@ -0,0 +1,25 @@
#include "layout.h"
#include "../vgmstream.h"
/* set up for the block at the given offset */
void block_update_gsnd(off_t block_offset, VGMSTREAM * vgmstream) {
STREAMFILE* sf = vgmstream->ch[0].streamfile;
int block_header_size = 0x20; // from header
int block_channel_size = 0x8000; // from header, per channel
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = block_channel_size;
vgmstream->next_block_offset = block_offset + block_header_size + block_channel_size * vgmstream->channels;
uint32_t file_size = get_streamfile_size(sf);
for (int i = 0; i < vgmstream->channels; i++) {
int interleave;
if (vgmstream->next_block_offset > file_size)
interleave = (file_size - block_offset - block_header_size) / vgmstream->channels;
else
interleave = block_channel_size;
vgmstream->ch[i].offset = block_offset + block_header_size + (interleave * i);
}
}

View file

@ -0,0 +1,22 @@
#include "layout.h"
#include "../vgmstream.h"
/* set up for the block at the given offset */
void block_update_vas_kceo(off_t block_offset, VGMSTREAM* vgmstream) {
STREAMFILE* sf = vgmstream->ch[0].streamfile;
// last block is smaller in a few non-looped files
int file_size = get_streamfile_size(sf);
int block_size = 0x20000;
if (block_offset + block_size > file_size) {
block_size = file_size - block_offset;
}
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = (block_size - 0x20) / vgmstream->channels;
vgmstream->next_block_offset = block_offset + block_size;
for (int i = 0; i < vgmstream->channels; i++) {
vgmstream->ch[i].offset = block_offset; //stereo XBOX-IMA
}
}

View file

@ -1,24 +0,0 @@
#include "layout.h"
#include "../vgmstream.h"
/* set up for the block at the given offset */
void block_update_xvas(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
if((vgmstream->current_block_offset-get_streamfile_size(vgmstream->ch[0].streamfile))>(0x20000-0x20))
vgmstream->current_block_size = 0x20000-0x20;
else
vgmstream->current_block_size = vgmstream->current_block_offset-get_streamfile_size(vgmstream->ch[0].streamfile)-0x20;
vgmstream->next_block_offset =
vgmstream->current_block_offset +
(vgmstream->current_block_size + 0x20);
for (i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].offset = vgmstream->current_block_offset;
}
vgmstream->current_block_size /=2;
}

View file

@ -39,7 +39,7 @@ void loop_layout_segmented(VGMSTREAM* vgmstream, int32_t loop_sample);
typedef struct {
int layer_count;
VGMSTREAM** layers;
sample_t* buffer;
void* buffer;
int input_channels; /* internal buffer channels */
int output_channels; /* resulting channels (after mixing, if applied) */
int external_looping; /* don't loop using per-layer loops, but layout's own looping */
@ -72,8 +72,8 @@ void block_update_ws_aud(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_dec(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_vs_mh(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_mul(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_gsnd(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_vas_kceo(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_rage_aud(off_t block_offset, VGMSTREAM* vgmstream);

View file

@ -64,7 +64,7 @@
LIBVGMSTREAM_API uint32_t libvgmstream_get_version(void);
/* CHANGELOG:
* - 1.0.0: initial version
* - 1.0.0: beta version
*/
@ -74,8 +74,8 @@ LIBVGMSTREAM_API uint32_t libvgmstream_get_version(void);
/* available sample formats, interleaved: buf[0]=ch0, buf[1]=ch1, buf[2]=ch0, buf[3]=ch0, ... */
typedef enum {
LIBVGMSTREAM_SFMT_PCM16 = 1,
//LIBVGMSTREAM_SFMT_PCM24 = 2,
//LIBVGMSTREAM_SFMT_PCM32 = 3,
LIBVGMSTREAM_SFMT_PCM24 = 2,
LIBVGMSTREAM_SFMT_PCM32 = 3,
LIBVGMSTREAM_SFMT_FLOAT = 4,
} libvgmstream_sfmt_t;

View file

@ -3,48 +3,58 @@
#include "../layout/layout.h"
/* .2dx - Konami/Bemani beatmania IIDX container [beatmania IIDX 9th Style (AC) - beatmania IIDX 15 DJ TROOPERS (AC)] */
/* .2dx - Konami/Bemani beatmania IIDX container [beatmania IIDX 9th Style (AC) - beatmania IIDX 15 DJ TROOPERS (AC), Bishi Bashi Channel (AC)] */
VGMSTREAM* init_vgmstream_2dx(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
int target_subsong = sf->stream_index, total_subsongs;
uint32_t meta_offset, table_offset, subfile_offset, subfile_size;
/* checks */
if (!check_extensions(sf, "2dx"))
goto fail;
return NULL;
/* Check for leftover crypto header */
/*
if (read_u32be(0x00, sf) == 0x25654E63 || //IIDX 9th Style
read_u32be(0x00, sf) == 0x25653130 || //IIDX 10th Style
read_u32be(0x00, sf) == 0x25653131 || //IIDX 11 RED
read_u32be(0x00, sf) == 0x25653132 || //IIDX 12 HAPPY SKY
read_u32be(0x00, sf) == 0x25686964 || //IIDX 15 DJ TROOPERS
read_u32be(0x00, sf) == 0x25694F30) //IIDX 16 EMPRESS
meta_offset = 0x18;
else */
meta_offset = 0x10;
table_offset = meta_offset + 0x38;
// check for leftover crypto header (not part of the file):
// - "%eNc" IIDX 9th Style
// - "%e10" IIDX 10th Style
// - "%e11" IIDX 11 RED
// - "%e12" IIDX 12 HAPPY SKY
// - "%hid" IIDX 15 DJ TROOPERS
// - "%iO0" IIDX 16 EMPRESS
uint32_t skip_offset = 0x00;
uint32_t header_id = read_u32be(0x00, sf);
uint32_t data_size = read_u32le(0x04, sf); // without padding (0x04 or 0x10)
if ((header_id >> 24) == '%' && data_size + 0x10 > get_streamfile_size(sf)) {
skip_offset = 0x08;
}
// 00: bank name
// 10: first subsong offset
// 14: subsongs
// 18+: memory garbage?
// 48: table
uint32_t table_offset = 0x48 + skip_offset;
uint32_t first_offset = read_u32le(0x10 + skip_offset,sf);
int target_subsong = sf->stream_index;
int total_subsongs = read_u32le(0x14 + skip_offset,sf);
if (target_subsong == 0) target_subsong = 1;
total_subsongs = read_u32le(meta_offset + 0x4,sf);
if (target_subsong > total_subsongs)
goto fail;
if (target_subsong > total_subsongs || total_subsongs < 1) // arbitrary max
return NULL;
subfile_offset = read_u32le(table_offset + 0x04 * (target_subsong - 1), sf);
subfile_size = read_u32le(subfile_offset + 0x8,sf) + 0x18;
// extra checks to fail faster
if (total_subsongs > 1024) // arbitrary max
return NULL;
if (first_offset != read_u32le(table_offset, sf))
return NULL;
uint32_t subfile_offset = read_u32le(table_offset + 0x04 * (target_subsong - 1), sf) + skip_offset;
uint32_t subfile_size = read_u32le(subfile_offset + 0x08, sf) + 0x18;
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "2dx9");
if (!temp_sf) goto fail;
temp_sf->stream_index = 1;
vgmstream = init_vgmstream_2dx9(temp_sf);
if (!vgmstream) goto fail;
if (vgmstream->num_streams > 1)
goto fail;
vgmstream->num_streams = total_subsongs;
close_streamfile(temp_sf);

View file

@ -6,26 +6,35 @@ VGMSTREAM* init_vgmstream_astb(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset, data_size;
int loop_flag, channels;
int i, xma_streams;
/* check */
/* checks */
if (!is_id32be(0x00,sf, "ASTB"))
goto fail;
return NULL;
if (!check_extensions(sf,"ast"))
goto fail;
if (read_u32be(0x04,sf) != get_streamfile_size(sf))
goto fail;
if (read_u16be(0x30,sf) != 0x165) /* only seen XMA1 */
goto fail;
return NULL;
// 04: file size
// 08: 0x200?
// 0c: version?
start_offset = read_u32be(0x10,sf);
// 14: -1?
// 18: -1?
// 1c: -1?
data_size = read_u32be(0x20,sf);
xma_streams = read_u16be(0x38,sf);
// 24: -1?
// 28: -1?
// 2c: -1?
if (read_u16be(0x30,sf) != 0x0165) // XMA1 only
return NULL;
// 32: xma info size
// 34: xma config
int xma_streams = read_u16be(0x38,sf);
loop_flag = read_u8(0x3a,sf);
channels = 0; /* sum of all stream channels (though only 1/2ch ever seen) */
for (i = 0; i < xma_streams; i++) {
int sample_rate = read_s32be(0x3c + 0x04,sf); // first stream
channels = 0; // sum of all stream channels (though only 1/2ch are ever seen)
for (int i = 0; i < xma_streams; i++) {
channels += read_u8(0x3c + 0x14 * i + 0x11,sf);
}
@ -34,8 +43,8 @@ VGMSTREAM* init_vgmstream_astb(STREAMFILE* sf) {
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_s32be(0x40,sf);
vgmstream->meta_type = meta_ASTB;
vgmstream->sample_rate = sample_rate;
{
/* manually find sample offsets (XMA1 nonsense again) */

View file

@ -0,0 +1,57 @@
#include "meta.h"
#include "../coding/coding.h"
/* ASTL - found in Dead Rising (PC) */
VGMSTREAM* init_vgmstream_astl(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset, data_size;
int loop_flag, channels;
/* checks */
if (!is_id32be(0x00,sf, "ASTL"))
return NULL;
if (!check_extensions(sf,"ast"))
return NULL;
// 04: null
// 08: 0x201?
// 0c: version?
start_offset = read_u32le(0x10,sf);
// 14: null?
// 18: null?
// 1c: null?
data_size = read_u32le(0x20,sf);
// 24: -1?
// 28: -1?
// 2c: -1?
if (read_u16le(0x30,sf) != 0x0001) // PCM only
return NULL;
channels = read_u16le(0x32, sf);
int sample_rate = read_s32le(0x34,sf);
// 38: bitrate
// 3a: block size
// 3c: bps
loop_flag = 0; // unlike X360 no apparent loop info in the files
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_ASTL;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = pcm16_bytes_to_samples(data_size, channels);
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x2;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -67,7 +67,7 @@ VGMSTREAM* init_vgmstream_axhd(STREAMFILE* sf) {
h.sample_rate = 44100;
continue;
}
VGM_LOG("%x: %x + %x\n", sound_offset, h.stream_offset, h.stream_size );
// fmt
codec = read_u16le(sound_offset + 0x26, sf);
h.channels = read_u16le(sound_offset + 0x28, sf);

View file

@ -2,17 +2,19 @@
#include "../coding/coding.h"
/* !B0X - Traveller's Tales speech files [Lego Batman 2 (PC), Lego Dimensions (PS3)] */
VGMSTREAM* init_vgmstream_cbx(STREAMFILE* sf) {
/* !B0X/CB03 - Traveller's Tales (!B0X) / Warthog (CB03) speech files [Lego Batman 2 (PC), Lego Dimensions (PS3), Animaniacs: The Great Edgar Hunt (GC)] */
VGMSTREAM* init_vgmstream_chatterbox(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
uint32_t start_offset, pcm_size;
int loop_flag, channels, sample_rate;
/* checks */
if (!is_id32be(0x00,sf, "!B0X"))
if (!is_id32be(0x00,sf, "!B0X") && !is_id32be(0x00,sf, "CB03"))
return NULL;
if (!check_extensions(sf, "cbx"))
// .cbx: Traveller's Tales
// .box: Warthog
if (!check_extensions(sf, "cbx,box"))
return NULL;
/* debug strings identify this as "Chatterbox"/"CBOX"/"CBX", while sound lib seems called "NuSound"

View file

@ -1,169 +0,0 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util.h"
/* a few formats from Excitebots */
/* .sfx, some .sf0 - DSP and PCM */
VGMSTREAM * init_vgmstream_eb_sfx(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag = 0;
int channel_count;
int coding_type;
long body_size;
long header_size;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("sfx",filename_extension(filename)) &&
strcasecmp("sf0",filename_extension(filename)))
goto fail;
/* check sizes */
body_size = read_32bitLE(0x00,streamFile);
header_size = read_32bitLE(0x04,streamFile);
if (body_size + header_size != get_streamfile_size(streamFile))
goto fail;
loop_flag = 0;
switch (read_8bit(0x09,streamFile))
{
case 0:
if (header_size != 0x20)
goto fail;
coding_type = coding_PCM16BE;
break;
case 1:
if (header_size != 0x80)
goto fail;
coding_type = coding_NGC_DSP;
loop_flag = 1;
break;
default:
goto fail;
}
channel_count = 1;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = header_size;
vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
vgmstream->coding_type = coding_type;
if (coding_NGC_DSP == coding_type)
{
vgmstream->num_samples = dsp_nibbles_to_samples(body_size*2);
if (loop_flag)
{
vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bitBE(0x30,streamFile));
vgmstream->loop_end_sample = dsp_nibbles_to_samples(read_32bitBE(0x34,streamFile));
}
}
else
{
vgmstream->num_samples = body_size / 2;
if (loop_flag)
{
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
}
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_EB_SFX;
vgmstream->allow_dual_stereo = 1;
/* open the file for reading */
{
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
vgmstream->ch[0].streamfile = file;
vgmstream->ch[0].channel_start_offset=
vgmstream->ch[0].offset=start_offset;
if (coding_NGC_DSP == coding_type)
{
int i;
for (i = 0; i < 16; i++)
{
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x3C+i*2,streamFile);
}
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
/* .sf0 - PCM (degenerate stereo .sfx?) */
VGMSTREAM * init_vgmstream_eb_sf0(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
int loop_flag = 0;
int channel_count;
long file_size;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("sf0",filename_extension(filename)))
goto fail;
/* no header, check file size and go on faith */
file_size = get_streamfile_size(streamFile);
if (file_size % 0x8000)
goto fail;
channel_count = 2;
loop_flag = 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->sample_rate = 32000;
vgmstream->num_samples = file_size / 4;
vgmstream->coding_type = coding_PCM16BE;
vgmstream->layout_type = layout_interleave;
vgmstream->meta_type = meta_EB_SF0;
vgmstream->interleave_block_size = 0x4000;
/* open the file for reading by each channel */
{
int i;
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 = vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
/* don't know what to do about .sng and .sn0 */

View file

@ -1,41 +1,45 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/meta_utils.h"
/* EZWAVE - EZ2DJ (Arcade) */
VGMSTREAM * init_vgmstream_ezw(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, data_size;
int loop_flag, channel_count;
/* EZW - from AmuseWorld games [EZ2DJ 5TH (AC)] */
VGMSTREAM* init_vgmstream_ezw(STREAMFILE* sf) {
/* check extension, case insensitive */
if ( !check_extensions(streamFile,"ezw"))
goto fail;
loop_flag = 0;
channel_count = read_8bit(0x0, streamFile);
data_size = read_32bitLE(0xE,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
start_offset = 0x12;
vgmstream->sample_rate = read_32bitLE(0x2,streamFile);
vgmstream->coding_type = coding_PCM16LE;
vgmstream->num_samples = data_size/(channel_count*2);
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x2;
vgmstream->meta_type = meta_EZW;
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
/* checks */
int channels = read_s16le(0x00,sf);
if (channels < 1 || channels > 16) //arbitrary max
return NULL;
// .ezw: EZ2DJ
// .ssf: EZ2AC
if (!check_extensions(sf,"ezw,ssf"))
return NULL;
// no header ID but internally it's referred as the "EZW Format"
// (some early games use regular .wav instead)
meta_header_t h = {0};
h.meta = meta_EZW;
h.channels = read_s16le(0x00, sf);
h.sample_rate = read_s32le(0x02, sf);
// 06: bitrate
h.interleave = read_s16le(0x0A, sf) / channels;
int bps = read_s16le(0x0C, sf);
h.stream_size = read_u32le(0x0E,sf);
if (h.interleave != 0x02)
return NULL;
if (bps != 16)
return NULL;
h.stream_offset = 0x12;
h.num_samples = pcm16_bytes_to_samples(h.stream_size, channels);
h.coding = coding_PCM16LE;
h.layout = layout_interleave;
h.open_stream = true;
h.sf = sf;
return alloc_metastream(&h);
}

View file

@ -620,6 +620,7 @@ static bool parse_fsb(fsb_header_t* fsb, STREAMFILE* sf) {
/* XOR encryption for some FSB4, though the flag is only seen after decrypting */
//;VGM_ASSERT(fsb->flags & FMOD_FSB_SOURCE_ENCRYPTED, "FSB ENCRYPTED found\n");
#ifdef VGM_USE_MPEG
// rare FSB3 have odd cases [Rise of the Argonauts (PC)]
if (fsb->codec == MPEG && fsb->version == FMOD_FSB_VERSION_3_1) {
uint32_t mpeg_id = read_u32be(fsb->stream_offset, sf);
@ -639,6 +640,7 @@ static bool parse_fsb(fsb_header_t* fsb, STREAMFILE* sf) {
// rarely sets more samples than data, must clamp reads to avoid spilling into next subsong: Player_Death_DLG.fsb, Lykas_Atalanta_Join_DLG.fsb
// probably a bug as samples don't seem to match MPEG's 'Info' headers and can be both bigger and smaller than loop_end
}
#endif
return true;
fail:

View file

@ -2,7 +2,7 @@
#include "../coding/coding.h"
#include "../util/endianness.h"
typedef enum { PCM16LE, MSADPCM, XMA2, ATRAC9 } gtd_codec_t;
typedef enum { NONE, PCM16LE, MSADPCM, XMA2, ATRAC9, HEVAG } gtd_codec_t;
static void read_name(VGMSTREAM* vgmstream, STREAMFILE* sf, uint32_t offset);
@ -10,12 +10,11 @@ static void read_name(VGMSTREAM* vgmstream, STREAMFILE* sf, uint32_t offset);
/* GHS - Hexadrive's HexaEngine games [Gunslinger Stratos (AC), Knights Contract (X360), Valhalla Knights 3 (Vita)] */
VGMSTREAM* init_vgmstream_ghs(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
uint32_t stream_offset, stream_size, stpr_offset = 0, loop_start_offset = 0, loop_end_offset = 0;
uint32_t chunk_offset, chunk_size = 0, at9_config_data = 0, block_size = 0;
int loop_flag, channels, sample_rate;
uint32_t stream_offset, stream_size = 0, stpr_offset = 0, loop_start_offset = 0, loop_end_offset = 0;
uint32_t chunk_offset = 0, chunk_size = 0, block_size, at9_config_data = 0;
int loop_flag = 0, channels, sample_rate;
int32_t num_samples, loop_start_sample, loop_end_sample;
gtd_codec_t codec;
int total_subsongs = 0, target_subsong = sf->stream_index;
gtd_codec_t codec = NONE;
/* checks */
@ -28,32 +27,90 @@ VGMSTREAM* init_vgmstream_ghs(STREAMFILE* sf) {
read_u32_t read_u32 = big_endian ? read_u32be : read_u32le;
read_u16_t read_u16 = big_endian ? read_u16be : read_u16le;
int is_old = 0x34 + read_u32le(0x30,sf) + read_u32le(0x0c,sf) == get_streamfile_size(sf);
total_subsongs = read_u32(0x04, sf); /* seen in sfx packs inside .ged */
int target_subsong = sf->stream_index;
int total_subsongs = read_u32(0x04, sf); /* seen in sfx packs inside .ged */
if (!check_subsongs(&target_subsong, total_subsongs))
return NULL;
/* not seen */
if (target_subsong > 1 && is_old)
// header version is not formally specified, use v1 channels as test (v2 has sample rate in that position)
uint32_t version_test = read_u32le(0x10, sf);
bool is_v1 = (version_test < 16);
if (is_v1) {
uint32_t offset = 0x08;
stream_offset = 0x00;
for (int i = 0; i < total_subsongs; i++) {
int format = read_u32(offset + 0x00,sf);
int temp_size = read_u32(offset + 0x04,sf);
if (i + 1 == target_subsong) {
if (format == 0x0000) {
codec = PCM16LE; /* VK3 voices */
block_size = 0x02;
}
else if (format == 0x0001) {
codec = HEVAG; /* VK3 voices */
block_size = 0x10;
}
else if (format == 0x0002) {
codec = ATRAC9; /* VK3 bgm */
block_size = 0;
}
else {
VGM_LOG("GHS: unknown v1 format %x\n", format);
goto fail;
}
stream_size = read_u32(offset + 0x04,sf);
channels = read_u32(offset + 0x08,sf);
sample_rate = read_u32(offset + 0x0c,sf);
// 10: null/bps in PCM?
loop_start_offset = read_u32(offset + 0x14,sf);
loop_end_offset = read_u32(offset + 0x18,sf);
// 1c: channel layout in ATRAC9?
at9_config_data = read_u32be(offset + 0x20,sf);
loop_flag = loop_end_offset > loop_start_offset;
}
offset += 0x24;
if (i + 1 < target_subsong) {
stream_offset += temp_size;
}
}
if (codec == NONE)
goto fail;
/* header version, not formally specified */
if (!is_old) {
/* 0x08: size of all seek tables (XMA2, all tables go together after headers) / null */
stream_offset += offset;
// STPR subheader
if (codec == ATRAC9) {
if (target_subsong > 1) //unknown STPR position for other subsongs
return NULL;
stpr_offset = stream_offset;
stream_offset = read_u32(stpr_offset + 0x04,sf) + 0x34;
}
}
else {
// 0x08: size of all seek tables (XMA2, all tables go together after headers) / null
uint32_t offset = 0x0c + (target_subsong - 1) * 0x64;
int format = read_u16(offset + 0x00,sf);
if (format == 0x0001)
if (format == 0x0001) {
codec = PCM16LE; /* GS bgm */
else if (format == 0x0002)
}
else if (format == 0x0002) {
codec = MSADPCM; /* GS sfx */
}
else if (format == 0x0166) {
codec = XMA2;
chunk_offset = offset; /* "fmt " */
chunk_size = 0x34;
}
else {
VGM_LOG("GHS: unknown v2 format %x\n", format);
goto fail;
}
@ -78,24 +135,6 @@ VGMSTREAM* init_vgmstream_ghs(STREAMFILE* sf) {
stpr_offset = read_u32(offset + 0x54,sf) + read_u32(offset + 0x58,sf);
}
else {
codec = ATRAC9;
/* 08: always 02? */
stream_size = read_u32(0x0c,sf);
channels = read_u32(0x10,sf);
sample_rate = read_u32(0x14,sf);
/* 18: null? */
loop_start_offset = read_u32(0x1c,sf);
loop_end_offset = read_u32(0x20,sf);
/* 24: channel layout? */
at9_config_data = read_u32be(0x28,sf);
/* 2c: STPR */
stream_offset = read_u32(0x30,sf) + 0x34;
loop_flag = loop_end_offset > loop_start_offset;
stpr_offset = 0x2c;
}
/* build the VGMSTREAM */
@ -130,6 +169,15 @@ VGMSTREAM* init_vgmstream_ghs(STREAMFILE* sf) {
break;
case HEVAG:
vgmstream->coding_type = coding_HEVAG;
vgmstream->layout_type = layout_interleave;
vgmstream->frame_size = block_size;
vgmstream->num_samples = ps_bytes_to_samples(stream_size, channels);
break;
#ifdef VGM_USE_FFMPEG
case XMA2:
vgmstream->codec_data = init_ffmpeg_xma_chunk(sf, stream_offset, stream_size, chunk_offset, chunk_size);

View file

@ -14,10 +14,10 @@ VGMSTREAM* init_vgmstream_gsnd(STREAMFILE* sf) {
/* checks */
if (!is_id32be(0x00,sf, "GSND"))
goto fail;
return NULL;
if (!check_extensions(sf,"gsp"))
goto fail;
return NULL;
sb = open_streamfile_by_ext(sf, "gsb");
if (!sb) goto fail;
@ -78,7 +78,7 @@ VGMSTREAM* init_vgmstream_gsnd(STREAMFILE* sf) {
size_t num_blocks;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_blocked_gsb;
vgmstream->layout_type = layout_blocked_gsnd;
if (!find_chunk_be(sf, get_id32be("GCEX"),first_offset,1, &chunk_offset,NULL))
goto fail;

View file

@ -1,6 +1,7 @@
#ifndef _HCA_BF_
#define _HCA_BF_
#include <inttypes.h>
#include "meta.h"
#include "../coding/coding.h"
@ -9,30 +10,37 @@
static void bruteforce_process_result(hca_keytest_t* hk, unsigned long long* p_keycode) {
*p_keycode = hk->best_key;
if (hk->best_score < 0 || hk->best_score > 10000) {
if (hk->best_score <= 0 || hk->best_score > 10000) {
VGM_LOG("HCA BF: no good key found\n");
}
else {
VGM_LOG("HCA BF: best key=%08x%08x (score=%i)\n",
(uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), hk->best_score);
VGM_LOG("HCA BF: best key=%"PRIu64" / %08x%08x (score=%i)\n",
*p_keycode, (uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), hk->best_score);
}
}
const char* hbf_info[] = {
"64LE",
"64BE",
"32LE",
"32BE",
};
typedef enum {
HBF_TYPE_64LE_1,
HBF_TYPE_64BE_1,
HBF_TYPE_32LE_1,
HBF_TYPE_32BE_1,
HBF_TYPE_64LE_4,
HBF_TYPE_64BE_4,
HBF_TYPE_32LE_4,
HBF_TYPE_32BE_4,
} HBF_type_t;
//HBF_TYPE_64LE_4,
//HBF_TYPE_64BE_4,
//HBF_TYPE_32LE_4,
//HBF_TYPE_32BE_4,
} hbf_type_t;
/* Bruteforce binary keys in executables and similar files, mainly for some mobile games.
* Kinda slow but acceptable for ~100MB exes, not very optimized. Unity usually has keys
* in plaintext (inside levelX or other base files) instead though, use test below. */
static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey, HBF_type_t type) {
static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey, hbf_type_t type) {
STREAMFILE* sf_keys = NULL;
uint8_t* buf = NULL;
uint64_t keys_offset;
@ -48,7 +56,8 @@ static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data
sf_keys = open_streamfile_by_filename(sf, "keys.bin");
if (!sf_keys) return;
VGM_LOG("HCA BF: test keys.bin (type %i)\n", type);
const char* type_info = hbf_info[type];
VGM_LOG("HCA BF: using keys.bin (%s mode)\n", type_info);
buf = malloc(HCA_BF_CHUNK);
if (!buf) {
@ -64,10 +73,10 @@ static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data
case HBF_TYPE_64BE_1:
case HBF_TYPE_32LE_1:
case HBF_TYPE_32BE_1: step = 0x01; break;
case HBF_TYPE_64LE_4:
case HBF_TYPE_64BE_4:
case HBF_TYPE_32LE_4:
case HBF_TYPE_32BE_4: step = 0x04; break;
//case HBF_TYPE_64LE_4:
//case HBF_TYPE_64BE_4:
//case HBF_TYPE_32LE_4:
//case HBF_TYPE_32BE_4: step = 0x04; break;
default: goto done;
}
@ -83,7 +92,7 @@ static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data
if (keys_limit >= 8)
keys_offset += keys_limit - 8;
VGM_LOG("HCA: reading %llx + ...\n", (long long)keys_offset);
VGM_LOG("HCA BF: reading %llx + ...\n", (long long)keys_offset);
keys_limit = read_streamfile(buf, keys_offset, HCA_BF_CHUNK, sf_keys);
if (keys_limit == 0)
return;
@ -92,7 +101,7 @@ static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data
if (pos % 0x1000000 == 0) {
uint64_t pos_out = keys_offset + pos;
VGM_LOG("HCA: pos %llx...\n", (long long)pos_out);
VGM_LOG("HCA BF: pos %llx...\n", (long long)pos_out);
}
#ifdef HCA_BF_IGNORE_BAD_KEYS
@ -108,10 +117,10 @@ static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data
case HBF_TYPE_64BE_1: key = get_u64be(buf + pos); break;
case HBF_TYPE_32LE_1: key = get_u32le(buf + pos); break;
case HBF_TYPE_32BE_1: key = get_u32be(buf + pos); break;
case HBF_TYPE_64LE_4: key = get_u64le(buf + pos); break;
case HBF_TYPE_64BE_4: key = get_u64be(buf + pos); break;
case HBF_TYPE_32LE_4: key = get_u32le(buf + pos); break;
case HBF_TYPE_32BE_4: key = get_u32be(buf + pos); break;
//case HBF_TYPE_64LE_4: key = get_u64le(buf + pos); break;
//case HBF_TYPE_64BE_4: key = get_u64be(buf + pos); break;
//case HBF_TYPE_32LE_4: key = get_u32le(buf + pos); break;
//case HBF_TYPE_32BE_4: key = get_u32be(buf + pos); break;
default: goto done;
}
pos += step;
@ -130,13 +139,15 @@ done:
bruteforce_process_result(&hk, p_keycode);
close_streamfile(sf_keys);
free(buf);
VGM_LOG("HCA BF: done\n\n");
}
static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_1);
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_1);
//bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_1);
//bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_1);
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_1);
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_1);
//bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_4);
//bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_4);
@ -145,9 +156,6 @@ static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, uns
}
#include <inttypes.h>
//#include <stdio.h>
/* same as the above but for txt lines. */
static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
STREAMFILE* sf_keys = NULL;
@ -165,7 +173,7 @@ static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, uns
sf_keys = open_streamfile_by_filename(sf, "keys.txt");
if (!sf_keys) return;
VGM_LOG("HCA BF: test keys.txt\n");
VGM_LOG("HCA BF: using keys.txt\n");
keys_size = get_streamfile_size(sf_keys);
@ -192,7 +200,7 @@ static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, uns
count = sscanf(line, "%" SCNd64, &key);
if (count != 1) continue;
VGM_ASSERT(pos % 10000 == 0, "HCA: count %i...\n", i);
VGM_ASSERT(pos % 10000 == 0, "HCA BF: count %i...\n", i);
if (key == 0)
continue;
@ -208,6 +216,8 @@ done:
bruteforce_process_result(&hk, p_keycode);
close_streamfile(sf_keys);
free(buf);
VGM_LOG("HCA BF: done\n\n");
}
/* same as the above but good ol' bruteforce numbers (useful for games with keys that are dates) */
@ -225,7 +235,7 @@ static void bruteforce_hca_key_num(STREAMFILE* sf, hca_codec_data* hca_data, uns
sf_keys = open_streamfile_by_filename(sf, "keys.num");
if (!sf_keys) return;
VGM_LOG("HCA BF: test keys.num\n");
VGM_LOG("HCA BF: using keys.num\n");
keys_size = get_streamfile_size(sf_keys);
@ -245,7 +255,7 @@ static void bruteforce_hca_key_num(STREAMFILE* sf, hca_codec_data* hca_data, uns
key = min;
min++;
VGM_ASSERT(min % 0x100000 == 0, "HCA: count %x...\n", (uint32_t)min);
VGM_ASSERT(min % 0x100000 == 0, "HCA BF: count %x...\n", (uint32_t)min);
hk.key = key;
test_hca_key(hca_data, &hk);
@ -256,9 +266,13 @@ static void bruteforce_hca_key_num(STREAMFILE* sf, hca_codec_data* hca_data, uns
done:
bruteforce_process_result(&hk, p_keycode);
close_streamfile(sf_keys);
VGM_LOG("HCA BF: done\n\n");
}
static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
VGM_LOG("HCA bruteforcer start\n");
bruteforce_hca_key_bin(sf, hca_data, p_keycode, subkey);
if (*p_keycode != 0)
return;
@ -270,6 +284,8 @@ static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigne
bruteforce_hca_key_num(sf, hca_data, p_keycode, subkey);
if (*p_keycode != 0)
return;
VGM_LOG("HCA bruteforcer done\n");
}
#endif

View file

@ -568,6 +568,7 @@ static const hcakey_info hcakey_list[] = {
{0xb58259c9d1f9ebc1}, // music_0310025
{0xbd9e17f5262e3f09}, // music_0310026
{0xba8c9e65cf055de}, // music_0310027
{0xf8cad906044f1b35}, // music_0310028
{0xb921c3992807dadd}, // music_0320001
{0x38ad99a045dc971f}, // music_0320002
{0xf616642579ba5850}, // music_0320003
@ -733,6 +734,7 @@ static const hcakey_info hcakey_list[] = {
{0x1ad8db767d9ba4a7}, // music_0620018
{0x9bc820aa161b0f08}, // music_0620019
{0x7d1d8c5dd43cabfc}, // music_0620020
{0x5a216f2660d870c0}, // music_0620021
{0x6cccc0684c8b2664}, // music_0640001
{0x85f26fa7befc2b5a}, // music_0810000
{0xd1df27a57399613e}, // music_0810001
@ -761,6 +763,7 @@ static const hcakey_info hcakey_list[] = {
{0x6cb33fe1e8506d0f}, // music_0910008
{0xfaf9830ee551c6c4}, // music_0910009
{0xf7c51ef55106e4a0}, // music_0910010
{0xcd35d39900ebaedc}, // music_0910011
{0x4683c57919dbdeee}, // music_0920001
{0x126d0d20ad7f0401}, // music_0920002
{0x1652eb8bf3cea8f5}, // music_0920003
@ -1274,6 +1277,7 @@ static const hcakey_info hcakey_list[] = {
{0x591899d025c3beb7}, // music_5050323
{0xa57678c62ef99124}, // music_5050324
{0x925f360a8ccb4c32}, // music_5050325
{0x2a9281f77161e068}, // music_5050326
{0x52c250eade92393b}, // music_9010001
{0xf66e6bb5b0599b07}, // music_9010002
{0x8582b5a60dbbf948}, // music_9010003

View file

@ -3,37 +3,38 @@
#include "../coding/coding.h"
#include "../util.h"
/* .IAB - from Runtime(?) games [Ueki no Housoku - Taosu ze Robert Juudan!! (PS2), RPG Maker 3 (PS2)] */
VGMSTREAM * init_vgmstream_ps2_iab(STREAMFILE *streamFile) {
/* .IAB - from Runtime(?) games [Ueki no Housoku: Taosu ze Robert Juudan!! (PS2), RPG Maker 3 (PS2)] */
VGMSTREAM* init_vgmstream_iab(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
int loop_flag, channels;
/* checks */
if (!check_extensions(streamFile,"iab"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x10000000)
goto fail;
if (read_32bitLE(0x1C,streamFile) != get_streamfile_size(streamFile))
goto fail;
if (read_u32be(0x00,sf) != 0x10000000)
return NULL;
if (!check_extensions(sf,"iab"))
return NULL;
if (read_u32le(0x1c,sf) != get_streamfile_size(sf))
return NULL;
loop_flag = 0;
channel_count = 2;
channels = 2;
start_offset = 0x40;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
vgmstream->meta_type = meta_PS2_IAB;
vgmstream->meta_type = meta_IAB;
vgmstream->sample_rate = read_s32le(0x04,sf);
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_ps2_iab;
//vgmstream->interleave_block_size = read_32bitLE(0x0C, streamFile); /* unneeded */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
goto fail;
/* calc num_samples */
@ -43,7 +44,7 @@ VGMSTREAM * init_vgmstream_ps2_iab(STREAMFILE *streamFile) {
block_update(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));
while (vgmstream->next_block_offset < get_streamfile_size(sf));
block_update(start_offset, vgmstream);
}

View file

@ -5,6 +5,8 @@ typedef struct {
int loop_flag;
int32_t loop_start;
int32_t loop_end;
uint16_t loop_start_adjust;
uint16_t loop_end_padding;
uint32_t file_size;
#ifdef VGM_USE_FFMPEG
mp4_custom_t mp4;
@ -23,50 +25,68 @@ VGMSTREAM* init_vgmstream_ktac(STREAMFILE* sf) {
if (!is_id32be(0x00,sf, "KTAC"))
return NULL;
/* .ktac: header id (probable extension from debug strings is "kac" */
// .ktac: header id (probable extension from debug strings is "kac"
if (!check_extensions(sf,"ktac"))
return NULL;
/* 0x04: version? (always 1) */
// 0x04: version? (0x01000000=common, 0x01010000=WP9 2022)
ktac.file_size = read_u32le(0x08,sf);
if (ktac.file_size != get_streamfile_size(sf))
return NULL;
ktac.mp4.stream_offset = read_u32le(0x0c,sf);
ktac.mp4.stream_size = read_u32le(0x10,sf);
ktac.type = read_u32le(0x14,sf);
ktac.type = read_u32le(0x14,sf); // 0=AoT, KnC3 bgm, type 1=KnC3 1ch voices, type 2=DW4, Atelier Ryza, others
ktac.mp4.sample_rate = read_u32le(0x18,sf);
ktac.mp4.num_samples = read_u32le(0x1c,sf); /* full samples */
ktac.mp4.num_samples = read_u32le(0x1c,sf); // full samples (total_frames * frame_size)
ktac.mp4.channels = read_u16le(0x20,sf);
ktac.mp4.frame_samples = read_u16le(0x22,sf);
ktac.mp4.encoder_delay = read_u16le(0x24,sf);
ktac.mp4.end_padding = read_u16le(0x26,sf);
ktac.loop_start = read_u32le(0x28,sf);
ktac.loop_end = read_u32le(0x2c,sf);
/* 0x30: ? (big, related to loops) */
/* 0x34: ? (always null) */
ktac.loop_start_adjust = read_u16le(0x30,sf);
ktac.loop_end_padding = read_u16le(0x32,sf); // usually same as end_padding
// 0x34: reserved? (always null)
ktac.mp4.table_offset = read_u32le(0x38,sf);
ktac.mp4.table_entries = read_u32le(0x3c,sf);
ktac.mp4.table_entries = read_u32le(0x3c,sf); // total_frames
ktac.loop_flag = (ktac.loop_end > 0);
/* type 1 files crash during sample_copy, wrong fake header/esds?
* (0=AoT, KnC3 bgm, 1=KnC3 1ch voices, 2=DW4, Atelier Ryza) */
if (ktac.type == 1)
// loop handling, correct vs full loops too [Winning Post 9 2022 (PC)]
// - loop_start == 1 = 2048 + adjust 64 == 2112 == encoder delay
// - (loop_end + 1) == total_frames, loop_end_adjust = 96 = end_padding
ktac.loop_start = ktac.loop_start * ktac.mp4.frame_samples + ktac.loop_start_adjust;
ktac.loop_end = (ktac.loop_end + 1) * ktac.mp4.frame_samples - ktac.loop_end_padding;
int channels = ktac.mp4.channels;
int sample_rate = ktac.mp4.sample_rate;
int num_samples = ktac.mp4.num_samples;
// type 1 has some odd behavior. FFmpeg returns 2 channels with dupe samples (must decode x2),
// Possibly fake mp4's add_esds config is off, but internal sample_rate/etc seems correct (matters for decoding).
// It's not impossible it's just some KT decoder trickery, so for now force double values.
if (ktac.type == 1) {
vgm_logi("KTAC: type %i found\n", ktac.type);
if (channels != 1)
goto fail;
channels *= 2; //could use 1 channel + let copy-samples ignore extra channel?
sample_rate *= 2;
num_samples *= 2;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(ktac.mp4.channels, ktac.loop_flag);
vgmstream = allocate_vgmstream(channels, ktac.loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_KTAC;
vgmstream->sample_rate = ktac.mp4.sample_rate;
vgmstream->num_samples = ktac.mp4.num_samples - ktac.mp4.encoder_delay - ktac.mp4.end_padding;
vgmstream->loop_start_sample = ktac.loop_start * ktac.mp4.frame_samples - ktac.mp4.encoder_delay;
vgmstream->loop_end_sample = ktac.loop_end * ktac.mp4.frame_samples - ktac.mp4.encoder_delay;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples - ktac.mp4.end_padding - ktac.mp4.encoder_delay;
vgmstream->loop_start_sample = ktac.loop_start - ktac.mp4.encoder_delay;
vgmstream->loop_end_sample = ktac.loop_end - ktac.mp4.encoder_delay;
/* KTAC uses AAC, but not type found in .aac (that has headered frames, like mp3) but raw
* packets + frame size table (similar to .mp4/m4a). We set config for FFmpeg's fake M4A header */
vgmstream->codec_data = init_ffmpeg_mp4_custom_std(sf, &ktac.mp4);
// KTAC uses AAC, but not type found in .aac (that has headered frames, like mp3) but raw
// packets + frame size table (similar to .mp4/m4a). We set config for FFmpeg's fake M4A header
vgmstream->codec_data = init_ffmpeg_mp4_custom_ktac(sf, &ktac.mp4);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;

View file

@ -0,0 +1,49 @@
#include "meta.h"
#include "../util/meta_utils.h"
#include "../coding/coding.h"
/* .LPS - from Rave Master (GC) */
VGMSTREAM* init_vgmstream_lps(STREAMFILE* sf) {
/* checks */
uint32_t data_size = read_u32be(0x00, sf);
if (data_size + 0xE0 != get_streamfile_size(sf))
return NULL;
if (read_u32be(0x04, sf) != 0x01)
return NULL;
if (read_u32be(0x08, sf) != 0x10000000)
return NULL;
if (read_u32be(0x0c, sf) != 0x00)
return NULL;
if (!check_extensions(sf, "lps"))
return NULL;
meta_header_t h = {0};
h.meta = meta_LPS;
//TODO: standard(?) DSP header, maybe handle like others
h.num_samples = read_s32be(0x20 + 0x00,sf);
// 04: nibbles
h.sample_rate = read_s32be(0x20 + 0x08,sf);
h.loop_flag = read_s16be(0x20 + 0x0c,sf) == 0x0001;
h.loop_start = read_u32be(0x20 + 0x10,sf);
h.loop_end = read_s32be(0x20 + 0x14,sf);
h.coefs_offset = 0x20 + 0x1c;
h.hists_offset = 0x20 + 0x1c + 0x20 + 0x04;
h.loop_start = dsp_nibbles_to_samples(h.loop_start);
h.loop_end = dsp_nibbles_to_samples(h.loop_end); //+ 1;
h.channels = 1;
h.allow_dual_stereo = true;
h.big_endian = true;
h.stream_offset = 0xE0;
h.coding = coding_NGC_DSP;
h.layout = layout_none;
h.open_stream = true;
h.sf = sf;
return alloc_metastream(&h);
}

View file

@ -0,0 +1,70 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/meta_utils.h"
/* MADP - from Capcom 3DS games */
VGMSTREAM* init_vgmstream_madp(STREAMFILE* sf) {
/* checks */
if (!is_id32be(0x00,sf, "MADP"))
return NULL;
if (!check_extensions(sf, "mca"))
return NULL;
meta_header_t h = {0};
h.meta = meta_MADP;
int version = read_u16le(0x04, sf);
h.channels = read_u16le(0x08, sf);
h.interleave = read_u16le(0x0a, sf); // assumed, only seen 0x100
h.num_samples = read_s32le(0x0c, sf);
h.sample_rate = read_s32le(0x10, sf);
h.loop_start = read_s32le(0x14, sf);
h.loop_end = read_s32le(0x18, sf);
h.head_size = read_u32le(0x1c, sf); // v3=loop related?, v5=partial size?
h.stream_size = read_u32le(0x20, sf);
// 24: duration (f32)
// rest: varies between versions
int cues = 0;
if (version >= 0x04) {
cues = read_u16le(0x28, sf); //seems to be some kind of seek table with start ps + hist per channel
// 0x2a: id-ish value? (same for all files in a game)
}
// format is kind of inconsistent between games but the following seems to work
if (version == 3)
h.head_size = get_streamfile_size(sf) - h.stream_size; // probably 0x2c + 0x30*ch
h.coefs_spacing = 0x30;
uint32_t coefs_start = (h.head_size - h.coefs_spacing * h.channels);
h.coefs_offset = coefs_start + cues * 0x14;
// hist + start/loop ps seem to follow after coefs
switch(version) {
case 0x03: // Resident Evil Mercenaries 3D, Super Street Fighter IV 3D
h.stream_offset = h.head_size;
break;
case 0x04: // EX Troopers, Ace Attourney 5
h.stream_offset = get_streamfile_size(sf) - h.stream_size; // usually head_size but not for some MH3U songs
break;
case 0x05: // Ace Attourney 6, Monster Hunter Generations
h.stream_offset = read_u32le(coefs_start - 0x04, sf);
break;
default:
return NULL;
}
h.loop_flag = h.loop_end > 0;
if (h.loop_end > h.num_samples) // some MH3U songs, somehow
h.loop_end = h.num_samples;
h.coding = coding_NGC_DSP;
h.layout = layout_interleave;
h.open_stream = true;
h.sf = sf;
return alloc_metastream(&h);
}

View file

@ -1,95 +0,0 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
/* Capcom MADP - found in Capcom 3DS games */
VGMSTREAM * init_vgmstream_mca(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int channel_count, loop_flag, version;
size_t head_size, data_size, file_size;
off_t start_offset, coef_offset, coef_start, coef_shift;
int coef_spacing;
/* check extension, case insensitive */
if (!check_extensions(streamFile,"mca"))
goto fail;
/* check header */
if ((uint32_t)read_32bitBE(0, streamFile) != 0x4D414450) /* "MADP" */
goto fail;
channel_count = read_8bit(0x8, streamFile);
if (channel_count < 1) goto fail;
loop_flag = read_32bitLE(0x18, streamFile) > 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->interleave_block_size = read_16bitLE(0xa, streamFile); /* guessed, only seen 0x100 */
vgmstream->num_samples = read_32bitLE(0xc, streamFile);
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x10, streamFile);
vgmstream->loop_start_sample = read_32bitLE(0x14, streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x18, streamFile);
if (vgmstream->loop_end_sample > vgmstream->num_samples) /* some MH3U songs, somehow */
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
vgmstream->meta_type = meta_MCA;
/* find data/coef offsets (guessed, formula may change with version) */
version = read_16bitLE(0x04, streamFile);
coef_spacing = 0x30;
data_size = read_32bitLE(0x20, streamFile);
if (version <= 0x3) { /* v3: Resident Evil Mercenaries 3D, Super Street Fighter IV 3D */
head_size = get_streamfile_size(streamFile) - data_size; /* probably 0x2c + 0x30*ch */
coef_shift = 0x0;
coef_start = head_size - coef_spacing * channel_count;
start_offset = head_size;
coef_offset = coef_start + coef_shift * 0x14;
} else if (version == 0x4) { /* v4: EX Troopers, Ace Attourney 5 */
head_size = read_16bitLE(0x1c, streamFile);
coef_shift = read_16bitLE(0x28, streamFile);
coef_start = head_size - coef_spacing * channel_count;
start_offset = get_streamfile_size(streamFile) - data_size; /* usually head_size but not for some MH3U songs */
coef_offset = coef_start + coef_shift * 0x14;
} else { /* v5: Ace Attourney 6, Monster Hunter Generations, v6+? */
head_size = read_16bitLE(0x1c, streamFile); /* partial size */
coef_shift = read_16bitLE(0x28, streamFile);
coef_start = head_size - coef_spacing * channel_count;
start_offset = read_32bitLE(coef_start - 0x4, streamFile);
coef_offset = coef_start + coef_shift * 0x14;
}
/* sanity check (for bad rips with the header manually truncated to in attempt to "fix" v5 headers) */
file_size = get_streamfile_size(streamFile);
if (start_offset + data_size > file_size) {
if (head_size + data_size > file_size)
goto fail;
start_offset = file_size - data_size;
}
/* set up ADPCM coefs */
dsp_read_coefs_le(vgmstream, streamFile, coef_offset, coef_spacing);
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream,streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -0,0 +1,65 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
/* Guerrilla's MSS - Found in ShellShock Nam '67 (PS2/Xbox), Killzone (PS2) */
VGMSTREAM* init_vgmstream_mcss(STREAMFILE *sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset, data_size;
int loop_flag = 0, channels;
/* checks */
if (!is_id32be(0x00,sf, "MCSS"))
return NULL;
if (!check_extensions(sf, "mss"))
return NULL;
loop_flag = 0;
// 04: version? (always 0x00000100 LE)
start_offset = read_u32le(0x08,sf);
data_size = read_u32le(0x0c,sf);
int sample_rate = read_s32le(0x10,sf);
// 14(1): 1/2/3/4 if 2/4/6/8ch
// 15(1): 0/1?
channels = read_u16le(0x16,sf);
int interleave = read_u32le(0x18,sf);
uint32_t chan_size = read_u32le(0x1C,sf); //without padding
// 20: "Guerrilla MSS"
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_MCSS;
vgmstream->sample_rate = sample_rate;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
// no other way to know
if (vgmstream->interleave_block_size == 0x4800) {
vgmstream->coding_type = coding_XBOX_IMA;
/* in stereo multichannel this value is distance between 2ch pair, but we need
* interleave*ch = full block (2ch 0x4800 + 2ch 0x4800 = 4ch, 0x4800+4800 / 4 = 0x2400) */
vgmstream->interleave_block_size = vgmstream->interleave_block_size / 2;
if (vgmstream->channels > 2 && vgmstream->channels % 2 != 0)
goto fail; // only 2ch+..+2ch layout is known
/* header values are somehow off? */
data_size = get_streamfile_size(sf) - start_offset;
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, vgmstream->channels);
}
else {
// 0x800 interleave
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = ps_bytes_to_samples(chan_size, 1);
}
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -275,8 +275,6 @@ VGMSTREAM * init_vgmstream_sat_sap(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_dc_idvi(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ps2_rnd(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_kraw(STREAMFILE *streamFile);
VGMSTREAM* init_vgmstream_omu(STREAMFILE* sf);
@ -334,7 +332,8 @@ VGMSTREAM* init_vgmstream_ssm(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_vgs(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_vgs(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_vgs_old(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_dcs_wav(STREAMFILE * streamFile);
@ -348,11 +347,11 @@ VGMSTREAM* init_vgmstream_p2bt_move_visa(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_gbts(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_wii_sng(STREAMFILE *streamFile);
VGMSTREAM* init_vgmstream_song_monster(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ngc_ffcc_str(STREAMFILE *streamFile);
VGMSTREAM* init_vgmstream_str_sqex(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_sat_baka(STREAMFILE *streamFile);
@ -378,7 +377,7 @@ VGMSTREAM * init_vgmstream_ps2_sps(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_nds_hwas(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ngc_lps(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_lps(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ps2_snd(STREAMFILE * streamFile);
@ -390,7 +389,7 @@ VGMSTREAM * init_vgmstream_2dx9(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_dsp_kceje(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ps2_vgv(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_vgv(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_gcub(STREAMFILE * streamFile);
@ -463,7 +462,7 @@ VGMSTREAM* init_vgmstream_cps(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ngc_nst_dsp(STREAMFILE* streamFile);
VGMSTREAM* init_vgmstream_nst_monster(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_baf(STREAMFILE* streamFile);
@ -477,7 +476,7 @@ VGMSTREAM* init_vgmstream_ras(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_spm(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_iab(STREAMFILE* streamFile);
VGMSTREAM* init_vgmstream_iab(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_vs_str(STREAMFILE* streamFile);
@ -496,8 +495,8 @@ VGMSTREAM* init_vgmstream_adp_wildfire(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_adp_qd(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_eb_sfx(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_eb_sf0(STREAMFILE* streamFile);
VGMSTREAM* init_vgmstream_sfx0_monster(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_sfx0_monster_old(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_mtaf(STREAMFILE* streamFile);
@ -507,7 +506,7 @@ VGMSTREAM * init_vgmstream_wpd(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_mn_str(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_mss(STREAMFILE* streamFile);
VGMSTREAM* init_vgmstream_mcss(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ps2_hsf(STREAMFILE* streamFile);
@ -534,7 +533,7 @@ VGMSTREAM * init_vgmstream_kt_g1l(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_kt_wiibgm(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ktss(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_mca(STREAMFILE* streamFile);
VGMSTREAM* init_vgmstream_madp(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_btsnd(STREAMFILE* streamFile);
@ -620,7 +619,7 @@ VGMSTREAM* init_vgmstream_opus_nsopus(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_opus_sqex(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_opus_rsnd(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_pc_ast(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_astl(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_naac(STREAMFILE * streamFile);
@ -759,7 +758,7 @@ VGMSTREAM * init_vgmstream_apc(STREAMFILE *streamFile);
VGMSTREAM* init_vgmstream_wav2(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_xau_konami(STREAMFILE *streamFile);
VGMSTREAM* init_vgmstream_sfxb(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_derf(STREAMFILE *streamFile);
@ -998,7 +997,7 @@ VGMSTREAM* init_vgmstream_nxof(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_gwb_gwd(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_cbx(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_chatterbox(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_vas_rockstar(STREAMFILE* sf);
@ -1034,4 +1033,6 @@ VGMSTREAM* init_vgmstream_mio(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_2dx(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ssp(STREAMFILE* sf);
#endif

View file

@ -1,68 +0,0 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
/* Guerrilla's MSS - Found in ShellShock Nam '67 (PS2/Xbox), Killzone (PS2) */
VGMSTREAM * init_vgmstream_mss(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
size_t data_size;
int loop_flag = 0, channel_count;
/* checks */
if (!check_extensions(streamFile, "mss"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4D435353) /* "MCSS" */
goto fail;
loop_flag = 0;
channel_count = read_16bitLE(0x16,streamFile);
/* 0x04: version? (always 0x00000100 LE) */
start_offset = read_32bitLE(0x08,streamFile);
data_size = read_32bitLE(0x0c,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
/* 0x14(1): 1/2/3/4 if 2/4/6/8ch, 0x15(1): 0/1?, 0x16: ch */
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitLE(0x18,streamFile);
vgmstream->num_samples = read_32bitLE(0x1C,streamFile);
vgmstream->meta_type = meta_MSS;
/* no other way to know */
if (vgmstream->interleave_block_size == 0x4800) {
vgmstream->coding_type = coding_XBOX_IMA;
/* in stereo multichannel this value is distance between 2ch pair, but we need
* interleave*ch = full block (2ch 0x4800 + 2ch 0x4800 = 4ch, 0x4800+4800 / 4 = 0x2400) */
vgmstream->interleave_block_size = vgmstream->interleave_block_size / 2;
if (vgmstream->channels > 2 && vgmstream->channels % 2 != 0)
goto fail; /* only 2ch+..+2ch layout is known */
/* header values are somehow off? */
data_size = get_streamfile_size(streamFile) - start_offset;
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, vgmstream->channels);
}
else {
/* 0x800 interleave */
vgmstream->coding_type = coding_PSX;
if (vgmstream->num_samples * vgmstream->channels <= data_size)
vgmstream->num_samples = vgmstream->num_samples / 16 * 28;
}
/* open the file for reading */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1,85 +0,0 @@
#include "meta.h"
#include "../util.h"
/* STR (Final Fantasy: Crystal Chronicles) */
VGMSTREAM * init_vgmstream_ngc_ffcc_str(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("str",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x53545200 || /* "STR\0" */
read_32bitBE(0x08,streamFile) != get_streamfile_size(streamFile) ||
read_32bitBE(0x10,streamFile) != -1) /* this might be loop point */
goto fail;
loop_flag = 0;
channel_count = read_32bitBE(0x18,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x1000;
vgmstream->channels = channel_count;
if (read_32bitBE(0x14,streamFile)==0)
vgmstream->sample_rate = 32000;
else
vgmstream->sample_rate = 44100;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->num_samples = read_32bitBE(0x0C,streamFile)*14;
if (channel_count > 1)
{
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x1000;
}
else
{
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = 0x1000;
}
vgmstream->meta_type = meta_FFCC_STR;
if (vgmstream->coding_type == coding_NGC_DSP) {
int c;
for (c=0;c<channel_count;c++)
{
int i;
for (i=0;i<16;i++) {
vgmstream->ch[c].adpcm_coef[i] = read_16bitBE(0x20 + c * 0x2e + 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;i<channel_count;i++) {
vgmstream->ch[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;
}

View file

@ -1,70 +0,0 @@
#include "meta.h"
#include "../util.h"
/* LPS (found in Rave Master (Groove Adventure Rave)(GC) */
VGMSTREAM * init_vgmstream_ngc_lps(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("lps",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x8,streamFile) != 0x10000000)
goto fail;
loop_flag = read_32bitBE(0x30,streamFile);
channel_count = 1;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x60;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x28,streamFile);
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->num_samples = (read_32bitBE(0x34,streamFile))/16*14;
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitBE(0x30,streamFile))/16*14;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_NGC_LPS;
vgmstream->allow_dual_stereo = 1;
if (vgmstream->coding_type == coding_NGC_DSP) {
int i;
for (i=0;i<16;i++) {
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x3C+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;i<channel_count;i++) {
vgmstream->ch[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;
}

View file

@ -1,89 +0,0 @@
#include "meta.h"
#include "../util.h"
/* DSP (Animaniacs: The Great Edgar Hunt) */
// NOTE: The second dsp header is just a dummy, both channels
// use the same coef table (0x20)
VGMSTREAM * init_vgmstream_ngc_nst_dsp(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("dsp",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x0,streamFile) != read_32bitBE(0x54,streamFile))
goto fail;
if (read_32bitBE(0x4,streamFile) != read_32bitBE(0x58,streamFile))
goto fail;
if (read_32bitBE(0x8,streamFile) != read_32bitBE(0x5C,streamFile))
goto fail;
if (read_32bitBE(0xC,streamFile) != read_32bitBE(0x60,streamFile))
goto fail;
loop_flag = 0;
channel_count = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0xAC;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x14,streamFile);
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->num_samples = read_32bitBE(0x8,streamFile);
#if 0
if (loop_flag) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = 0;
}
#endif
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
vgmstream->meta_type = meta_NGC_NST_DSP;
if (vgmstream->coding_type == coding_NGC_DSP) {
int i;
for (i=0;i<16;i++) {
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x20+i*2,streamFile);
}
if (vgmstream->channels) {
for (i=0;i<16;i++) {
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x20+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;i<channel_count;i++) {
vgmstream->ch[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;
}

View file

@ -0,0 +1,48 @@
#include "meta.h"
#include "../util/meta_utils.h"
#include "../coding/coding.h"
/* .NST - from Animaniacs: The Great Edgar Hunt (GC) */
VGMSTREAM* init_vgmstream_nst_monster(STREAMFILE* sf) {
/* checks */
if (read_u32be(0x00,sf) != 1)
return NULL;
// .nst: original
// .dsp: renamed for plugins (to be removed?)
if (!check_extensions(sf, "nst,dsp"))
return NULL;
// DSP header but second is just a dummy, both channels use the same coef table (0x20)
if (read_u32be(0x00,sf) != read_u32be(0x54,sf))
return NULL;
if (read_u32be(0x04,sf) != read_u32be(0x58,sf))
return NULL;
if (read_u32be(0x08,sf) != read_u32be(0x5C,sf))
return NULL;
if (read_u32be(0x0C,sf) != read_u32be(0x60,sf))
return NULL;
meta_header_t h = {0};
h.meta = meta_NST_MONSTER;
h.num_samples = read_s32be(0x08, sf);
h.sample_rate = read_s32be(0x14, sf);
h.channels = 2;
h.interleave = 0x10;
h.coefs_offset = 0x20;
h.coefs_spacing = 0x00;
h.big_endian = true;
//h.hists_offset = 0x00; //?
//h.hists_spacing = h.coefs_spacing;
h.stream_offset = 0xAC;
h.coding = coding_NGC_DSP;
h.layout = layout_interleave;
h.open_stream = true;
h.sf = sf;
return alloc_metastream(&h);
}

View file

@ -8,7 +8,6 @@ static bool is_oor(STREAMFILE* sf);
/* .OOR ("OptimizedObsforR") - rUGP/AGES engine audio [Muv-Luv (multi), Liberation Maiden SIN (PS3/Vita)] */
VGMSTREAM* init_vgmstream_oor(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
vorbis_custom_codec_data* data = NULL;
off_t start_offset;
@ -23,6 +22,7 @@ VGMSTREAM* init_vgmstream_oor(STREAMFILE* sf) {
return NULL;
#ifdef VGM_USE_VORBIS
vorbis_custom_codec_data* data = NULL;
vorbis_custom_config cfg = {0}; //loads info on success
data = init_vorbis_custom(sf, 0x00, VORBIS_OOR, &cfg);
@ -50,15 +50,15 @@ VGMSTREAM* init_vgmstream_oor(STREAMFILE* sf) {
// v0 files don't set last granule (must be done after opening streamfiles)
if (!cfg.last_granule)
vgmstream->num_samples = vorbis_custom_get_samples(vgmstream);
#else
goto fail;
#endif
return vgmstream;
fail:
free_vorbis_custom(data);
close_vgmstream(vgmstream);
return NULL;
#else
return NULL;
#endif
}
// OOR is bitpacked but try to determine if bytes look like a .oor (will fail later if we picked a wrong candidate).

View file

@ -136,8 +136,9 @@ VGMSTREAM* init_vgmstream_opus_std(STREAMFILE* sf) {
/* .opus: standard / .lopus: for plugins
* .bgm: Cotton Reboot (Switch)
* .opu: Ys Memoire: The Oath in Felghana (Switch)
* .ogg: Trouble Witches Origin (Switch) */
if (!check_extensions(sf,"opus,lopus,bgm,opu,ogg,logg"))
* .ogg: Trouble Witches Origin (Switch)
* .opusnx: Sweet Café Collection (Switch) */
if (!check_extensions(sf,"opus,lopus,bgm,opu,ogg,logg,opusnx"))
goto fail;
offset = 0x00;

View file

@ -1,44 +0,0 @@
#include "meta.h"
#include "../coding/coding.h"
/* ASTL - found in Dead Rising (PC) */
VGMSTREAM * init_vgmstream_pc_ast(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, data_size;
int loop_flag, channel_count;
/* check extension, case insensitive */
if ( !check_extensions(streamFile,"ast"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4153544C) /* "ASTL" */
goto fail;
loop_flag = 0; //TODO - Find hidden loop point calc and flag
channel_count = read_8bit(0x32, streamFile);
data_size = read_32bitLE(0x20,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* TODO - Find non-obvious loop points and flag (if any) */
start_offset = read_32bitLE(0x10,streamFile);
vgmstream->sample_rate = read_32bitLE(0x34,streamFile);
vgmstream->coding_type = coding_PCM16LE;
vgmstream->num_samples = data_size/(channel_count*2);
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x2;
vgmstream->meta_type = meta_PC_AST;
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1,56 +0,0 @@
#include "meta.h"
#include "../util.h"
/* rnd (from Karaoke Revolution) */
VGMSTREAM * init_vgmstream_ps2_rnd(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("rnd",filename_extension(filename))) goto fail;
loop_flag = 0;
channel_count = read_32bitLE(0x00,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x10;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = (get_streamfile_size(streamFile)-0x10)/16*28/vgmstream->channels;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x2000;
vgmstream->meta_type = meta_HGC1;
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[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;
}

View file

@ -1,64 +0,0 @@
#include "meta.h"
#include "../util.h"
/* VGV (from Rune: Viking Warlord) */
VGMSTREAM * init_vgmstream_ps2_vgv(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("vgv",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x08,streamFile) != 0x0)
goto fail;
if (read_32bitBE(0x0C,streamFile) != 0x0)
goto fail;
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 = 0x10;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x0,streamFile);
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = (get_streamfile_size(streamFile))*28/16/channel_count;
if (loop_flag) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)*28/16/channel_count;
}
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_PS2_VGV;
/* 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; //+vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View file

@ -185,7 +185,7 @@ typedef struct {
bool is_at9;
} riff_fmt_chunk;
static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk* fmt) {
static bool read_fmt(bool big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk* fmt) {
uint32_t (*read_u32)(off_t,STREAMFILE*) = big_endian ? read_u32be : read_u32le;
uint16_t (*read_u16)(off_t,STREAMFILE*) = big_endian ? read_u16be : read_u16le;
@ -235,19 +235,19 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk
case 0x0001: /* PCM */
switch (fmt->bps) {
case 32:
case 32: /* Get Off My Lawn! (PC) */
fmt->coding_type = coding_PCM32LE;
break;
case 24: /* Omori (PC) */
case 24: /* Tinertia (PC), Beatbuddy (WiiU) */
fmt->coding_type = coding_PCM24LE;
break;
case 16:
case 16: /* common */
fmt->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
/* broken block size [Rayman 2 (DC)] */
if (fmt->block_size == 0x02 && fmt->channels > 1)
fmt->block_size = 0x02 * fmt->channels;
break;
case 8:
case 8: /* The Lost Vikings 2 (PC), Phoenix Wright: Ace Attorney (iOS) */
fmt->coding_type = coding_PCM8_U;
break;
default:
@ -256,7 +256,7 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk
fmt->interleave = fmt->block_size / fmt->channels;
break;
case 0x0002: /* MSADPCM */
case 0x0002: /* MSADPCM [Descent: Freespace (PC)] */
if (fmt->bps == 4) {
/* ADPCMWAVEFORMAT extra data:
* - samples per frame (16b)
@ -273,10 +273,12 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk
goto fail;
}
break;
case 0x0003: /* floating point PCM */
case 0x0003: /* floating point PCM [Cube World (PC), SphereZor (WiiU)] */
if (fmt->bps == 32) {
fmt->coding_type = coding_PCMFLOAT;
} else {
}
else {
goto fail;
}
fmt->interleave = fmt->block_size / fmt->channels;
@ -407,10 +409,10 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk
goto fail;
}
return 1;
return true;
fail:
return 0;
return false;
}
static bool is_ue4_msadpcm(STREAMFILE* sf, riff_fmt_chunk* fmt, int fact_sample_count, off_t start_offset, uint32_t data_size);
@ -481,8 +483,9 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
* .voi: Sol Trigger (PSP)[ATRAC3]
* .se: Rockman X4 (PC)
* .v: Rozen Maiden: Duellwalzer (PS2)
* .xst: Animaniacs: The Great Edgar Hunt (Xbox)
*/
if (!check_extensions(sf, "wav,lwav,xwav,mwv,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv,wvx,str,at3,rws,aud,at9,ckd,saf,ima,nsa,pcm,xvag,ogg,logg,p1d,xms,mus,dat,ldat,wma,lwma,caf,wax,voi,se,v")) {
if (!check_extensions(sf, "wav,lwav,xwav,mwv,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv,wvx,str,at3,rws,aud,at9,ckd,saf,ima,nsa,pcm,xvag,ogg,logg,p1d,xms,mus,dat,ldat,wma,lwma,caf,wax,voi,se,v,xst")) {
return NULL;
}
@ -589,7 +592,7 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
goto fail; /* only one per file */
fmt_chunk_found = true;
if (!read_fmt(0, sf, current_chunk, &fmt))
if (!read_fmt(false, sf, current_chunk, &fmt))
goto fail;
/* some Dreamcast/Naomi games again [Headhunter (DC), Bomber hehhe (DC), Rayman 2 (DC)] */
@ -1291,7 +1294,7 @@ VGMSTREAM* init_vgmstream_rifx(STREAMFILE* sf) {
if (FormatChunkFound) goto fail;
FormatChunkFound = 1;
if (!read_fmt(1, sf, current_chunk, &fmt))
if (!read_fmt(true, sf, current_chunk, &fmt))
goto fail;
break;

View file

@ -1,64 +1,64 @@
#include "meta.h"
#include "../coding/coding.h"
/* SD9 - from Konami arcade games [beatmania IIDX series (AC), BeatStream (AC)] */
VGMSTREAM * init_vgmstream_sd9(STREAMFILE *streamFile) {
VGMSTREAM* init_vgmstream_sd9(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
int loop_flag, channels;
/* checks */
if (!check_extensions(streamFile, "sd9"))
goto fail;
if (!is_id32be(0x00, sf, "SD9\0"))
return NULL;
// .sd9: header ID
if (!check_extensions(sf, "sd9"))
return NULL;
if (read_32bitBE(0x0, streamFile) != 0x53443900) /* SD9 */
goto fail;
if (read_32bitBE(0x20, streamFile) != 0x52494646) /* RIFF */
goto fail;
if (read_32bitBE(0x28, streamFile) != 0x57415645) /* WAVE */
goto fail;
if (read_32bitBE(0x2c, streamFile) != 0x666D7420) /* fmt */
goto fail;
if (read_32bitBE(0x72, streamFile) != 0x64617461) /* data */
goto fail;
// 04: header size
// 08: data size
// 0c: 0x3231?
int loop_count = read_s16le(0x0e,sf); //-1 or N;
uint32_t loop_start = read_u32le(0x14, sf);
uint32_t loop_end = read_u32le(0x18, sf);
// 1c: loop flag? (1=loop_end defined)
// 1e: category id?
/* Some SD9s may loop without any loop points specificed.
If loop_flag is set with no points, loop entire song. */
// Some SD9s sets count > 0 without any loop points specificed, loop entire song.
// However can't tell apart from songs that shouldn't do full loops. (ex. IIDX 16 sys_sound.ssp #3 vs #26).
// In IIDX 21 loop count < 0 w/ loops exist; in other cases count < 0 usually has no loops defined.
loop_flag = (loop_count > 0) || (loop_count < 0 && loop_end);
loop_flag = read_16bitLE(0x0e,streamFile);
//loop_flag = read_32bitLE(0x18, streamFile); // use loop end
channel_count = read_16bitLE(0x36, streamFile);
// regular RIFF header with fmt + fact + data
if (!is_id32be(0x20, sf, "RIFF"))
return NULL;
if (!is_id32be(0x28, sf, "WAVE"))
return NULL;
if (!is_id32be(0x2c, sf, "fmt "))
return NULL;
channels = read_u16le(0x36, sf);
start_offset = 0x7a;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(0x38, streamFile);
vgmstream->num_samples = read_32bitLE(0x6e, streamFile);
if (loop_flag > 0) {
vgmstream->loop_start_sample = read_32bitLE(0x14, streamFile) / 2 / channel_count;
vgmstream->loop_end_sample = read_32bitLE(0x18, streamFile) / 2 / channel_count;
if (vgmstream->loop_end_sample == 0) {
vgmstream->meta_type = meta_SD9;
vgmstream->sample_rate = read_s32le(0x38, sf);
vgmstream->num_samples = read_s32le(0x6e, sf);
vgmstream->loop_start_sample = pcm16_bytes_to_samples(loop_start, channels);
vgmstream->loop_end_sample = pcm16_bytes_to_samples(loop_end, channels);
if (vgmstream->loop_end_sample == 0)
vgmstream->loop_end_sample = vgmstream->num_samples;
}
}
/* beatmania IIDX 21: Spada is a special case. Loop flag is false but loops exist.
Konami, Why? */
if ((loop_flag < 0) && (read_32bitLE(0x18, streamFile) !=0)) {
vgmstream->loop_start_sample = read_32bitLE(0x14, streamFile) / 2 / channel_count;
vgmstream->loop_end_sample = read_32bitLE(0x18, streamFile) / 2 / channel_count;
}
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->frame_size = read_16bitLE(0x40, streamFile);
vgmstream->meta_type = meta_SD9;
if (!msadpcm_check_coefs(streamFile, 0x48))
vgmstream->frame_size = read_u16le(0x40, sf);
if (!msadpcm_check_coefs(sf, 0x48))
goto fail;
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;

View file

@ -0,0 +1,159 @@
#include "meta.h"
#include "../util/meta_utils.h"
#include "../coding/coding.h"
/* SFX0 - from Monster Games [NASCAR Heat 2002 (Xbox), NASCAR: Dirt to Daytona (PS2/GC), Excite Truck (Wii), ExciteBots (Wii)] */
VGMSTREAM* init_vgmstream_sfx0_monster(STREAMFILE* sf) {
/* checks*/
uint32_t data_size = read_u32le(0x00,sf);
uint32_t head_size = read_u32le(0x04,sf);
if (!data_size || !head_size || data_size + head_size != get_streamfile_size(sf))
return NULL;
// .sfx: common
// .sf0: tiny .sn0 (preload?)
if (!check_extensions(sf, "sfx,sf0"))
return NULL;
// SFX0 is the internal fourCC used for .sfx
meta_header_t h = {0};
h.meta = meta_SFX0_MONSTER;
h.loop_flag = read_u8 (0x08, sf);
int extra_flag = read_u8 (0x09, sf); // always 1 in DSP
// 0a: null?
int codec = read_u16le(0x0c, sf);
h.channels = read_u16le(0x0e, sf);
h.sample_rate = read_s32le(0x10, sf);
// 14: bitrate (not always accurate?)
uint32_t config1 = read_u32le(0x18, sf); // block size + bps
uint32_t config2 = read_u32le(0x1c, sf); // usually 0
// 20: 0x10 padding (Xbox), partial DSP header on DSP or data
if (h.channels != 1) // not seen (late games use .sfx + .2.sfx dual tracks)
return NULL;
h.stream_offset = head_size;
// .sf0 mini files
if (codec == 0x00 && extra_flag == 0 && head_size <= 0x20) {
codec = 0x0002;
h.loop_flag = 0;
}
switch (codec) {
case 0xCFFF: // PS2 games
if (config1 != 0x00040002 || config2 != 0)
return NULL;
h.coding = coding_PSX;
h.layout = layout_none;
h.num_samples = ps_bytes_to_samples(data_size, h.channels);
break;
case 0x0069: // Xbox games
if (config1 != 0x00040024 || config2 != 0x00400002)
return NULL;
h.coding = coding_XBOX_IMA;
h.layout = layout_none;
h.num_samples = xbox_ima_bytes_to_samples(data_size, h.channels);
break;
case 0x0001: // GC games
if (config1 != 0x00100002 || config2 != 0)
return NULL;
h.coding = coding_PCM16LE; //LE!
h.layout = layout_none;
h.num_samples = pcm16_bytes_to_samples(data_size, h.channels);
break;
case 0x0000: // Wii games
if (config1 != 0x00100000 || config2 != 0)
return NULL;
h.coding = coding_NGC_DSP;
h.layout = layout_none;
h.num_samples = dsp_bytes_to_samples(data_size, h.channels);
h.big_endian = true;
h.coefs_offset = 0x3c;
break;
case 0x0002: // fake codec for .sf0 [ExciteBots (Wii)]
if (config1 != 0x00100000 || config2 != 0)
return NULL;
h.coding = coding_PCM16BE;
h.layout = layout_none;
h.num_samples = pcm16_bytes_to_samples(data_size, h.channels);
break;
default:
return NULL;
}
// full loops only
h.loop_start = 0;
h.loop_end = h.num_samples;
h.open_stream = true;
h.sf = sf;
return alloc_metastream(&h);
}
/* SFX0 - from early Monster Games [NASCAR Heat 2002 (PS2)] */
VGMSTREAM* init_vgmstream_sfx0_monster_old(STREAMFILE* sf) {
/* checks*/
uint32_t data_size = read_u32le(0x00,sf);
uint32_t head_size = 0x16;
if (!data_size || data_size + head_size != get_streamfile_size(sf))
return NULL;
if (!check_extensions(sf, "sfx"))
return NULL;
// SFX0 is the internal fourCC used for .sfx
meta_header_t h = {0};
h.meta = meta_SFX0_MONSTER;
int codec = read_u16le(0x04, sf);
h.channels = read_u16le(0x06, sf);
h.sample_rate = read_s32le(0x08, sf);
// 0c: bitrate (not always accurate?)
uint32_t config1 = read_u32le(0x10, sf);
uint16_t config2 = read_u16le(0x14, sf);
if (h.channels != 1) //not seen
return NULL;
h.stream_offset = head_size;
switch (codec) {
case 0xCFFF:
if (config1 != 0x00040002 || config2 != 0x6164)
return NULL;
h.coding = coding_PSX;
h.layout = layout_none;
h.num_samples = ps_bytes_to_samples(data_size, h.channels);
h.loop_flag = read_u8(0x17, sf) == 0x06; //PSX loop flags
break;
default:
return NULL;
}
// full loops only
h.loop_start = 0;
h.loop_end = h.num_samples;
h.open_stream = true;
h.sf = sf;
return alloc_metastream(&h);
}

View file

@ -0,0 +1,103 @@
#include "meta.h"
#include "../coding/coding.h"
/* SFXB - from Konami games [Yu-Gi-Oh: The Dawn of Destiny (Xbox)] */
VGMSTREAM* init_vgmstream_sfxb(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
int loop_flag, channels, sample_rate;
/* checks */
if (!is_id32be(0x00,sf, "SFXB"))
return NULL;
if (!check_extensions(sf,"xau"))
return NULL;
// 04: version? (2)
// 08: file id
// 0c: file size
// 10: possibly chunk definitions (all files have 4)
// 00: type (00030200=subsong info, 00030201=headers, 00030202=data)
// 04: size
// 08: relative offset (after chunks = 0x50)
// 0c: always 0x00000202
uint32_t subs_offset = 0x50 + read_u32le(0x28,sf); //always 0x00
uint32_t head_offset = 0x50 + read_u32le(0x38,sf); //always 0x10
uint32_t data_offset = 0x50 + read_u32le(0x48,sf); //varies
// subsong chunk
// 00: file id again
// 04: subsongs
// 08: always 0x7F
// 0c: null
int target_subsong = sf->stream_index;
int total_subsongs = read_u32le(subs_offset + 0x04, sf);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong > total_subsongs)
return NULL;
uint32_t entry_offset = head_offset + 0x60 * (target_subsong - 1);
// 00: type
// 04: flags?
// 08: flags? (always 0x00020000)
// 0c: offset
// 10: size
// 14: null
// 18: loop start
// 1c: loop end
// 20: RIFF + "XWV" + "fmt" + "loop" (same as loop start/end) + "data" (same as size)
uint32_t stream_type = read_u32le(entry_offset + 0x00, sf);
uint32_t stream_offset = read_u32le(entry_offset + 0x0c, sf) + data_offset;
uint32_t stream_size = read_u32le(entry_offset + 0x10, sf);
uint32_t loop_start = read_u32le(entry_offset + 0x18, sf);
uint32_t loop_end = read_u32le(entry_offset + 0x1c, sf) + loop_start;
if (!is_id32be(entry_offset + 0x20,sf, "RIFF"))
return NULL;
if (read_u16le(entry_offset + 0x34,sf) != 0x01) /* codec */
return NULL;
channels = read_u16le(entry_offset + 0x36, sf);
sample_rate = read_u32le(entry_offset + 0x38, sf);
loop_flag = (loop_end > 0);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_SFXB;
vgmstream->sample_rate = sample_rate;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
switch(stream_type) {
case 0x0001:
vgmstream->coding_type = coding_SILENCE;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = sample_rate;
// stream info is repeat of first subsong
break;
case 0x0F01:
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
vgmstream->num_samples = pcm16_bytes_to_samples(stream_size, channels);
vgmstream->loop_start_sample = pcm16_bytes_to_samples(loop_start, channels);
vgmstream->loop_end_sample = pcm16_bytes_to_samples(loop_end, channels);
break;
default:
goto fail;
}
if (!vgmstream_open_stream(vgmstream, sf, stream_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -0,0 +1,60 @@
#include "meta.h"
#include "../util/meta_utils.h"
#include "../coding/coding.h"
static STREAMFILE* setup_song_streamfile(STREAMFILE* sf) {
STREAMFILE* new_sf = NULL;
STREAMFILE* multi_sf[2] = {0};
multi_sf[0] = open_wrap_streamfile(sf);
multi_sf[1] = open_streamfile_by_ext(sf, "sf0");
new_sf = open_multifile_streamfile_f(multi_sf, 2);
return new_sf;
}
/* Song - from Monster Games with split data [ExciteBots (Wii)] */
VGMSTREAM* init_vgmstream_song_monster(STREAMFILE* sf) {
/* checks*/
int sample_rate = read_s32le(0x00,sf);
if (sample_rate != 32000)
return NULL;
if (read_u32be(0x04,sf))
return NULL;
// .sn0/sng: common
if (!check_extensions(sf, "sn0,sng"))
return NULL;
meta_header_t h = {0};
h.meta = meta_SONG_MONSTER;
h.chan_size = read_u32le(0x08,sf);
h.interleave = read_u32le(0x0c,sf);
if (read_u32be(0x10,sf))
return NULL;
h.stream_offset = 0x14;
h.sample_rate = sample_rate;
h.channels = 2;
if (h.interleave * h.channels + 0x14 != get_streamfile_size(sf))
return NULL;
h.coding = coding_PCM16BE;
h.layout = layout_interleave;
uint32_t total_size = (h.chan_size + h.interleave) * h.channels;
h.num_samples = pcm16_bytes_to_samples(total_size, h.channels);
// first block is in this header, rest of data in separate sf0; join both to play as one (could use segments too)
STREAMFILE* temp_sf = setup_song_streamfile(sf);
if (!temp_sf)
return NULL;
h.open_stream = true;
h.sf = temp_sf;
VGMSTREAM* v = alloc_metastream(&h);
close_streamfile(temp_sf);
return v;
}

View file

@ -31,7 +31,7 @@ VGMSTREAM* init_vgmstream_spsd(STREAMFILE *sf) {
/* At 0x30(4*ch) is some config per channel but doesn't seem to affect ADPCM (found with PCM too) */
//todo with 0x80 seems 0x2c is a loop_start_sample but must be adjusted to +1 block? (uncommon flag though)
// With 0x80, 0x2c is a loop_start_sample but must be adjusted to +1 block (uncommon flag though)
loop_flag = (flags & 0x80);
channels = ((flags & 0x01) || (flags & 0x02)) ? 2 : 1; /* 0x02 is rare (Virtua Tennis 2) */
start_offset = 0x40;
@ -63,7 +63,7 @@ VGMSTREAM* init_vgmstream_spsd(STREAMFILE *sf) {
case 0x03: /* standard */
vgmstream->coding_type = coding_AICA_int;
vgmstream->num_samples = yamaha_bytes_to_samples(data_size, channels);
vgmstream->loop_start_sample = /*read_s32le(0x2c,streamFile) +*/ yamaha_bytes_to_samples(0x2000,1);
vgmstream->loop_start_sample = read_s32le(0x2c,sf) + yamaha_bytes_to_samples(0x2000,1);
vgmstream->loop_end_sample = vgmstream->num_samples;
break;

View file

@ -0,0 +1,74 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
/* .ssp - Konami/Bemani beatmania IIDX container [beatmania IIDX 16 (AC) ~ beatmania IIDX 19 (AC), Bishi Bashi Channel (AC)] */
VGMSTREAM* init_vgmstream_ssp(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
/* checks */
if (!check_extensions(sf, "ssp"))
return NULL;
// 00: bank name
// 10: first subsong offset
// 14: max subsongs
// 18+: memory garbage?
// 48: table
uint32_t table_offset = 0x48;
uint32_t first_offset = read_u32le(0x10,sf);
int target_subsong = sf->stream_index;
int total_subsongs = read_u32le(0x14,sf);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong > total_subsongs || total_subsongs < 1) // arbitrary max
return NULL;
// extra checks to fail faster
if (total_subsongs > 1024) // arbitrary max
return NULL;
if (first_offset != read_u32le(table_offset, sf))
return NULL;
// unlike .2dx table seems to have many blanks (total subsongs seems accurate)
uint32_t subfile_offset = 0;
int current_subsong = 0;
uint32_t offset = table_offset;
while (offset < first_offset) {
uint32_t entry_offset = read_u32le(offset, sf);
offset += 0x04;
if (entry_offset == 0)
continue;
current_subsong++;
if (current_subsong == target_subsong) {
subfile_offset = entry_offset;
break;
}
}
if (subfile_offset == 0)
return NULL;
uint32_t subfile_size = read_u32le(subfile_offset + 0x08, sf) + 0x18;
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "sd9");
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_sd9(temp_sf);
if (!vgmstream) goto fail;
vgmstream->num_streams = total_subsongs;
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -0,0 +1,43 @@
#include "meta.h"
#include "../util/meta_utils.h"
#include "../coding/coding.h"
/* STR - from Final Fantasy Crystal Chronicles (GC) */
VGMSTREAM* init_vgmstream_str_sqex(STREAMFILE* sf) {
/* checks */
if (!is_id32be(0x00,sf, "STR\0"))
return NULL;
if (!check_extensions(sf, "str"))
return NULL;
if (read_u32be(0x04,sf) != 0)
return NULL;
if (read_u32be(0x08,sf) != get_streamfile_size(sf))
return NULL;
meta_header_t h = {0};
h.meta = meta_STR_SQEX;
h.num_samples = read_s32be(0x0C, sf) * 14;
// 10: always -1 (loop point?)
h.sample_rate = read_u32be(0x14, sf) != 0 ? 44100 : 32000; // unknown value
h.channels = read_s32be(0x18, sf);
// 1c: volume? (128)
h.coefs_offset = 0x20;
h.coefs_spacing = 0x2e;
h.big_endian = true;
// 40: initial ps
// 48: hist?
h.interleave = 0x1000;
h.stream_offset = 0x1000;
h.coding = coding_NGC_DSP;
h.layout = layout_interleave;
h.open_stream = true;
h.sf = sf;
return alloc_metastream(&h);
}

View file

@ -226,8 +226,7 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
}
/* set common interleaves to simplify usage
* (maybe should ignore if manually overwritten, possibly with 0 on purpose?) */
/* set common interleaves to simplify usage */
if (txth.interleave == 0) {
uint32_t interleave = 0;
switch(txth.codec) {
@ -244,7 +243,7 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
case PCM8_U:
case PCM8_SB:
case ULAW:
case ALAW:
case ALAW: interleave = 0x01; break;
default:
break;
}

View file

@ -16,8 +16,6 @@
static void apply_settings_body(VGMSTREAM* vgmstream, txtp_entry_t* entry) {
// tweak playable part, which only makes sense
VGM_LOG("tesst: %i,%i\n", entry->body_mode , vgmstream->loop_flag);
if (!entry->body_mode || !vgmstream->loop_flag)
return;

View file

@ -2,43 +2,45 @@
#include "../coding/coding.h"
/* .VAI - from Asobo Studio games [Ratatouille (GC)] */
VGMSTREAM * init_vgmstream_vai(STREAMFILE *streamFile) {
VGMSTREAM* init_vgmstream_vai(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
size_t data_size;
int loop_flag, channel_count;
int loop_flag, channels;
/* checks */
if ( !check_extensions(streamFile,"vai") )
goto fail;
int sample_rate = read_s32be(0x00,sf);
if (sample_rate < 8000 || sample_rate > 48000) //arbitrary max
return NULL;
if (!check_extensions(sf,"vai"))
return NULL;
start_offset = 0x4060;
data_size = get_streamfile_size(streamFile) - start_offset;
if (read_32bitBE(0x04,streamFile) != data_size)
goto fail;
data_size = read_s32be(0x04,sf);
if (data_size != get_streamfile_size(sf) - start_offset)
return NULL;
channel_count = 2;
channels = 2;
loop_flag = 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VAI;
vgmstream->sample_rate = read_32bitBE(0x00,streamFile);
vgmstream->num_samples = dsp_bytes_to_samples(data_size,channel_count);
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = dsp_bytes_to_samples(data_size,channels);
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x4000;
dsp_read_coefs_be(vgmstream,streamFile,0x0c,0x20);
dsp_read_coefs_be(vgmstream, sf, 0x0c, 0x20);
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;

View file

@ -123,9 +123,9 @@ VGMSTREAM* init_vgmstream_vas_kceo(STREAMFILE* sf) {
case IMA:
vgmstream->coding_type = coding_XBOX_IMA;
vgmstream->layout_type = layout_blocked_xvas;
vgmstream->layout_type = layout_blocked_vas_kceo;
/* blocks of 0x20000 with padding */
// blocks of 0x20000 with 0x20 padding, remove it to calculate samples
data_size -= (data_size / 0x20000) * 0x20;
loop_start -= (loop_start / 0x20000) * 0x20;
loop_end -= (loop_end / 0x20000) * 0x20;

View file

@ -2,71 +2,95 @@
#include "../util.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
#include "../util/meta_utils.h"
/* VGS - from Guitar Hero Encore - Rocks the 80s, Guitar Hero II PS2 */
/* VGS - from Harmonix games [Guitar Hero II (PS2), Guitar Hero Encore: Rocks the 80s (PS2)] */
VGMSTREAM* init_vgmstream_vgs(STREAMFILE *sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
size_t channel_size = 0, stream_data_size, stream_frame_count;
int channels = 0, loop_flag = 0, sample_rate = 0, stream_sample_rate;
int i;
/* checks */
if (!is_id32be(0x00,sf, "VgS!"))
goto fail;
/* 0x04: version? */
return NULL;
// 0x04: version?
if (!check_extensions(sf,"vgs"))
goto fail;
return NULL;
meta_header_t h = {0};
h.meta = meta_VGS;
/* contains N streams, which can have one less frame, or half frame and sample rate */
for (i = 0; i < 8; i++) {
stream_sample_rate = read_32bitLE(0x08 + 0x08*i + 0x00,sf);
stream_frame_count = read_32bitLE(0x08 + 0x08*i + 0x04,sf);
stream_data_size = stream_frame_count*0x10;
for (int i = 0; i < 8; i++) {
int stream_sample_rate = read_s32le(0x08 + 0x08 * i + 0x00,sf);
uint32_t stream_frame_count = read_u32le(0x08 + 0x08 * i + 0x04,sf);
uint32_t stream_data_size = stream_frame_count * 0x10;
if (stream_sample_rate == 0)
break;
if (!sample_rate || !channel_size) {
sample_rate = stream_sample_rate;
channel_size = stream_data_size;
if (!h.sample_rate || !h.chan_size) {
h.sample_rate = stream_sample_rate;
h.chan_size = stream_data_size;
}
/* some streams end 1 frame early */
if (channel_size - 0x10 == stream_data_size) {
channel_size -= 0x10;
if (h.chan_size - 0x10 == stream_data_size) {
h.chan_size -= 0x10;
}
/* Guitar Hero II sometimes uses half sample rate for last stream */
if (sample_rate != stream_sample_rate) {
if (h.sample_rate != stream_sample_rate) {
VGM_LOG("VGS: ignoring stream %i\n", i);
//total_streams++; // todo handle substreams
break;
}
channels++;
h.channels++;
}
start_offset = 0x80;
h.stream_offset = 0x80;
h.num_samples = ps_bytes_to_samples(h.chan_size, 1);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
h.coding = coding_PSX_badflags; // flag = stream/channel number
h.layout = layout_blocked_vgs;
h.open_stream = true;
h.sf = sf;
vgmstream->meta_type = meta_VGS;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = ps_bytes_to_samples(channel_size * channels, channels);
return alloc_metastream(&h);
}
vgmstream->coding_type = coding_PSX_badflags; /* flag = stream/channel number */
vgmstream->layout_type = layout_blocked_vgs;
/* .vgs - from Harmonix games [Karaoke Revolution (PS2), EyeToy: AntiGrav (PS2)] */
VGMSTREAM* init_vgmstream_vgs_old(STREAMFILE* sf) {
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
/* checks */
int channels = read_s32le(0x00,sf);
if (channels < 1 || channels > 4)
return NULL;
// .vgs: actual extension in bigfiles
if (!check_extensions(sf,"vgs"))
return NULL;
meta_header_t h = {0};
h.meta = meta_VGS;
h.channels = read_s32le(0x00, sf);
h.sample_rate = read_s32le(0x04, sf);
int frame_count = read_u32le(0x08, sf);
// 0c: usually 0, sometimes garbage
h.stream_offset = 0x10;
h.stream_size = get_streamfile_size(sf) - h.stream_offset;
if (frame_count * h.channels * 0x10 > h.stream_size)
return NULL;
h.num_samples = ps_bytes_to_samples(h.stream_size, channels);
h.interleave = 0x2000;
h.coding = coding_PSX;
h.layout = layout_interleave;
h.open_stream = true;
h.sf = sf;
return alloc_metastream(&h);
}

View file

@ -0,0 +1,33 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/meta_utils.h"
/* .VGV - from Rune: Viking Warlord (PS2) */
VGMSTREAM* init_vgmstream_vgv(STREAMFILE* sf) {
/* checks */
if (read_u32le(0x00,sf) < 22050 || read_u32le(0x00,sf) > 48000) // always 22050?
return NULL;
if (read_f32le(0x04,sf) == 0.0 || read_f32le(0x04,sf) > 500.0) //duration, known max is ~432.08 = 7:12
return NULL;
if (read_u32le(0x08,sf) != 0x00 || read_u32le(0x0c,sf) != 0x00)
return NULL;
if (!check_extensions(sf, "vgv"))
return NULL;
meta_header_t h = {0};
h.meta = meta_VGV;
h.channels = 1;
h.sample_rate = read_s32le(0x00, sf);
h.stream_offset = 0x10;
h.stream_size = get_streamfile_size(sf);
h.num_samples = ps_bytes_to_samples(h.stream_size, h.channels);
h.coding = coding_PSX;
h.open_stream = true;
h.sf = sf;
return alloc_metastream(&h);
}

View file

@ -1,125 +0,0 @@
#include "meta.h"
#include "../util.h"
/* SNG (from Excite Truck [WII]) */
VGMSTREAM * init_vgmstream_wii_sng(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int i;
int loop_flag;
int channel_count;
int coef1;
int coef2;
int first_block_len;
int second_channel_start;
int dataBuffer = 0;
int Founddata = 0;
size_t file_size;
off_t current_chunk;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("sng",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x30545352) /* "0STR" */
goto fail;
if (read_32bitBE(0x04,streamFile) != 0x34000000) /* 0x34000000 */
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x08000000) /* 0x08000000" */
goto fail;
if (read_32bitBE(0x0C,streamFile) != 0x01000000) /* 0x01000000 */
goto fail;
if (read_32bitLE(0x10,streamFile) != (get_streamfile_size(streamFile)))
goto fail;
loop_flag = (read_32bitLE(0x130,streamFile) !=0); /* not sure */
channel_count = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x180;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x110,streamFile);
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->num_samples = read_32bitLE(0x100,streamFile)/16*14*2;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitBE(0x130,streamFile)/16*14;
vgmstream->loop_end_sample = read_32bitBE(0x134,streamFile)/16*14;
}
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_WII_SNG;
/* scan file until we find a "data" string */
first_block_len = read_32bitLE(0x100,streamFile);
file_size = get_streamfile_size(streamFile);
{
current_chunk = first_block_len;
/* Start at 0 and loop until we reached the
file size, or until we found a "data string */
while (!Founddata && current_chunk < file_size) {
dataBuffer = (read_32bitLE(current_chunk,streamFile));
if (dataBuffer == first_block_len) { /* The value from the first block length */
/* if "data" string found, retrieve the needed infos */
Founddata = 1;
second_channel_start = current_chunk+0x80;
/* We will cancel the search here if we have a match */
break;
}
/* else we will increase the search offset by 1 */
current_chunk = current_chunk + 1;
}
}
coef1 = 0x13C;
if (Founddata == 0) {
goto fail;
} else if (Founddata == 1) {
coef2 = current_chunk+0x3C;
}
for (i=0;i<16;i++)
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(coef1+i*2,streamFile);
if (channel_count == 2) {
for (i=0;i<16;i++)
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(coef2+i*2,streamFile);
}
/* open the file for reading */
{
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;
/* The first channel */
vgmstream->ch[0].channel_start_offset=
vgmstream->ch[0].offset=start_offset;
/* The second channel */
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[i].channel_start_offset=
vgmstream->ch[1].offset=second_channel_start;
}
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1,60 +0,0 @@
#include "meta.h"
#include "../coding/coding.h"
/* XAU - from Konami games [Yu-Gi-Oh - The Dawn of Destiny (Xbox)] */
VGMSTREAM * init_vgmstream_xau_konami(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, header_offset;
size_t stream_size;
int loop_flag, channel_count, sample_rate;
off_t loop_start, loop_end;
/* checks */
if ( !check_extensions(streamFile,"xau") )
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x53465842) /* "SFXB" */
goto fail;
//todo: subsongs used in sfx packs (rare)
if (read_32bitLE(0x54,streamFile) != 1) /* subsong count */
goto fail;
start_offset = 0x60 + read_32bitLE(0x34,streamFile);
header_offset = 0x60 + 0x20 + 0x40*0; /* target subsong */
if (read_32bitBE(header_offset+0x00,streamFile) != 0x52494646) /* "RIFF" */
goto fail;
if (read_16bitLE(header_offset+0x14,streamFile) != 0x01) /* codec */
goto fail;
channel_count = read_16bitLE(header_offset+0x16,streamFile);
sample_rate = read_32bitLE(header_offset+0x18,streamFile);
loop_start = read_32bitLE(header_offset+030,streamFile);
loop_end = read_32bitLE(header_offset+0x34,streamFile);
loop_flag = (loop_end > 0);
stream_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_XAU_KONAMI;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = pcm_bytes_to_samples(stream_size,channel_count,16);
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);
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1,65 +1,65 @@
#include "meta.h"
#include "../coding/coding.h"
/* XMD - from Konami Xbox games [Silent Hill 4 (Xbox), Castlevania Curse of Darkness (Xbox)] */
VGMSTREAM * init_vgmstream_xmd(STREAMFILE *streamFile) {
/* XMD - from Konami Xbox games [Silent Hill 4 (Xbox), Castlevania: Curse of Darkness (Xbox)] */
VGMSTREAM* init_vgmstream_xmd(STREAMFILE *sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate;
int loop_flag, channels, sample_rate;
size_t data_size, loop_start, frame_size;
/* checks (.xmd comes from bigfiles with filenames) */
if (!check_extensions(streamFile, "xmd"))
goto fail;
if (!check_extensions(sf, "xmd"))
return NULL;
if ((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) == 0x786D6400) { /* "xmd\0" */
if ((read_u32be(0x00,sf) & 0xFFFFFF00) == get_id32be("xmd\0")) {
/* v2 from Castlevania: Curse of Darkness */
channel_count = read_8bit(0x03,streamFile);
sample_rate = (uint16_t)read_16bitLE(0x04, streamFile);
data_size = read_32bitLE(0x06, streamFile);
loop_flag = read_8bit(0x0a,streamFile);
loop_start = read_32bitLE(0x0b, streamFile);
channels = read_u8 (0x03,sf);
sample_rate = read_u16le(0x04, sf);
data_size = read_u32le(0x06, sf);
loop_flag = read_u8 (0x0a,sf);
loop_start = read_u32le(0x0b, sf);
/* 0x0f(2): unknown+config? */
frame_size = 0x15;
start_offset = 0x11;
}
else {
/* v1 from Silent Hill 4 */
channel_count = read_8bit(0x00,streamFile);
sample_rate = (uint16_t)read_16bitLE(0x01, streamFile);
data_size = read_32bitLE(0x03, streamFile);
loop_flag = read_8bit(0x07,streamFile);
loop_start = read_32bitLE(0x08, streamFile);
// v1 from Silent Hill 4
channels = read_u8 (0x00,sf);
// 01: volume? always 0x80
sample_rate = read_u16le(0x01, sf);
data_size = read_u32le(0x03, sf);
loop_flag = read_u8 (0x07,sf);
loop_start = read_u32le(0x08, sf);
frame_size = 0x0d;
start_offset = 0x0c;
}
/* extra checks just in case */
if (data_size > get_streamfile_size(streamFile))
goto fail; /* v1 .xmd are sector-aligned with padding */
if (channel_count > 2)
goto fail;
if (data_size > get_streamfile_size(sf))
return NULL; // v1 .xmd are sector-aligned with padding
if (channels < 1 || channels > 2)
return NULL;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = data_size / frame_size / channel_count * ((frame_size-0x06)*2 + 2); /* bytes to samples */
if (loop_flag) {
vgmstream->loop_start_sample = loop_start / frame_size / channel_count * ((frame_size-0x06)*2 + 2); /* bytes to samples */
vgmstream->num_samples = data_size / frame_size / channels * ((frame_size - 0x06) * 2 + 2); // bytes to samples
vgmstream->loop_start_sample = loop_start / frame_size / channels * ((frame_size - 0x06)*2 + 2); // bytes to samples
vgmstream->loop_end_sample = vgmstream->num_samples;
}
vgmstream->meta_type = meta_XMD;
vgmstream->coding_type = coding_XMD;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = frame_size;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;

View file

@ -4,54 +4,59 @@
static void read_xps_name(VGMSTREAM *vgmstream, STREAMFILE *streamFile, int file_id);
/* .XPS+DAT - From Software games streams [Metal Wolf Chaos (Xbox), Otogi (Xbox)] */
VGMSTREAM * init_vgmstream_xps_dat(STREAMFILE *streamFile) {
VGMSTREAM* init_vgmstream_xps_dat(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE * streamData = NULL;
STREAMFILE* sf_data = NULL;
off_t start_offset, header_offset;
size_t stream_size;
int loop_flag, channel_count, sample_rate, codec, loop_start_sample, loop_end_sample, file_id;
int total_subsongs, target_subsong = streamFile->stream_index;
int loop_flag, channels, sample_rate, codec, loop_start_sample, loop_end_sample, file_id;
/* checks */
if (!check_extensions(streamFile, "xps"))
goto fail;
if (read_u32le(0x00,sf) != get_streamfile_size(sf))
return NULL;
if (!check_extensions(sf, "xps"))
return NULL;
if (read_32bitLE(0x00,streamFile) != get_streamfile_size(streamFile))
goto fail;
if (read_32bitBE(0x0c,streamFile) != 0x64696666) /* "diff" */
goto fail;
// 04: bank subsongs
if (read_u32le(0x08,sf) != 0x02) // type 2=xps
return NULL;
if (!is_id32be(0x0c,sf, "diff"))
return NULL;
/* handle .xps+dat (bank .xps are done below) */
streamData = open_streamfile_by_ext(streamFile, "dat");
if (!streamData) goto fail;
// handle .xps+dat (bank .xps are done below)
sf_data = open_streamfile_by_ext(sf, "dat");
if (!sf_data) return NULL;
/* 0x00: approximate file size */
// 00: approximate file size
// 04: subsongs
// 08: type 1=dat
total_subsongs = read_32bitLE(0x04,streamData);
int target_subsong = sf->stream_index;
int total_subsongs = read_s32le(0x04,sf_data);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) return NULL;
header_offset = 0x20 + 0x94*(target_subsong-1); /* could start at 0x0c too */
header_offset = 0x20 + 0x94 * (target_subsong-1); // could start at 0x0c or 0x10 too
file_id = read_32bitLE(header_offset+0x00,streamData);
start_offset = read_32bitLE(header_offset+0x04,streamData);
stream_size = read_32bitLE(header_offset+0x08,streamData);
file_id = read_s32le(header_offset+0x00,sf_data);
start_offset = read_u32le(header_offset+0x04,sf_data);
stream_size = read_u32le(header_offset+0x08,sf_data);
/* 0x0c: loop start offset? */
/* 0x10: loop end offset? */
/* 0x14: always null? */
codec = read_16bitLE(header_offset+0x18,streamData);
channel_count = read_16bitLE(header_offset+0x1a,streamData);
sample_rate = read_32bitLE(header_offset+0x1c,streamData);
codec = read_u16le(header_offset+0x18,sf_data);
channels = read_u16le(header_offset+0x1a,sf_data);
sample_rate = read_s32le(header_offset+0x1c,sf_data);
/* 0x20: average bitrate */
/* 0x24: block size, bps */
loop_flag = read_32bitLE(header_offset+0x5c,streamData);
loop_start_sample = read_32bitLE(header_offset+0x6c,streamData);
loop_end_sample = read_32bitLE(header_offset+0x70,streamData) + 1; /* a "smpl" chunk basically */
loop_flag = read_s32le(header_offset+0x5c,sf_data);
loop_start_sample = read_s32le(header_offset+0x6c,sf_data);
loop_end_sample = read_s32le(header_offset+0x70,sf_data) + 1; // a "smpl" chunk basically
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
@ -66,56 +71,54 @@ VGMSTREAM * init_vgmstream_xps_dat(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16);
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channels, 16);
break;
case 0x69:
vgmstream->coding_type = coding_XBOX_IMA;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = xbox_ima_bytes_to_samples(stream_size, channel_count);
vgmstream->num_samples = xbox_ima_bytes_to_samples(stream_size, channels);
break;
default:
goto fail;
}
read_xps_name(vgmstream, streamFile, file_id);
read_xps_name(vgmstream, sf, file_id);
if (!vgmstream_open_stream(vgmstream,streamData,start_offset))
if (!vgmstream_open_stream(vgmstream,sf_data,start_offset))
goto fail;
close_streamfile(streamData);
close_streamfile(sf_data);
return vgmstream;
fail:
close_streamfile(streamData);
close_streamfile(sf_data);
close_vgmstream(vgmstream);
return NULL;
}
static void read_xps_name(VGMSTREAM *vgmstream, STREAMFILE *streamFile, int file_id) {
int i, entries;
int name_id = -1, udss_name_id;
off_t entry_offset = 0x10;
static void read_xps_name(VGMSTREAM* vgmstream, STREAMFILE* sf, int file_id) {
int name_id = -1;
/* main section + stream sections (usually same number but not always) */
entries = read_32bitLE(0x04,streamFile);
int entries = read_s32le(0x04,sf);
/* "sid\0" entries: find name_id of file_id */
for (i = 0; i < entries; i++) {
off_t entry_base = entry_offset;
size_t entry_size = read_32bitLE(entry_base+0x00,streamFile);
uint32_t entry_id = read_32bitBE(entry_base+0x04,streamFile);
size_t entry_pad = read_32bitLE(entry_base+0x08,streamFile);
uint32_t entry_offset = 0x10;
for (int i = 0; i < entries; i++) {
uint32_t entry_base = entry_offset;
uint32_t entry_size = read_u32le(entry_base+0x00,sf);
uint32_t entry_id = read_u32be(entry_base+0x04,sf);
uint32_t entry_pad = read_u32le(entry_base+0x08,sf);
/* 0x0c: always null, rest: entry (format varies) */
entry_offset += entry_size + entry_pad + 0x10;
/* sound info entry */
if (entry_id == 0x73696400) { /* "sid\0" */
int entry_file_id = read_32bitLE(entry_base+0x10,streamFile);
int entry_name_id = read_32bitLE(entry_base+0x14,streamFile);
if (entry_id == get_id32be("sid\0")) {
int entry_file_id = read_s32le(entry_base+0x10,sf);
int entry_name_id = read_s32le(entry_base+0x14,sf);
if (entry_file_id == file_id && name_id == -1) {
name_id = entry_name_id;
}
@ -123,101 +126,111 @@ static void read_xps_name(VGMSTREAM *vgmstream, STREAMFILE *streamFile, int file
}
/* sound stream entry, otherwise no good */
if (entry_id != 0x75647373) { /* "udss" */
goto fail;
if (entry_id != get_id32be("udss")) {
return;
}
udss_name_id = read_32bitLE(entry_base+0x10,streamFile);
int udss_name_id = read_s32le(entry_base+0x10,sf);
if (udss_name_id == name_id) {
off_t name_offset = entry_base + 0x10 + 0x08;
size_t name_size = entry_size - 0x08; /* includes null */
read_string(vgmstream->stream_name,name_size, name_offset,streamFile);
read_string(vgmstream->stream_name,name_size, name_offset,sf);
return;
}
}
fail:
return;
}
/* .XPS - From Software games banks [Metal Wolf Chaos (Xbox), Otogi (Xbox)] */
VGMSTREAM * init_vgmstream_xps(STREAMFILE *streamFile) {
VGMSTREAM * init_vgmstream_xps(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE * streamData = NULL;
int i, entries;
off_t entry_offset = 0x10;
int total_subsongs, target_subsong = streamFile->stream_index;
STREAMFILE* sf_data = NULL;
/* checks */
if (!check_extensions(streamFile, "xps"))
goto fail;
if (read_u32le(0x00,sf) != get_streamfile_size(sf))
return NULL;
if (!check_extensions(sf, "xps"))
return NULL;
if (read_32bitLE(0x00,streamFile) != get_streamfile_size(streamFile))
goto fail;
if (read_32bitBE(0x0c,streamFile) != 0x64696666) /* "diff" */
goto fail;
// 04: bank subsongs
if (read_u32le(0x08,sf) != 0x02) // 2=.xps, 1=.dat
return NULL;
if (!is_id32be(0x0c,sf, "diff"))
return NULL;
/* handle .xps alone (stream .xps+data are done above) */
streamData = open_streamfile_by_ext(streamFile, "dat");
if (streamData) goto fail;
sf_data = open_streamfile_by_ext(sf, "dat");
if (sf_data) return NULL;
/* main section + bank sections (usually same number but not always) */
entries = read_32bitLE(0x04,streamFile);
int entries = read_s32le(0x04,sf);
total_subsongs = 0;
int target_subsong = sf->stream_index;
int total_subsongs = 0;
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 /*|| target_subsong > total_subsongs || total_subsongs < 1*/) goto fail;
if (target_subsong < 0 /*|| target_subsong > total_subsongs || total_subsongs < 1*/)
return NULL;
//TODO: should probably unify
// - there is one "sid" per subsong with base config and one "udsb" per memory or external .dat stream
// - each "sid" is linked to a udsb by internal+external ids
// - however sids don't seem to be defined in the same order as streams
// - streams in .dat also don't seem to follow the sid order
/* parse entries: skip (there is probably a stream/bank flag here) */
for (i = 0; i < entries; i++) {
off_t entry_base = entry_offset;
size_t entry_size = read_32bitLE(entry_base+0x00,streamFile);
uint32_t entry_id = read_32bitBE(entry_base+0x04,streamFile);
size_t entry_pad = read_32bitLE(entry_base+0x08,streamFile);
/* 0x0c: always null, rest: entry (format varies) */
/* parse entries */
uint32_t entry_offset = 0x10;
for (int i = 0; i < entries; i++) {
uint32_t entry_base = entry_offset;
uint32_t entry_size = read_u32le(entry_base+0x00,sf);
uint32_t entry_id = read_u32be(entry_base+0x04,sf);
uint32_t entry_pad = read_u32le(entry_base+0x08,sf);
// 0c: null or garbage from other entries
// rest: entry (format varies)
entry_offset += entry_size + entry_pad + 0x10;
/* sound info entry */
if (entry_id == 0x73696400) { /* "sid\0" */
/* keep looking for sound banks */
// sound info entry
if (entry_id == get_id32be("sid\0")) {
// 10: external id
// 14: internal id
// 30: external flag
/* keep looking for stream entries */
continue;
}
/* sound bank entry, otherwise no good */
if (entry_id != 0x75647362) { /* "udsb" */
// stream entry
if (entry_id != get_id32be("udsb")) {
goto fail;
}
total_subsongs++;
/* open internal RIFF */
if (target_subsong == total_subsongs && vgmstream == NULL) {
STREAMFILE* temp_streamFile;
off_t subsong_offset = entry_base+0x18;
size_t subsong_size = read_32bitLE(entry_base+0x14,streamFile);
STREAMFILE* temp_sf;
// 10: internal id
uint32_t subsong_size = read_u32le(entry_base + 0x14,sf);
uint32_t subsong_offset = entry_base + 0x18;
temp_streamFile = setup_subfile_streamfile(streamFile, subsong_offset,subsong_size, "wav");
if (!temp_streamFile) goto fail;
temp_sf = setup_subfile_streamfile(sf, subsong_offset, subsong_size, "wav");
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_riff(temp_streamFile);
close_streamfile(temp_streamFile);
vgmstream = init_vgmstream_riff(temp_sf);
close_streamfile(temp_sf);
if (!vgmstream) goto fail;
}
}
/* subsong not found */
if (!vgmstream)
goto fail;
vgmstream->num_streams = total_subsongs;
return vgmstream;
fail:
close_streamfile(streamData);
close_streamfile(sf_data);
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -12,13 +12,12 @@ VGMSTREAM* init_vgmstream_xwav_new(STREAMFILE* sf) {
/* checks */
if (!is_id32le(0x00,sf, "XWAV"))
goto fail;
if (!is_id32be(0x00,sf, "VAWX")) //LE XWAV
return NULL;
/* .xwv: actual extension [Moon Diver (PS3/X360)]
* .vawx: header id */
if (!check_extensions(sf, "xwv,vawx"))
goto fail;
// .xwv: actual extension [Moon Diver (PS3/X360)]
if (!check_extensions(sf, "xwv"))
return NULL;
/* similar to older version but BE and a bit less complex */
/* 0x04: data size
@ -143,9 +142,9 @@ VGMSTREAM* init_vgmstream_xwav_old(STREAMFILE* sf) {
if (!is_id32be(0x00,sf, "XWAV"))
goto fail;
/* .xwv: actual extension [Bullet Witch (X360), Lost Odyssey Demo (X360)] */
// .xwv: actual extension [Bullet Witch (X360), Lost Odyssey Demo (X360)]
if (!check_extensions(sf, "xwv"))
goto fail;
return NULL;
/* similar to newer version but LE and a bit more complex */
/* 0x04: data size

View file

@ -92,7 +92,6 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_xmu,
init_vgmstream_sat_sap,
init_vgmstream_dc_idvi,
init_vgmstream_ps2_rnd,
init_vgmstream_idsp_tt,
init_vgmstream_kraw,
init_vgmstream_omu,
@ -130,11 +129,10 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_sts,
init_vgmstream_p2bt_move_visa,
init_vgmstream_gbts,
init_vgmstream_wii_sng,
init_vgmstream_ngc_dsp_iadp,
init_vgmstream_aax,
init_vgmstream_utf_dsp,
init_vgmstream_ngc_ffcc_str,
init_vgmstream_str_sqex,
init_vgmstream_sat_baka,
init_vgmstream_swav,
init_vgmstream_vsf,
@ -148,13 +146,12 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_dsp_ndp,
init_vgmstream_ps2_sps,
init_vgmstream_nds_hwas,
init_vgmstream_ngc_lps,
init_vgmstream_lps,
init_vgmstream_ps2_snd,
init_vgmstream_naomi_adpcm,
init_vgmstream_sd9,
init_vgmstream_2dx9,
init_vgmstream_dsp_kceje,
init_vgmstream_ps2_vgv,
init_vgmstream_gcub,
init_vgmstream_maxis_xa,
init_vgmstream_ngc_sck_dsp,
@ -195,14 +192,13 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_xvag,
init_vgmstream_cps,
init_vgmstream_sqex_scd,
init_vgmstream_ngc_nst_dsp,
init_vgmstream_nst_monster,
init_vgmstream_baf,
init_vgmstream_msf,
init_vgmstream_sndp,
init_vgmstream_sgxd,
init_vgmstream_ras,
init_vgmstream_spm,
init_vgmstream_ps2_iab,
init_vgmstream_vs_str,
init_vgmstream_lsf_n1nj4n,
init_vgmstream_xwav_new,
@ -211,13 +207,11 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_psnd,
init_vgmstream_adp_wildfire,
init_vgmstream_adp_qd,
init_vgmstream_eb_sfx,
init_vgmstream_eb_sf0,
init_vgmstream_mtaf,
init_vgmstream_alp,
init_vgmstream_wpd,
init_vgmstream_mn_str,
init_vgmstream_mss,
init_vgmstream_mcss,
init_vgmstream_ps2_hsf,
init_vgmstream_ivag,
init_vgmstream_2pfs,
@ -230,7 +224,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_kt_g1l,
init_vgmstream_kt_wiibgm,
init_vgmstream_bfstm,
init_vgmstream_mca,
init_vgmstream_madp,
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
init_vgmstream_mp4_aac,
#endif
@ -281,7 +275,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_opus_shinen,
init_vgmstream_opus_nus3,
init_vgmstream_opus_sps_n1,
init_vgmstream_pc_ast,
init_vgmstream_astl,
init_vgmstream_naac,
init_vgmstream_ubi_sb,
init_vgmstream_ubi_sm,
@ -290,7 +284,6 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_ubi_dat,
init_vgmstream_ubi_blk,
init_vgmstream_ubi_apm,
init_vgmstream_ezw,
init_vgmstream_vxn,
init_vgmstream_ea_snr_sns,
init_vgmstream_ea_sps,
@ -352,12 +345,11 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_msv,
init_vgmstream_sdf,
init_vgmstream_svgp,
init_vgmstream_vai,
init_vgmstream_aif_asobo,
init_vgmstream_ao,
init_vgmstream_apc,
init_vgmstream_wav2,
init_vgmstream_xau_konami,
init_vgmstream_sfxb,
init_vgmstream_derf,
init_vgmstream_utk,
init_vgmstream_nxa1,
@ -498,7 +490,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_nxof,
init_vgmstream_gwb_gwd,
init_vgmstream_s_pack,
init_vgmstream_cbx,
init_vgmstream_chatterbox,
init_vgmstream_vas_rockstar,
init_vgmstream_ea_sbk,
init_vgmstream_dsp_asura,
@ -519,7 +511,6 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_undefind,
init_vgmstream_oor,
init_vgmstream_mio,
init_vgmstream_2dx,
/* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */
init_vgmstream_agsc,
@ -537,6 +528,16 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_vs_mh,
init_vgmstream_adpcm_capcom,
init_vgmstream_ima,
init_vgmstream_vgv,
init_vgmstream_iab,
init_vgmstream_2dx,
init_vgmstream_ssp,
init_vgmstream_sfx0_monster,
init_vgmstream_sfx0_monster_old,
init_vgmstream_song_monster,
init_vgmstream_vai,
init_vgmstream_ezw,
init_vgmstream_vgs_old,
/* need companion files */
init_vgmstream_pos,
init_vgmstream_sli_loops,

View file

@ -211,10 +211,10 @@ typedef enum {
layout_blocked_str_snds,
layout_blocked_ws_aud,
layout_blocked_dec,
layout_blocked_xvas,
layout_blocked_vas_kceo,
layout_blocked_vs_mh,
layout_blocked_mul,
layout_blocked_gsb,
layout_blocked_gsnd,
layout_blocked_thp,
layout_blocked_filp,
layout_blocked_ea_swvr,
@ -302,7 +302,7 @@ typedef enum {
meta_HIS, /* Her Ineractive .his */
meta_BNSF, /* Bandai Namco Sound Format */
meta_XA, /* CD-ROM XA */
meta_XA,
meta_ADS,
meta_NPS,
meta_RXWS,
@ -367,7 +367,7 @@ typedef enum {
meta_ISH_ISD, /* Various (ISH+ISD DSP) */
meta_GSND,
meta_YDSP, /* WWE Day of Reckoning */
meta_FFCC_STR, /* Final Fantasy: Crystal Chronicles */
meta_STR_SQEX,
meta_UBI_JADE, /* Beyond Good & Evil, Rayman Raving Rabbids */
meta_GCA, /* Metal Slug Anthology */
meta_SSM,
@ -441,11 +441,11 @@ typedef enum {
meta_REDSPARK, /* "RedSpark" RSD (MadWorld) */
meta_RAGE_AUD, /* Rockstar AUD - MC:LA, GTA IV */
meta_NDS_HWAS, /* Spider-Man 3, Tony Hawk's Downhill Jam, possibly more... */
meta_NGC_LPS, /* Rave Master (Groove Adventure Rave)(GC) */
meta_LPS,
meta_NAOMI_ADPCM, /* NAOMI/NAOMI2 Arcade games */
meta_SD9, /* Konami/Bemani Arcade Games */
meta_2DX9, /* beatmania IIDX Arcade Games */
meta_PS2_VGV, /* Rune: Viking Warlord */
meta_SD9,
meta_2DX9,
meta_VGV,
meta_GCUB,
meta_MAXIS_XA, /* Sim City 3000 (PC) */
meta_NGC_SCK_DSP, /* Scorpion King (NGC) */
@ -481,18 +481,18 @@ typedef enum {
meta_GH3_BAR, /* Guitar Hero III Mobile .bar */
meta_DSP_DSPW, /* Sengoku Basara 3 [WII] */
meta_PS2_JSTM, /* Tantei Jinguji Saburo - Kind of Blue (PS2) */
meta_SQEX_SCD, /* Square-Enix SCD */
meta_NGC_NST_DSP, /* Animaniacs [NGC] */
meta_BAF, /* Bizarre Creations (Blur, James Bond) */
meta_XVAG, /* Ratchet & Clank Future: Quest for Booty (PS3) */
meta_SQEX_SCD,
meta_NST_MONSTER,
meta_BAF,
meta_XVAG,
meta_CPS,
meta_MSF,
meta_SNDP,
meta_SGXD, /* Sony: Folklore, Genji, Tokyo Jungle (PS3), Brave Story, Kurohyo (PSP) */
meta_SGXD,
meta_RAS,
meta_SPM,
meta_VGS_PS,
meta_PS2_IAB, /* Ueki no Housoku - Taosu ze Robert Juudan!! (PS2) */
meta_IAB,
meta_VS_STR, /* The Bouncer */
meta_LSF_N1NJ4N, /* .lsf n1nj4n Fastlane Street Racing (iPhone) */
meta_XWAV,
@ -501,13 +501,13 @@ typedef enum {
meta_PSND,
meta_ADP_WILDFIRE,
meta_QD_ADP,
meta_EB_SFX, /* Excitebots .sfx */
meta_EB_SF0, /* Excitebots .sf0 */
meta_SFX0_MONSTER,
meta_SONG_MONSTER,
meta_MTAF,
meta_ALP,
meta_WPD,
meta_MN_STR, /* Mini Ninjas (PC/PS3/WII) */
meta_MSS, /* Guerilla: ShellShock Nam '67 (PS2/Xbox), Killzone (PS2) */
meta_MCSS,
meta_PS2_HSF, /* Lowrider (PS2) */
meta_IVAG,
meta_2PFS,
@ -518,7 +518,7 @@ typedef enum {
meta_IDSP_NAMCO,
meta_KT_WIIBGM, /* Koei Tecmo WiiBGM */
meta_KTSS, /* Koei Tecmo Nintendo Stream (KNS) */
meta_MCA, /* Capcom MCA "MADP" */
meta_MADP,
meta_ADX_MONSTER,
meta_HCA,
meta_SVAG_SNK,
@ -533,7 +533,7 @@ typedef enum {
meta_WWISE_RIFF, /* Audiokinetic Wwise RIFF/RIFX */
meta_UBI_RAKI, /* Ubisoft RAKI header (Rayman Legends, Just Dance 2017) */
meta_SNDX,
meta_OGL, /* Shin'en Wii/WiiU (Jett Rocket (Wii), FAST Racing NEO (WiiU)) */
meta_OGL,
meta_MPC3,
meta_GHS,
meta_AAC_TRIACE,
@ -548,11 +548,11 @@ typedef enum {
meta_EA_SNU, /* Electronic Arts SNU (Dead Space) */
meta_AWC, /* Rockstar AWC (GTA5, RDR) */
meta_OPUS, /* Nintendo Opus [Lego City Undercover (Switch)] */
meta_PC_AST, /* Dead Rising (PC) */
meta_NAAC, /* Namco AAC (3DS) */
meta_UBI_SB, /* Ubisoft banks */
meta_UBI_APM, /* Ubisoft APM */
meta_EZW, /* EZ2DJ (Arcade) EZWAV */
meta_ASTL,
meta_NAAC,
meta_UBI_SB,
meta_UBI_APM,
meta_EZW,
meta_VXN, /* Gameloft mobile games */
meta_EA_SNR_SNS, /* Electronic Arts SNR+SNS (Burnout Paradise) */
meta_EA_SPS, /* Electronic Arts SPS (Burnout Crash) */
@ -610,7 +610,7 @@ typedef enum {
meta_AO, /* Cloudphobia (PC) */
meta_APC, /* MegaRace 3 (PC) */
meta_WAV2,
meta_XAU_KONAMI, /* Yu-Gi-Oh - The Dawn of Destiny (Xbox) */
meta_SFXB,
meta_DERF, /* Stupid Invaders (PC) */
meta_SADF,
meta_UTK,
@ -618,7 +618,7 @@ typedef enum {
meta_ADPCM_CAPCOM,
meta_UE4OPUS,
meta_XWMA,
meta_VA3, /* DDR Supernova 2 AC */
meta_VA3,
meta_XOPUS,
meta_VS_SQUARE,
meta_NWAV,