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 f96cfea2d3
commit 4232fb3949
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 */
uint8_t sr_index = 0;
uint8_t ch_index = 0;
uint8_t unknown = 0;
int i;
for (i = 0; i < 16; i++) {
if (m4a_sample_rates[i] == h->mp4->sample_rate) {
sr_index = i;
break;
}
* 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 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++) {
if (m4a_channels[i] == h->mp4->channels) {
ch_index = i;
break;
}
}
for (int i = 0; i < 8; i++) {
if (m4a_channels[i] == h->mp4->channels) {
ch_index = i;
break;
}
config |= (object_type & 0x1F) << 11; /* 5b */
config |= (sr_index & 0x0F) << 7; /* 4b */
config |= (ch_index & 0x0F) << 3; /* 4b */
config |= (unknown & 0x07) << 0; /* 3b */
}
add_atom(h, "esds", 0x33);
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 |= (extra & 0x07) << 0; /* 3b */
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

@ -21,77 +21,77 @@
#define LIBACM_VERSION "1.1"
#define ACM_ID 0x032897
#define ACM_WORD 2
#define ACM_ID 0x032897
#define ACM_WORD 2
#define ACM_OK 0
#define ACM_ERR_OTHER -1
#define ACM_ERR_OPEN -2
#define ACM_ERR_NOT_ACM -3
#define ACM_ERR_READ_ERR -4
#define ACM_ERR_BADFMT -5
#define ACM_ERR_CORRUPT -6
#define ACM_ERR_UNEXPECTED_EOF -7
#define ACM_ERR_NOT_SEEKABLE -8
#define ACM_OK 0
#define ACM_ERR_OTHER -1
#define ACM_ERR_OPEN -2
#define ACM_ERR_NOT_ACM -3
#define ACM_ERR_READ_ERR -4
#define ACM_ERR_BADFMT -5
#define ACM_ERR_CORRUPT -6
#define ACM_ERR_UNEXPECTED_EOF -7
#define ACM_ERR_NOT_SEEKABLE -8
typedef struct ACMInfo {
unsigned channels;
unsigned rate;
unsigned acm_id;
unsigned acm_version;
unsigned acm_channels; /* channels from header (usually wrong) */
unsigned acm_level;
unsigned acm_cols; /* 1 << acm_level */
unsigned acm_rows;
unsigned channels;
unsigned rate;
unsigned acm_id;
unsigned acm_version;
unsigned acm_channels; /* channels from header (usually wrong) */
unsigned acm_level;
unsigned acm_cols; /* 1 << acm_level */
unsigned acm_rows;
} ACMInfo;
typedef struct {
/* read bytes */
int (*read_func)(void *ptr, int size, int n, void *datasrc);
/* optional, must support seeking into start*/
int (*seek_func)(void *datasrc, int offset, int whence);
/* optional, called on acm_close */
int (*close_func)(void *datasrc);
/* returns size in bytes*/
int (*get_length_func)(void *datasrc);
/* read bytes */
int (*read_func)(void *ptr, int size, int n, void *datasrc);
/* optional, must support seeking into start*/
int (*seek_func)(void *datasrc, int offset, int whence);
/* optional, called on acm_close */
int (*close_func)(void *datasrc);
/* returns size in bytes*/
int (*get_length_func)(void *datasrc);
} acm_io_callbacks;
struct ACMStream {
ACMInfo info;
unsigned total_values;
ACMInfo info;
unsigned total_values;
/* acm data stream */
void *io_arg;
acm_io_callbacks io;
unsigned data_len;
/* acm data stream */
void *io_arg;
acm_io_callbacks io;
unsigned data_len;
/* acm stream buffer */
unsigned char *buf;
unsigned buf_max, buf_size, buf_pos, bit_avail;
unsigned bit_data;
unsigned buf_start_ofs;
/* acm stream buffer */
unsigned char *buf;
unsigned buf_max, buf_size, buf_pos, bit_avail;
unsigned bit_data;
unsigned buf_start_ofs;
/* block lengths (in samples) */
unsigned block_len;
unsigned wrapbuf_len;
/* buffers */
int *block;
int *wrapbuf;
int *ampbuf;
int *midbuf; /* pointer into ampbuf */
/* result */
unsigned block_ready:1;
unsigned file_eof:1;
unsigned wavc_file:1;
unsigned stream_pos; /* in words. absolute */
unsigned block_pos; /* in words, relative */
/* block lengths (in samples) */
unsigned block_len;
unsigned wrapbuf_len;
/* buffers */
int *block;
int *wrapbuf;
int *ampbuf;
int *midbuf; /* pointer into ampbuf */
/* result */
unsigned block_ready:1;
unsigned file_eof:1;
unsigned wavc_file:1;
unsigned stream_pos; /* in words. absolute */
unsigned block_pos; /* in words, relative */
};
typedef struct ACMStream ACMStream;
/* decode.c */
int acm_open_decoder(ACMStream **res, void *io_arg, acm_io_callbacks io, int force_chans);
int acm_read(ACMStream *acm, void *buf, unsigned nbytes,
int bigendianp, int wordlen, int sgned);
int bigendianp, int wordlen, int sgned);
void acm_close(ACMStream *acm);
/* util.c */
@ -108,7 +108,7 @@ unsigned acm_pcm_tell(ACMStream *acm);
unsigned acm_time_total(ACMStream *acm);
unsigned acm_time_tell(ACMStream *acm);
int acm_read_loop(ACMStream *acm, void *dst, unsigned len,
int bigendianp, int wordlen, int sgned);
int bigendianp, int wordlen, int sgned);
int acm_seek_pcm(ACMStream *acm, unsigned pcm_pos);
int acm_seek_time(ACMStream *acm, unsigned pos_ms);
const char *acm_strerror(int err);

File diff suppressed because it is too large Load diff

View file

@ -25,30 +25,30 @@
#include "libacm.h"
#define WAVC_HEADER_LEN 28
#define ACM_HEADER_LEN 14
#define WAVC_HEADER_LEN 28
#define ACM_HEADER_LEN 14
/*
* error strings
*/
static const char *_errlist[] = {
"No error",
"ACM error",
"Cannot open file",
"Not an ACM file",
"Read error",
"Bad format",
"Corrupt file",
"Unexcpected EOF",
"Stream not seekable"
"No error",
"ACM error",
"Cannot open file",
"Not an ACM file",
"Read error",
"Bad format",
"Corrupt file",
"Unexcpected EOF",
"Stream not seekable"
};
const char *acm_strerror(int err)
{
int nerr = sizeof(_errlist) / sizeof(char *);
if ((-err) < 0 || (-err) >= nerr)
return "Unknown error";
return _errlist[-err];
int nerr = sizeof(_errlist) / sizeof(char *);
if ((-err) < 0 || (-err) >= nerr)
return "Unknown error";
return _errlist[-err];
}
/*
@ -57,61 +57,61 @@ const char *acm_strerror(int err)
static int _read_file(void *ptr, int size, int n, void *arg)
{
FILE *f = (FILE *)arg;
return fread(ptr, size, n, f);
FILE *f = (FILE *)arg;
return fread(ptr, size, n, f);
}
static int _close_file(void *arg)
{
FILE *f = (FILE *)arg;
return fclose(f);
FILE *f = (FILE *)arg;
return fclose(f);
}
static int _seek_file(void *arg, int offset, int whence)
{
FILE *f = (FILE *)arg;
return fseek(f, offset, whence);
FILE *f = (FILE *)arg;
return fseek(f, offset, whence);
}
static int _get_length_file(void *arg)
{
FILE *f = (FILE *)arg;
int res, pos, len = -1;
FILE *f = (FILE *)arg;
int res, pos, len = -1;
pos = ftell(f);
if (pos < 0)
return -1;
pos = ftell(f);
if (pos < 0)
return -1;
res = fseek(f, 0, SEEK_END);
if (res >= 0) {
len = ftell(f);
fseek(f, pos, SEEK_SET);
}
return len;
res = fseek(f, 0, SEEK_END);
if (res >= 0) {
len = ftell(f);
fseek(f, pos, SEEK_SET);
}
return len;
}
int acm_open_file(ACMStream **res, const char *filename, int force_chans)
{
int err;
FILE *f;
acm_io_callbacks io;
ACMStream *acm;
int err;
FILE *f;
acm_io_callbacks io;
ACMStream *acm;
if ((f = fopen(filename, "rb")) == NULL)
return ACM_ERR_OPEN;
if ((f = fopen(filename, "rb")) == NULL)
return ACM_ERR_OPEN;
memset(&io, 0, sizeof(io));
io.read_func = _read_file;
io.seek_func = _seek_file;
io.close_func = _close_file;
io.get_length_func = _get_length_file;
memset(&io, 0, sizeof(io));
io.read_func = _read_file;
io.seek_func = _seek_file;
io.close_func = _close_file;
io.get_length_func = _get_length_file;
if ((err = acm_open_decoder(&acm, f, io, force_chans)) < 0) {
fclose(f);
return err;
}
*res = acm;
return 0;
if ((err = acm_open_decoder(&acm, f, io, force_chans)) < 0) {
fclose(f);
return err;
}
*res = acm;
return 0;
}
/*
@ -120,14 +120,14 @@ int acm_open_file(ACMStream **res, const char *filename, int force_chans)
static unsigned pcm2time(ACMStream *acm, unsigned long long pcm)
{
return pcm * 1000 / acm->info.rate;
/* return ((10 * pcm) / acm->info.rate) * 100; */
return pcm * 1000 / acm->info.rate;
/* return ((10 * pcm) / acm->info.rate) * 100; */
}
static unsigned time2pcm(ACMStream *acm, unsigned long long time_ms)
{
return time_ms * acm->info.rate / 1000;
/* return (time_ms / 100) * (acm->info.rate / 10); */
return time_ms * acm->info.rate / 1000;
/* return (time_ms / 100) * (acm->info.rate / 10); */
}
/*
@ -136,67 +136,67 @@ static unsigned time2pcm(ACMStream *acm, unsigned long long time_ms)
const ACMInfo *acm_info(ACMStream *acm)
{
return &acm->info;
return &acm->info;
}
unsigned acm_rate(ACMStream *acm)
{
return acm->info.rate;
return acm->info.rate;
}
unsigned acm_channels(ACMStream *acm)
{
return acm->info.channels;
return acm->info.channels;
}
int acm_seekable(ACMStream *acm)
{
return acm->data_len > 0;
return acm->data_len > 0;
}
unsigned acm_bitrate(ACMStream *acm)
{
unsigned long long bits, time, bitrate = 0;
unsigned long long bits, time, bitrate = 0;
if (acm_raw_total(acm) == 0)
return 13000;
if (acm_raw_total(acm) == 0)
return 13000;
time = acm_time_total(acm);
if (time > 0) {
bits = 8 * acm_raw_total(acm);
bitrate = 1000 * bits / time;
}
return bitrate;
time = acm_time_total(acm);
if (time > 0) {
bits = 8 * acm_raw_total(acm);
bitrate = 1000 * bits / time;
}
return bitrate;
}
unsigned acm_pcm_tell(ACMStream *acm)
{
return acm->stream_pos / acm->info.channels;
return acm->stream_pos / acm->info.channels;
}
unsigned acm_pcm_total(ACMStream *acm)
{
return acm->total_values / acm->info.channels;
return acm->total_values / acm->info.channels;
}
unsigned acm_time_tell(ACMStream *acm)
{
return pcm2time(acm, acm_pcm_tell(acm));
return pcm2time(acm, acm_pcm_tell(acm));
}
unsigned acm_time_total(ACMStream *acm)
{
return pcm2time(acm, acm_pcm_total(acm));
return pcm2time(acm, acm_pcm_total(acm));
}
unsigned acm_raw_tell(ACMStream *acm)
{
return acm->buf_start_ofs + acm->buf_pos;
return acm->buf_start_ofs + acm->buf_pos;
}
unsigned acm_raw_total(ACMStream *acm)
{
return acm->data_len;
return acm->data_len;
}
/*
@ -205,74 +205,74 @@ unsigned acm_raw_total(ACMStream *acm)
int acm_seek_time(ACMStream *acm, unsigned time_ms)
{
int res = acm_seek_pcm(acm, time2pcm(acm, time_ms));
if (res <= 0)
return res;
return pcm2time(acm, res);
int res = acm_seek_pcm(acm, time2pcm(acm, time_ms));
if (res <= 0)
return res;
return pcm2time(acm, res);
}
int acm_seek_pcm(ACMStream *acm, unsigned pcm_pos)
{
unsigned word_pos = pcm_pos * acm->info.channels;
unsigned start_ofs;
unsigned word_pos = pcm_pos * acm->info.channels;
unsigned start_ofs;
if (word_pos < acm->stream_pos) {
if (acm->io.seek_func == NULL)
return ACM_ERR_NOT_SEEKABLE;
if (word_pos < acm->stream_pos) {
if (acm->io.seek_func == NULL)
return ACM_ERR_NOT_SEEKABLE;
start_ofs = ACM_HEADER_LEN;
if (acm->wavc_file)
start_ofs += WAVC_HEADER_LEN;
start_ofs = ACM_HEADER_LEN;
if (acm->wavc_file)
start_ofs += WAVC_HEADER_LEN;
if (acm->io.seek_func(acm->io_arg, start_ofs, SEEK_SET) < 0)
return ACM_ERR_NOT_SEEKABLE;
acm->file_eof = 0;
acm->buf_pos = 0;
acm->buf_size = 0;
acm->bit_avail = 0;
acm->bit_data = 0;
if (acm->io.seek_func(acm->io_arg, start_ofs, SEEK_SET) < 0)
return ACM_ERR_NOT_SEEKABLE;
acm->file_eof = 0;
acm->buf_pos = 0;
acm->buf_size = 0;
acm->bit_avail = 0;
acm->bit_data = 0;
acm->stream_pos = 0;
acm->block_pos = 0;
acm->block_ready = 0;
acm->buf_start_ofs = ACM_HEADER_LEN;
acm->stream_pos = 0;
acm->block_pos = 0;
acm->block_ready = 0;
acm->buf_start_ofs = ACM_HEADER_LEN;
memset(acm->wrapbuf, 0, acm->wrapbuf_len * sizeof(int));
}
while (acm->stream_pos < word_pos) {
int step = 2048, res;
if (acm->stream_pos + step > word_pos)
step = word_pos - acm->stream_pos;
memset(acm->wrapbuf, 0, acm->wrapbuf_len * sizeof(int));
}
while (acm->stream_pos < word_pos) {
int step = 2048, res;
if (acm->stream_pos + step > word_pos)
step = word_pos - acm->stream_pos;
res = acm_read(acm, NULL, step*2, 0,2,1);
if (res < 1)
break;
}
return acm->stream_pos / acm->info.channels;
res = acm_read(acm, NULL, step*2, 0,2,1);
if (res < 1)
break;
}
return acm->stream_pos / acm->info.channels;
}
/*
* read loop - full block reading
*/
int acm_read_loop(ACMStream *acm, void *dst, unsigned bytes,
int bigendianp, int wordlen, int sgned)
int bigendianp, int wordlen, int sgned)
{
unsigned char *dstp = dst;
int res, got = 0;
while (bytes > 0) {
res = acm_read(acm, dstp, bytes, bigendianp, wordlen, sgned);
if (res > 0) {
if (dstp)
dstp += res;
got += res;
bytes -= res;
} else {
if (res < 0 && got == 0)
return res;
break;
}
}
return got;
unsigned char *dstp = dst;
int res, got = 0;
while (bytes > 0) {
res = acm_read(acm, dstp, bytes, bigendianp, wordlen, sgned);
if (res > 0) {
if (dstp)
dstp += res;
got += res;
bytes -= res;
} else {
if (res < 0 && got == 0)
return res;
break;
}
}
return got;
}

View file

@ -1,375 +1,375 @@
/*****************************************************************************
E R I S A - L i b r a r y
-----------------------------------------------------------------------------
Copyright (C) 2002-2003 Leshade Entis, Entis-soft. All rights reserved.
*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "mio_xerisa.h"
#include "../../util/reader_get.h"
#define MIO_PACKET_BUFFER_MAX 0x20000 /* observed max is ~0x1d000 */
#define MIO_PACKET_HEADER_SIZE 0x08
#define MIO_PACKET_BYTES_MAX (32768 * 2 * 2) /* observed max: samples * channels * pcm16 */
static inline /*const*/ uint64_t get_id64le(const char* s) {
return (uint64_t)(
((uint64_t)s[7] << 56) |
((uint64_t)s[6] << 48) |
((uint64_t)s[5] << 40) |
((uint64_t)s[4] << 32) |
((uint64_t)s[3] << 24) |
((uint64_t)s[2] << 16) |
((uint64_t)s[1] << 8) |
((uint64_t)s[0] << 0)
);
}
MIOFile* MIOFile_Open() {
MIOFile* mf = calloc(1, sizeof(MIOFile));
if (!mf)
return NULL;
return mf;
}
void MIOFile_Close(MIOFile* mf) {
if (!mf) return;
free(mf->ptrWaveBuf);
free(mf->desc);
free(mf->buf);
free(mf);
}
static int read_chunk(EMC_RECORD_HEADER* rh, io_callback_t* file) {
uint8_t chunk[0x10];
int len = file->read(chunk, 1, 0x10, file->arg);
if (len != 0x10) goto fail;
rh->nRecordID = get_u64le(chunk + 0x00);
rh->nRecLength = get_u64le(chunk + 0x08);
return 1;
fail:
return 0;
}
/* reads string (possibly utf16) in the form of "KEY\r\nVAL\r\n" */
static int read_tag(char* tag, int tag_len, char* buf, int buf_len, int is_utf16le) {
int step = is_utf16le ? 2 : 1;
int buf_pos = 0;
int tag_pos = 0;
tag[0] = '\0';
while (1) {
if (buf_pos + step >= buf_len)
break;
if (tag_pos + 1 >= tag_len)
break;
char elem = buf[buf_pos++];
if (is_utf16le) /* ignore high byte for now (only seen simple tags) */
buf_pos++;
if (elem == '\0')
break;
tag[tag_pos++] = elem;
}
tag[tag_pos] = '\0';
return buf_pos;
}
static int read_int(const char* params, UDWORD *value) {
int n,m;
int temp;
m = sscanf(params, " %d%n", &temp,&n);
if (m != 1 || temp < 0)
return 0;
*value = temp;
return n;
}
/* Originally this is parsed into a list then returned when requested (ex. ERIFile::ETagInfo::GetRewindPoint)
* but pre-read to simplify. Tags format:
* - optional BOM (text is char16, possibly SHIFT-JIS), only seen files with utf-16
* - key\r\nvalue\r\n (keys usually start with '#') xN (probably null-separated but only seen 1 tag)
* - null padding (tag block is usually 0x80 even if only one short string is used) */
static void read_tags(MIOFile* mf) {
char tag[128];
int tag_len = sizeof(tag);
char* desc = mf->desc;
int desc_len = mf->desc_len;
int is_utf16le = 0;
if (desc[0] == '\xff' && desc[1] == '\xfe') {
is_utf16le = 1;
}
desc += 2;
desc_len -= 2;
while (1) {
int read = read_tag(tag, tag_len, desc, desc_len, is_utf16le);
if (read <= 0)
break;
if (memcmp(tag, "#rewind-point\r\n", 15) == 0)
read_int(tag + 15, &mf->mioih.rewindPoint);
desc += read;
desc_len -= read;
}
}
ESLError MIOFile_Initialize(MIOFile* mf, io_callback_t* file) {
EMC_RECORD_HEADER rh;
uint8_t buf[0x40];
int len, ok;
int size, to_read;
file->seek(file->arg, 0, IO_CALLBACK_SEEK_SET);
/* read base chunk */
{
to_read = 0x40;
len = file->read(buf, 1, to_read, file->arg);
if (len < to_read) goto fail;
mf->emcfh.cHeader = get_u64le(buf + 0x00);
mf->emcfh.dwFileID = get_u32le(buf + 0x08);
mf->emcfh.dwReserved = get_u32le(buf + 0x0c);
memcpy(mf->emcfh.cFormatDesc, buf + 0x10, 0x20);
/* 0x30: extra info 0x10 */
if (mf->emcfh.cHeader != get_id64le("Entis\x1a\x00\x00"))
goto fail;
/* each format has a fixed description, not checked in OG lib though */
if (memcmp(mf->emcfh.cFormatDesc, "Music Interleaved and Orthogonal", 0x20) != 0)
goto fail;
/* older files end with " transformed\0\0\0\0", and newer with null + data size */
}
/* read header chunks */
{
ok = read_chunk(&rh, file);
if (!ok) goto fail;
if (rh.nRecordID != get_id64le("Header "))
goto fail;
size = rh.nRecLength;
while (size > 0) {
ok = read_chunk(&rh, file);
if (!ok) goto fail;
size -= 0x10;
/* common info */
if (rh.nRecordID == get_id64le("FileHdr ")) {
to_read = rh.nRecLength;
if (to_read > sizeof(buf) || to_read != 0x14) goto fail;
len = file->read(buf, 1, to_read, file->arg);
if (len != to_read) goto fail;
mf->erifh.dwVersion = get_u32le(buf + 0x00);
mf->erifh.dwContainedFlag = get_u32le(buf + 0x04);
mf->erifh.dwKeyFrameCount = get_u32le(buf + 0x08);
mf->erifh.dwFrameCount = get_u32le(buf + 0x0c);
mf->erifh.dwAllFrameTime = get_u32le(buf + 0x10);
}
/* audio header */
if (rh.nRecordID == get_id64le("SoundInf")) {
to_read = rh.nRecLength;
if (to_read > sizeof(buf) || to_read != 0x28) goto fail;
len = file->read(buf, 1, to_read, file->arg);
if (len != to_read) goto fail;
mf->mioih.dwVersion = get_u32le(buf + 0x00);
mf->mioih.fdwTransformation= get_u32le(buf + 0x04);
mf->mioih.dwArchitecture = get_u32le(buf + 0x08);
mf->mioih.dwChannelCount = get_u32le(buf + 0x0c);
mf->mioih.dwSamplesPerSec = get_u32le(buf + 0x10);
mf->mioih.dwBlocksetCount = get_u32le(buf + 0x14);
mf->mioih.dwSubbandDegree = get_u32le(buf + 0x18);
mf->mioih.dwAllSampleCount = get_u32le(buf + 0x1c);
mf->mioih.dwLappedDegree = get_u32le(buf + 0x20);
mf->mioih.dwBitsPerSample = get_u32le(buf + 0x24);
}
/* other defaults */
mf->mioih.rewindPoint = -1; /* not looped (since #rewind-point 0 means loop from the beginning) */
/* tags */
if (rh.nRecordID == get_id64le("descript")) {
/* OG lib supports:
"title", "vocal-player", "composer", "arranger", "source", "track", "release-date", "genre",
"rewind-point" (loop start), "hot-spot", "resolution", "comment", "words" (lyrics)
Only seen loops though.
*/
/* sometimes chunk exists with just size 0x02 (empty but probably for BOM) */
to_read = rh.nRecLength;
if (to_read < 0x02 || to_read > 0x10000) goto fail;
mf->desc = calloc(1, to_read + 2);
if (!mf->desc) goto fail;
len = file->read(mf->desc, 1, to_read, file->arg);
if (len != to_read) goto fail;
/* doesn't always end with null */
mf->desc[to_read+0] = '\0';
mf->desc[to_read+1] = '\0';
mf->desc_len = to_read;
read_tags(mf);
}
/* other chunks (not seen / for other non-MIO formats?):
* - "PrevwInf" (image preview)
* - "ImageInf" (image header)
* - "Sequence" (image?)
* - "cpyright" (text info)
*/
size -= rh.nRecLength;
}
if (mf->erifh.dwVersion > 0x00020100) {
goto fail;
}
}
/* read file data */
{
ok = read_chunk(&rh, file);
if (!ok) goto fail;
if (rh.nRecordID != get_id64le("Stream "))
goto fail;
//printf("stream chunk reached\n");
/* packets are in "SoundStm" chunks ("ImageFrm" in images) */
mf->start = file->tell(file->arg);
}
return eslErrSuccess;
fail:
return eslErrGeneral;
}
ESLError MIOFile_Reset(MIOFile* mf, io_callback_t* file) {
if (!mf) goto fail;
file->seek(file->arg, mf->start, IO_CALLBACK_SEEK_SET);
return eslErrSuccess;
fail:
return eslErrGeneral;
}
static int parse_packet_header(uint8_t* buf, int buf_size, MIO_DATA_HEADER* dh) {
if (buf_size < MIO_PACKET_HEADER_SIZE)
goto fail;
dh->bytVersion = get_u8(buf + 0x00);
dh->bytFlags = get_u8(buf + 0x01);
dh->bytReserved1 = get_u8(buf + 0x02);
dh->bytReserved2 = get_u8(buf + 0x03);
dh->dwSampleCount = get_u32le(buf + 0x04);
return 1;
fail:
return 0;
}
ESLError MIOFile_NextPacket(MIOFile* mf, io_callback_t* file) {
EMC_RECORD_HEADER rh;
int ok, len;
ok = read_chunk(&rh, file);
if (!ok) return eslErrEof;
if (rh.nRecordID != get_id64le("SoundStm"))
goto fail;
/* prepare buf */
if (mf->buf_size < rh.nRecLength) {
if (rh.nRecLength > MIO_PACKET_BUFFER_MAX)
goto fail;
if (rh.nRecLength <= MIO_PACKET_HEADER_SIZE)
goto fail;
free(mf->buf);
mf->buf_size = rh.nRecLength;
mf->buf = malloc(mf->buf_size);
if (!mf->buf) goto fail;
}
len = file->read(mf->buf, 1, rh.nRecLength, file->arg);
if (len != rh.nRecLength) goto fail;
ok = parse_packet_header(mf->buf, rh.nRecLength, &mf->miodh);
if (!ok) goto fail;
mf->packet = mf->buf + MIO_PACKET_HEADER_SIZE;
mf->packet_size = rh.nRecLength - MIO_PACKET_HEADER_SIZE;
return eslErrSuccess;
fail:
return eslErrGeneral;
}
int MIOFile_GetTagLoop(MIOFile* mf, const char* tag) {
return mf->mioih.rewindPoint;
}
void* MIOFile_GetCurrentWaveBuffer(MIOFile* mf) {
int channels = mf->mioih.dwChannelCount;
int bps = mf->mioih.dwBitsPerSample;
int bytes_per_sample = channels * (bps / 8);
int chunk_samples = mf->miodh.dwSampleCount;
/* usually same for all except less in last packet */
UDWORD dwBytesAudio = chunk_samples * bytes_per_sample;
if (dwBytesAudio > MIO_PACKET_BYTES_MAX) goto fail;
if (dwBytesAudio > mf->ptrWaveBuf_len) {
free(mf->ptrWaveBuf);
mf->ptrWaveBuf = malloc(dwBytesAudio);
if (!mf->ptrWaveBuf) goto fail;
mf->ptrWaveBuf_len = dwBytesAudio;
}
return mf->ptrWaveBuf;
fail:
return NULL;
}
int MIOFile_GetCurrentWaveBufferCount(MIOFile* mf) {
int channels = mf->mioih.dwChannelCount;
int chunk_samples = mf->miodh.dwSampleCount;
return chunk_samples * channels;
}
/*****************************************************************************
E R I S A - L i b r a r y
-----------------------------------------------------------------------------
Copyright (C) 2002-2003 Leshade Entis, Entis-soft. All rights reserved.
*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "mio_xerisa.h"
#include "../../util/reader_get.h"
#define MIO_PACKET_BUFFER_MAX 0x20000 /* observed max is ~0x1d000 */
#define MIO_PACKET_HEADER_SIZE 0x08
#define MIO_PACKET_BYTES_MAX (32768 * 2 * 2) /* observed max: samples * channels * pcm16 */
static inline /*const*/ uint64_t get_id64le(const char* s) {
return (uint64_t)(
((uint64_t)s[7] << 56) |
((uint64_t)s[6] << 48) |
((uint64_t)s[5] << 40) |
((uint64_t)s[4] << 32) |
((uint64_t)s[3] << 24) |
((uint64_t)s[2] << 16) |
((uint64_t)s[1] << 8) |
((uint64_t)s[0] << 0)
);
}
MIOFile* MIOFile_Open() {
MIOFile* mf = calloc(1, sizeof(MIOFile));
if (!mf)
return NULL;
return mf;
}
void MIOFile_Close(MIOFile* mf) {
if (!mf) return;
free(mf->ptrWaveBuf);
free(mf->desc);
free(mf->buf);
free(mf);
}
static int read_chunk(EMC_RECORD_HEADER* rh, io_callback_t* file) {
uint8_t chunk[0x10];
int len = file->read(chunk, 1, 0x10, file->arg);
if (len != 0x10) goto fail;
rh->nRecordID = get_u64le(chunk + 0x00);
rh->nRecLength = get_u64le(chunk + 0x08);
return 1;
fail:
return 0;
}
/* reads string (possibly utf16) in the form of "KEY\r\nVAL\r\n" */
static int read_tag(char* tag, int tag_len, char* buf, int buf_len, int is_utf16le) {
int step = is_utf16le ? 2 : 1;
int buf_pos = 0;
int tag_pos = 0;
tag[0] = '\0';
while (1) {
if (buf_pos + step >= buf_len)
break;
if (tag_pos + 1 >= tag_len)
break;
char elem = buf[buf_pos++];
if (is_utf16le) /* ignore high byte for now (only seen simple tags) */
buf_pos++;
if (elem == '\0')
break;
tag[tag_pos++] = elem;
}
tag[tag_pos] = '\0';
return buf_pos;
}
static int read_int(const char* params, UDWORD *value) {
int n,m;
int temp;
m = sscanf(params, " %d%n", &temp,&n);
if (m != 1 || temp < 0)
return 0;
*value = temp;
return n;
}
/* Originally this is parsed into a list then returned when requested (ex. ERIFile::ETagInfo::GetRewindPoint)
* but pre-read to simplify. Tags format:
* - optional BOM (text is char16, possibly SHIFT-JIS), only seen files with utf-16
* - key\r\nvalue\r\n (keys usually start with '#') xN (probably null-separated but only seen 1 tag)
* - null padding (tag block is usually 0x80 even if only one short string is used) */
static void read_tags(MIOFile* mf) {
char tag[128];
int tag_len = sizeof(tag);
char* desc = mf->desc;
int desc_len = mf->desc_len;
int is_utf16le = 0;
if (desc[0] == '\xff' && desc[1] == '\xfe') {
is_utf16le = 1;
}
desc += 2;
desc_len -= 2;
while (1) {
int read = read_tag(tag, tag_len, desc, desc_len, is_utf16le);
if (read <= 0)
break;
if (memcmp(tag, "#rewind-point\r\n", 15) == 0)
read_int(tag + 15, &mf->mioih.rewindPoint);
desc += read;
desc_len -= read;
}
}
ESLError MIOFile_Initialize(MIOFile* mf, io_callback_t* file) {
EMC_RECORD_HEADER rh;
uint8_t buf[0x40];
int len, ok;
int size, to_read;
file->seek(file->arg, 0, IO_CALLBACK_SEEK_SET);
/* read base chunk */
{
to_read = 0x40;
len = file->read(buf, 1, to_read, file->arg);
if (len < to_read) goto fail;
mf->emcfh.cHeader = get_u64le(buf + 0x00);
mf->emcfh.dwFileID = get_u32le(buf + 0x08);
mf->emcfh.dwReserved = get_u32le(buf + 0x0c);
memcpy(mf->emcfh.cFormatDesc, buf + 0x10, 0x20);
/* 0x30: extra info 0x10 */
if (mf->emcfh.cHeader != get_id64le("Entis\x1a\x00\x00"))
goto fail;
/* each format has a fixed description, not checked in OG lib though */
if (memcmp(mf->emcfh.cFormatDesc, "Music Interleaved and Orthogonal", 0x20) != 0)
goto fail;
/* older files end with " transformed\0\0\0\0", and newer with null + data size */
}
/* read header chunks */
{
ok = read_chunk(&rh, file);
if (!ok) goto fail;
if (rh.nRecordID != get_id64le("Header "))
goto fail;
size = rh.nRecLength;
while (size > 0) {
ok = read_chunk(&rh, file);
if (!ok) goto fail;
size -= 0x10;
/* common info */
if (rh.nRecordID == get_id64le("FileHdr ")) {
to_read = rh.nRecLength;
if (to_read > sizeof(buf) || to_read != 0x14) goto fail;
len = file->read(buf, 1, to_read, file->arg);
if (len != to_read) goto fail;
mf->erifh.dwVersion = get_u32le(buf + 0x00);
mf->erifh.dwContainedFlag = get_u32le(buf + 0x04);
mf->erifh.dwKeyFrameCount = get_u32le(buf + 0x08);
mf->erifh.dwFrameCount = get_u32le(buf + 0x0c);
mf->erifh.dwAllFrameTime = get_u32le(buf + 0x10);
}
/* audio header */
if (rh.nRecordID == get_id64le("SoundInf")) {
to_read = rh.nRecLength;
if (to_read > sizeof(buf) || to_read != 0x28) goto fail;
len = file->read(buf, 1, to_read, file->arg);
if (len != to_read) goto fail;
mf->mioih.dwVersion = get_u32le(buf + 0x00);
mf->mioih.fdwTransformation= get_u32le(buf + 0x04);
mf->mioih.dwArchitecture = get_u32le(buf + 0x08);
mf->mioih.dwChannelCount = get_u32le(buf + 0x0c);
mf->mioih.dwSamplesPerSec = get_u32le(buf + 0x10);
mf->mioih.dwBlocksetCount = get_u32le(buf + 0x14);
mf->mioih.dwSubbandDegree = get_u32le(buf + 0x18);
mf->mioih.dwAllSampleCount = get_u32le(buf + 0x1c);
mf->mioih.dwLappedDegree = get_u32le(buf + 0x20);
mf->mioih.dwBitsPerSample = get_u32le(buf + 0x24);
}
/* other defaults */
mf->mioih.rewindPoint = -1; /* not looped (since #rewind-point 0 means loop from the beginning) */
/* tags */
if (rh.nRecordID == get_id64le("descript")) {
/* OG lib supports:
"title", "vocal-player", "composer", "arranger", "source", "track", "release-date", "genre",
"rewind-point" (loop start), "hot-spot", "resolution", "comment", "words" (lyrics)
Only seen loops though.
*/
/* sometimes chunk exists with just size 0x02 (empty but probably for BOM) */
to_read = rh.nRecLength;
if (to_read < 0x02 || to_read > 0x10000) goto fail;
mf->desc = calloc(1, to_read + 2);
if (!mf->desc) goto fail;
len = file->read(mf->desc, 1, to_read, file->arg);
if (len != to_read) goto fail;
/* doesn't always end with null */
mf->desc[to_read+0] = '\0';
mf->desc[to_read+1] = '\0';
mf->desc_len = to_read;
read_tags(mf);
}
/* other chunks (not seen / for other non-MIO formats?):
* - "PrevwInf" (image preview)
* - "ImageInf" (image header)
* - "Sequence" (image?)
* - "cpyright" (text info)
*/
size -= rh.nRecLength;
}
if (mf->erifh.dwVersion > 0x00020100) {
goto fail;
}
}
/* read file data */
{
ok = read_chunk(&rh, file);
if (!ok) goto fail;
if (rh.nRecordID != get_id64le("Stream "))
goto fail;
//printf("stream chunk reached\n");
/* packets are in "SoundStm" chunks ("ImageFrm" in images) */
mf->start = file->tell(file->arg);
}
return eslErrSuccess;
fail:
return eslErrGeneral;
}
ESLError MIOFile_Reset(MIOFile* mf, io_callback_t* file) {
if (!mf) goto fail;
file->seek(file->arg, mf->start, IO_CALLBACK_SEEK_SET);
return eslErrSuccess;
fail:
return eslErrGeneral;
}
static int parse_packet_header(uint8_t* buf, int buf_size, MIO_DATA_HEADER* dh) {
if (buf_size < MIO_PACKET_HEADER_SIZE)
goto fail;
dh->bytVersion = get_u8(buf + 0x00);
dh->bytFlags = get_u8(buf + 0x01);
dh->bytReserved1 = get_u8(buf + 0x02);
dh->bytReserved2 = get_u8(buf + 0x03);
dh->dwSampleCount = get_u32le(buf + 0x04);
return 1;
fail:
return 0;
}
ESLError MIOFile_NextPacket(MIOFile* mf, io_callback_t* file) {
EMC_RECORD_HEADER rh;
int ok, len;
ok = read_chunk(&rh, file);
if (!ok) return eslErrEof;
if (rh.nRecordID != get_id64le("SoundStm"))
goto fail;
/* prepare buf */
if (mf->buf_size < rh.nRecLength) {
if (rh.nRecLength > MIO_PACKET_BUFFER_MAX)
goto fail;
if (rh.nRecLength <= MIO_PACKET_HEADER_SIZE)
goto fail;
free(mf->buf);
mf->buf_size = rh.nRecLength;
mf->buf = malloc(mf->buf_size);
if (!mf->buf) goto fail;
}
len = file->read(mf->buf, 1, rh.nRecLength, file->arg);
if (len != rh.nRecLength) goto fail;
ok = parse_packet_header(mf->buf, rh.nRecLength, &mf->miodh);
if (!ok) goto fail;
mf->packet = mf->buf + MIO_PACKET_HEADER_SIZE;
mf->packet_size = rh.nRecLength - MIO_PACKET_HEADER_SIZE;
return eslErrSuccess;
fail:
return eslErrGeneral;
}
int MIOFile_GetTagLoop(MIOFile* mf, const char* tag) {
return mf->mioih.rewindPoint;
}
void* MIOFile_GetCurrentWaveBuffer(MIOFile* mf) {
int channels = mf->mioih.dwChannelCount;
int bps = mf->mioih.dwBitsPerSample;
int bytes_per_sample = channels * (bps / 8);
int chunk_samples = mf->miodh.dwSampleCount;
/* usually same for all except less in last packet */
UDWORD dwBytesAudio = chunk_samples * bytes_per_sample;
if (dwBytesAudio > MIO_PACKET_BYTES_MAX) goto fail;
if (dwBytesAudio > mf->ptrWaveBuf_len) {
free(mf->ptrWaveBuf);
mf->ptrWaveBuf = malloc(dwBytesAudio);
if (!mf->ptrWaveBuf) goto fail;
mf->ptrWaveBuf_len = dwBytesAudio;
}
return mf->ptrWaveBuf;
fail:
return NULL;
}
int MIOFile_GetCurrentWaveBufferCount(MIOFile* mf) {
int channels = mf->mioih.dwChannelCount;
int chunk_samples = mf->miodh.dwSampleCount;
return chunk_samples * channels;
}

File diff suppressed because it is too large Load diff

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 */
if (data->discard) {
start = data->discard;
if (start > rc)
start = rc;
data->discard -= start;
if (start == rc) /* consume all */
continue;
}
else {
start = 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
//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;
}
return;
fail:
VGM_LOG("OGG: error %lx during decode\n", rc);
memset(outbuf, 0, (samples_to_do - samples_done) * channels * sizeof(sample_t));
}
// 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;
/* 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 */
};
long rc = ov_read_float(&data->ogg_vorbis_file, &pcm_channels, max_samples, &data->bitstream);
if (rc <= 0) // rc is samples done
return false;
/* 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;
sbuf_init_flt(&ds->sbuf, data->fbuf, rc, v->channels);
ds->sbuf.filled = rc;
/* 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;
if (data->disable_reordering)
sbuf_interleave(&ds->sbuf, pcm_channels);
else
sbuf_interleave_vorbis(&ds->sbuf, pcm_channels);
*ptr = val;
ptr += channels;
}
if (data->discard) {
ds->discard = data->discard;
data->discard = 0;
}
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);
}
}
return true;
}
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;
}
}
void decode_pcm32le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i;
int32_t sample_count;
for (i=first_sample,sample_count=0; 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 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/=vgmstream->channels;
vgmstream->current_block_offset = block_offset;
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;
/* 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;
loop_flag = 0;
channel_count = read_8bit(0x0, streamFile);
data_size = read_32bitLE(0xE,streamFile);
// 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;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
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;
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;
h.stream_offset = 0x12;
h.num_samples = pcm16_bytes_to_samples(h.stream_size, channels);
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
h.coding = coding_PCM16LE;
h.layout = layout_interleave;
h.open_stream = true;
h.sf = sf;
fail:
close_vgmstream(vgmstream);
return NULL;
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)
goto fail;
/* header version, not formally specified */
if (!is_old) {
/* 0x08: size of all seek tables (XMA2, all tables go together after headers) / null */
// 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;
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

@ -1,55 +1,56 @@
#include "meta.h"
#include "../layout/layout.h"
#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) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
/* 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;
loop_flag = 0;
channel_count = 2;
start_offset = 0x40;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
vgmstream->meta_type = meta_PS2_IAB;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_ps2_iab;
//vgmstream->interleave_block_size = read_32bitLE(0x0C, streamFile); /* unneeded */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
/* calc num_samples */
{
vgmstream->next_block_offset = start_offset;
do {
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));
block_update(start_offset, vgmstream);
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../layout/layout.h"
#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_iab(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channels;
/* checks */
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;
channels = 2;
start_offset = 0x40;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
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,sf,start_offset))
goto fail;
/* calc num_samples */
{
vgmstream->next_block_offset = start_offset;
do {
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(sf));
block_update(start_offset, vgmstream);
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

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)
goto fail;
// 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,68 +1,68 @@
#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 * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
/* checks */
if (!check_extensions(streamFile, "sd9"))
goto fail;
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;
/* Some SD9s may loop without any loop points specificed.
If loop_flag is set with no points, loop entire song. */
loop_flag = read_16bitLE(0x0e,streamFile);
//loop_flag = read_32bitLE(0x18, streamFile); // use loop end
channel_count = read_16bitLE(0x36, streamFile);
start_offset = 0x7a;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, 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->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))
goto fail;
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* SD9 - from Konami arcade games [beatmania IIDX series (AC), BeatStream (AC)] */
VGMSTREAM* init_vgmstream_sd9(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channels;
/* checks */
if (!is_id32be(0x00, sf, "SD9\0"))
return NULL;
// .sd9: header ID
if (!check_extensions(sf, "sd9"))
return NULL;
// 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 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);
// 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(channels, loop_flag);
if (!vgmstream) goto fail;
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;
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->frame_size = read_u16le(0x40, sf);
if (!msadpcm_check_coefs(sf, 0x48))
goto fail;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

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

@ -1,45 +1,47 @@
#include "meta.h"
#include "../coding/coding.h"
/* .VAI - from Asobo Studio games [Ratatouille (GC)] */
VGMSTREAM * init_vgmstream_vai(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
size_t data_size;
int loop_flag, channel_count;
/* checks */
if ( !check_extensions(streamFile,"vai") )
goto fail;
start_offset = 0x4060;
data_size = get_streamfile_size(streamFile) - start_offset;
if (read_32bitBE(0x04,streamFile) != data_size)
goto fail;
channel_count = 2;
loop_flag = 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,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->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x4000;
dsp_read_coefs_be(vgmstream,streamFile,0x0c,0x20);
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* .VAI - from Asobo Studio games [Ratatouille (GC)] */
VGMSTREAM* init_vgmstream_vai(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
size_t data_size;
int loop_flag, channels;
/* checks */
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 = read_s32be(0x04,sf);
if (data_size != get_streamfile_size(sf) - start_offset)
return NULL;
channels = 2;
loop_flag = 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VAI;
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, sf, 0x0c, 0x20);
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;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
h.num_samples = ps_bytes_to_samples(h.chan_size, 1);
vgmstream->meta_type = meta_VGS;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = ps_bytes_to_samples(channel_size * channels, channels);
h.coding = coding_PSX_badflags; // flag = stream/channel number
h.layout = layout_blocked_vgs;
h.open_stream = true;
h.sf = sf;
vgmstream->coding_type = coding_PSX_badflags; /* flag = stream/channel number */
vgmstream->layout_type = layout_blocked_vgs;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
return alloc_metastream(&h);
}
/* .vgs - from Harmonix games [Karaoke Revolution (PS2), EyeToy: AntiGrav (PS2)] */
VGMSTREAM* init_vgmstream_vgs_old(STREAMFILE* sf) {
/* 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,69 +1,69 @@
#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) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, 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 ((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) == 0x786D6400) { /* "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);
/* 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);
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;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, 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->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))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#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 *sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channels, sample_rate;
size_t data_size, loop_start, frame_size;
/* checks (.xmd comes from bigfiles with filenames) */
if (!check_extensions(sf, "xmd"))
return NULL;
if ((read_u32be(0x00,sf) & 0xFFFFFF00) == get_id32be("xmd\0")) {
/* v2 from Castlevania: Curse of Darkness */
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
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(sf))
return NULL; // v1 .xmd are sector-aligned with padding
if (channels < 1 || channels > 2)
return NULL;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
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, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1,223 +1,236 @@
#include "meta.h"
#include "../coding/coding.h"
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 * vgmstream = NULL;
STREAMFILE * streamData = 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;
/* checks */
if (!check_extensions(streamFile, "xps"))
goto fail;
if (read_32bitLE(0x00,streamFile) != get_streamfile_size(streamFile))
goto fail;
if (read_32bitBE(0x0c,streamFile) != 0x64696666) /* "diff" */
goto fail;
/* handle .xps+dat (bank .xps are done below) */
streamData = open_streamfile_by_ext(streamFile, "dat");
if (!streamData) goto fail;
/* 0x00: approximate file size */
total_subsongs = read_32bitLE(0x04,streamData);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
header_offset = 0x20 + 0x94*(target_subsong-1); /* could start at 0x0c 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);
/* 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);
/* 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 */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->meta_type = meta_XPS_DAT;
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
switch(codec) {
case 0x01:
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);
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);
break;
default:
goto fail;
}
read_xps_name(vgmstream, streamFile, file_id);
if (!vgmstream_open_stream(vgmstream,streamData,start_offset))
goto fail;
close_streamfile(streamData);
return vgmstream;
fail:
close_streamfile(streamData);
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;
/* main section + stream sections (usually same number but not always) */
entries = read_32bitLE(0x04,streamFile);
/* "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);
/* 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_file_id == file_id && name_id == -1) {
name_id = entry_name_id;
}
continue;
}
/* sound stream entry, otherwise no good */
if (entry_id != 0x75647373) { /* "udss" */
goto fail;
}
udss_name_id = read_32bitLE(entry_base+0x10,streamFile);
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);
return;
}
}
fail:
return;
}
/* .XPS - From Software games banks [Metal Wolf Chaos (Xbox), Otogi (Xbox)] */
VGMSTREAM * init_vgmstream_xps(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * streamData = NULL;
int i, entries;
off_t entry_offset = 0x10;
int total_subsongs, target_subsong = streamFile->stream_index;
/* checks */
if (!check_extensions(streamFile, "xps"))
goto fail;
if (read_32bitLE(0x00,streamFile) != get_streamfile_size(streamFile))
goto fail;
if (read_32bitBE(0x0c,streamFile) != 0x64696666) /* "diff" */
goto fail;
/* handle .xps alone (stream .xps+data are done above) */
streamData = open_streamfile_by_ext(streamFile, "dat");
if (streamData) goto fail;
/* main section + bank sections (usually same number but not always) */
entries = read_32bitLE(0x04,streamFile);
total_subsongs = 0;
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 /*|| target_subsong > total_subsongs || total_subsongs < 1*/) goto fail;
/* 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) */
entry_offset += entry_size + entry_pad + 0x10;
/* sound info entry */
if (entry_id == 0x73696400) { /* "sid\0" */
/* keep looking for sound banks */
continue;
}
/* sound bank entry, otherwise no good */
if (entry_id != 0x75647362) { /* "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);
temp_streamFile = setup_subfile_streamfile(streamFile, subsong_offset,subsong_size, "wav");
if (!temp_streamFile) goto fail;
vgmstream = init_vgmstream_riff(temp_streamFile);
close_streamfile(temp_streamFile);
if (!vgmstream) goto fail;
}
}
/* subsong not found */
if (!vgmstream)
goto fail;
vgmstream->num_streams = total_subsongs;
return vgmstream;
fail:
close_streamfile(streamData);
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
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* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sf_data = NULL;
off_t start_offset, header_offset;
size_t stream_size;
int loop_flag, channels, sample_rate, codec, loop_start_sample, loop_end_sample, file_id;
/* checks */
if (read_u32le(0x00,sf) != get_streamfile_size(sf))
return NULL;
if (!check_extensions(sf, "xps"))
return NULL;
// 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)
sf_data = open_streamfile_by_ext(sf, "dat");
if (!sf_data) return NULL;
// 00: approximate file size
// 04: subsongs
// 08: type 1=dat
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) return NULL;
header_offset = 0x20 + 0x94 * (target_subsong-1); // could start at 0x0c or 0x10 too
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_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_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(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->meta_type = meta_XPS_DAT;
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
switch(codec) {
case 0x01:
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
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, channels);
break;
default:
goto fail;
}
read_xps_name(vgmstream, sf, file_id);
if (!vgmstream_open_stream(vgmstream,sf_data,start_offset))
goto fail;
close_streamfile(sf_data);
return vgmstream;
fail:
close_streamfile(sf_data);
close_vgmstream(vgmstream);
return NULL;
}
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) */
int entries = read_s32le(0x04,sf);
/* "sid\0" entries: find name_id of file_id */
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 == 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;
}
continue;
}
/* sound stream entry, otherwise no good */
if (entry_id != get_id32be("udss")) {
return;
}
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,sf);
return;
}
}
}
/* .XPS - From Software games banks [Metal Wolf Chaos (Xbox), Otogi (Xbox)] */
VGMSTREAM * init_vgmstream_xps(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sf_data = NULL;
/* checks */
if (read_u32le(0x00,sf) != get_streamfile_size(sf))
return NULL;
if (!check_extensions(sf, "xps"))
return NULL;
// 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) */
sf_data = open_streamfile_by_ext(sf, "dat");
if (sf_data) return NULL;
/* main section + bank sections (usually same number but not always) */
int entries = read_s32le(0x04,sf);
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*/)
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 */
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 == get_id32be("sid\0")) {
// 10: external id
// 14: internal id
// 30: external flag
/* keep looking for stream entries */
continue;
}
// stream entry
if (entry_id != get_id32be("udsb")) {
goto fail;
}
total_subsongs++;
/* open internal RIFF */
if (target_subsong == total_subsongs && vgmstream == NULL) {
STREAMFILE* temp_sf;
// 10: internal id
uint32_t subsong_size = read_u32le(entry_base + 0x14,sf);
uint32_t subsong_offset = entry_base + 0x18;
temp_sf = setup_subfile_streamfile(sf, subsong_offset, subsong_size, "wav");
if (!temp_sf) goto fail;
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(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

@ -1411,15 +1411,15 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush)
#ifdef MINIZ_UNALIGNED_USE_MEMCPY
static mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p)
{
mz_uint16 ret;
memcpy(&ret, p, sizeof(mz_uint16));
return ret;
mz_uint16 ret;
memcpy(&ret, p, sizeof(mz_uint16));
return ret;
}
static mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p)
{
mz_uint16 ret;
memcpy(&ret, p, sizeof(mz_uint16));
return ret;
mz_uint16 ret;
memcpy(&ret, p, sizeof(mz_uint16));
return ret;
}
#else
#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p)
@ -1527,9 +1527,9 @@ static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahe
#ifdef MINIZ_UNALIGNED_USE_MEMCPY
static mz_uint32 TDEFL_READ_UNALIGNED_WORD32(const mz_uint8* p)
{
mz_uint32 ret;
memcpy(&ret, p, sizeof(mz_uint32));
return ret;
mz_uint32 ret;
memcpy(&ret, p, sizeof(mz_uint32));
return ret;
}
#else
#define TDEFL_READ_UNALIGNED_WORD32(p) *(const mz_uint32 *)(p)
@ -1604,7 +1604,7 @@ static mz_bool tdefl_compress_fast(tdefl_compressor *d)
pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
#ifdef MINIZ_UNALIGNED_USE_MEMCPY
memcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist));
memcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist));
#else
*(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
#endif
@ -2801,7 +2801,7 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex
do
{
#ifdef MINIZ_UNALIGNED_USE_MEMCPY
memcpy(pOut_buf_cur, pSrc, sizeof(mz_uint32)*2);
memcpy(pOut_buf_cur, pSrc, sizeof(mz_uint32)*2);
#else
((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
@ -2828,7 +2828,7 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex
pOut_buf_cur[2] = pSrc[2];
pOut_buf_cur += 3;
pSrc += 3;
counter -= 3;
counter -= 3;
}
if (counter > 0)
{
@ -3802,47 +3802,47 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flag
if (extra_size_remaining)
{
const mz_uint8 *pExtra_data;
void* buf = NULL;
const mz_uint8 *pExtra_data;
void* buf = NULL;
if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size > n)
{
buf = MZ_MALLOC(ext_data_size);
if(buf==NULL)
return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size > n)
{
buf = MZ_MALLOC(ext_data_size);
if(buf==NULL)
return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size, buf, ext_data_size) != ext_data_size)
{
MZ_FREE(buf);
return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
}
if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size, buf, ext_data_size) != ext_data_size)
{
MZ_FREE(buf);
return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
}
pExtra_data = (mz_uint8*)buf;
}
else
{
pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
}
pExtra_data = (mz_uint8*)buf;
}
else
{
pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
}
do
{
mz_uint32 field_id;
mz_uint32 field_data_size;
if (extra_size_remaining < (sizeof(mz_uint16) * 2))
{
MZ_FREE(buf);
return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
}
if (extra_size_remaining < (sizeof(mz_uint16) * 2))
{
MZ_FREE(buf);
return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
}
field_id = MZ_READ_LE16(pExtra_data);
field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining)
{
MZ_FREE(buf);
return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
}
if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining)
{
MZ_FREE(buf);
return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
}
if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)
{
@ -3856,7 +3856,7 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flag
extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
} while (extra_size_remaining);
MZ_FREE(buf);
MZ_FREE(buf);
}
}
@ -4061,7 +4061,7 @@ mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename,
if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
{
MZ_FCLOSE(pFile);
MZ_FCLOSE(pFile);
return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
}
@ -6273,16 +6273,16 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n
}
#endif /* #ifndef MINIZ_NO_TIME */
if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
{
uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
uncomp_size = buf_size;
if (uncomp_size <= 3)
{
level = 0;
store_data_uncompressed = MZ_TRUE;
}
}
if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
{
uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
uncomp_size = buf_size;
if (uncomp_size <= 3)
{
level = 0;
store_data_uncompressed = MZ_TRUE;
}
}
archive_name_size = strlen(pArchive_name);
if (archive_name_size > MZ_UINT16_MAX)
@ -6298,9 +6298,9 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n
{
/* Bail early if the archive would obviously become too large */
if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size
+ MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len +
pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len
+ MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF)
+ MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len +
pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len
+ MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF)
{
pState->m_zip64 = MZ_TRUE;
/*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
@ -6399,13 +6399,13 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n
cur_archive_file_ofs += archive_name_size;
}
if (user_extra_data_len > 0)
{
if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)
return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
if (user_extra_data_len > 0)
{
if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)
return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
cur_archive_file_ofs += user_extra_data_len;
}
cur_archive_file_ofs += user_extra_data_len;
}
if (store_data_uncompressed)
{
@ -6559,8 +6559,8 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pA
{
/* Bail early if the archive would obviously become too large */
if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE
+ archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024
+ MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF)
+ archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024
+ MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF)
{
pState->m_zip64 = MZ_TRUE;
/*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
@ -6851,20 +6851,20 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pA
static size_t mz_file_read_func_stdio(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
{
MZ_FILE *pSrc_file = (MZ_FILE *)pOpaque;
mz_int64 cur_ofs = MZ_FTELL64(pSrc_file);
MZ_FILE *pSrc_file = (MZ_FILE *)pOpaque;
mz_int64 cur_ofs = MZ_FTELL64(pSrc_file);
if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET))))
return 0;
if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET))))
return 0;
return MZ_FREAD(pBuf, 1, n, pSrc_file);
return MZ_FREAD(pBuf, 1, n, pSrc_file);
}
mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)
const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)
{
return mz_zip_writer_add_read_buf_callback(pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, max_size, pFile_time, pComment, comment_size, level_and_flags,
user_extra_data, user_extra_data_len, user_extra_data_central, user_extra_data_central_len);
return mz_zip_writer_add_read_buf_callback(pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, max_size, pFile_time, pComment, comment_size, level_and_flags,
user_extra_data, user_extra_data_len, user_extra_data_central, user_extra_data_central_len);
}
mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags)
@ -7186,10 +7186,10 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *
{
/* src is zip64, dest must be zip64 */
/* name uint32_t's */
/* id 1 (optional in zip64?) */
/* crc 1 */
/* comp_size 2 */
/* name uint32_t's */
/* id 1 (optional in zip64?) */
/* crc 1 */
/* comp_size 2 */
/* uncomp_size 2 */
if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6))
{
@ -7725,7 +7725,7 @@ const char *mz_zip_get_error_string(mz_zip_error mz_err)
return "validation failed";
case MZ_ZIP_WRITE_CALLBACK_FAILED:
return "write callback failed";
case MZ_ZIP_TOTAL_ERRORS:
case MZ_ZIP_TOTAL_ERRORS:
return "total errors";
default:
break;

View file

@ -1294,13 +1294,13 @@ MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, c
#if 0
/* TODO */
typedef void *mz_zip_streaming_extract_state_ptr;
mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags);
mz_uint64 mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
mz_uint64 mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, mz_uint64 new_ofs);
size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size);
mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
typedef void *mz_zip_streaming_extract_state_ptr;
mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags);
mz_uint64 mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
mz_uint64 mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, mz_uint64 new_ofs);
size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size);
mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
#endif
/* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */
@ -1364,8 +1364,8 @@ MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const cha
/* Adds the contents of a file to an archive. This function also records the disk file's modified time into the archive. */
/* File data is supplied via a read callback function. User mz_zip_writer_add_(c)file to add a file directly.*/
MINIZ_EXPORT mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 max_size,
const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len,
const char *user_extra_data_central, mz_uint user_extra_data_central_len);
const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len,
const char *user_extra_data_central, mz_uint user_extra_data_central_len);
#ifndef MINIZ_NO_STDIO

View file

@ -1,20 +1,20 @@
#include "vorbis_codebooks.h"
int vcb_load_codebook_array(uint8_t* buf, int buf_size, uint32_t setup_id, const vcb_info_t* list, int list_length) {
for (int i = 0; i < list_length; i++) {
if (list[i].id != setup_id)
continue;
if (list[i].size > buf_size) // can't handle
return 0;
// found: copy data as-is
memcpy(buf, list[i].codebooks, list[i].size);
return list[i].size;
}
return 0;
}
#include "vorbis_codebooks.h"
int vcb_load_codebook_array(uint8_t* buf, int buf_size, uint32_t setup_id, const vcb_info_t* list, int list_length) {
for (int i = 0; i < list_length; i++) {
if (list[i].id != setup_id)
continue;
if (list[i].size > buf_size) // can't handle
return 0;
// found: copy data as-is
memcpy(buf, list[i].codebooks, list[i].size);
return list[i].size;
}
return 0;
}

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,