From 4232fb394964901ad5f187e8f86697e04bfca0b5 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Sun, 20 Apr 2025 21:33:11 -0700 Subject: [PATCH] VGMStream: Updated libvgmstream code base Updated VGMStream to r1980-242-gfccbb05f Signed-off-by: Christopher Snowhill --- .../libvgmstream.xcodeproj/project.pbxproj | 130 +- .../vgmstream/src/base/api_decode_base.c | 14 +- .../vgmstream/src/base/api_decode_open.c | 6 +- .../vgmstream/vgmstream/src/base/codec_info.c | 13 + .../vgmstream/vgmstream/src/base/codec_info.h | 2 + .../vgmstream/vgmstream/src/base/decode.c | 73 +- .../vgmstream/src/base/decode_state.h | 1 + .../vgmstream/vgmstream/src/base/info.c | 5 +- .../vgmstream/vgmstream/src/base/mixer.c | 23 +- .../vgmstream/vgmstream/src/base/render.c | 4 +- .../vgmstream/vgmstream/src/base/sbuf.c | 816 +++---- .../vgmstream/vgmstream/src/base/sbuf.h | 30 +- .../vgmstream/vgmstream/src/coding/coding.h | 22 +- .../vgmstream/src/coding/ffmpeg_decoder.c | 10 +- .../src/coding/ffmpeg_decoder_custom_mp4.c | 134 +- .../vgmstream/src/coding/libs/libacm.h | 108 +- .../vgmstream/src/coding/libs/libacm_decode.c | 1298 +++++------ .../vgmstream/src/coding/libs/libacm_util.c | 248 +-- .../src/coding/libs/mio_erisacontext.c | 1738 +++++++-------- .../vgmstream/src/coding/libs/mio_erisafile.c | 750 +++---- .../src/coding/libs/mio_erisasound.c | 1982 ++++++++--------- .../vgmstream/src/coding/mio_decoder.c | 26 +- .../vgmstream/src/coding/ogg_vorbis_decoder.c | 174 +- .../vgmstream/src/coding/pcm_decoder.c | 272 ++- .../vgmstream/src/coding/tac_decoder.c | 4 +- .../vgmstream/src/coding/ualaw_decoder.c | 84 + Frameworks/vgmstream/vgmstream/src/formats.c | 40 +- .../vgmstream/vgmstream/src/layout/blocked.c | 8 +- .../vgmstream/src/layout/blocked_filp.c | 17 +- .../vgmstream/src/layout/blocked_gsb.c | 28 - .../vgmstream/src/layout/blocked_gsnd.c | 25 + .../vgmstream/src/layout/blocked_vas_kceo.c | 22 + .../vgmstream/src/layout/blocked_xvas.c | 24 - .../vgmstream/vgmstream/src/layout/layout.h | 6 +- .../vgmstream/vgmstream/src/libvgmstream.h | 6 +- Frameworks/vgmstream/vgmstream/src/meta/2dx.c | 60 +- .../vgmstream/vgmstream/src/meta/astb.c | 35 +- .../vgmstream/vgmstream/src/meta/astl.c | 57 + .../vgmstream/vgmstream/src/meta/axhd.c | 2 +- .../src/meta/{cbx.c => chatterbox.c} | 10 +- .../vgmstream/vgmstream/src/meta/excitebots.c | 169 -- Frameworks/vgmstream/vgmstream/src/meta/ezw.c | 60 +- Frameworks/vgmstream/vgmstream/src/meta/fsb.c | 2 + Frameworks/vgmstream/vgmstream/src/meta/ghs.c | 118 +- .../vgmstream/vgmstream/src/meta/gsnd.c | 6 +- .../vgmstream/vgmstream/src/meta/hca_bf.h | 74 +- .../vgmstream/vgmstream/src/meta/hca_keys.h | 4 + .../vgmstream/src/meta/{ps2_iab.c => iab.c} | 111 +- .../vgmstream/vgmstream/src/meta/ktac.c | 58 +- Frameworks/vgmstream/vgmstream/src/meta/lps.c | 49 + .../vgmstream/vgmstream/src/meta/madp.c | 70 + Frameworks/vgmstream/vgmstream/src/meta/mca.c | 95 - .../vgmstream/vgmstream/src/meta/mcss.c | 65 + .../vgmstream/vgmstream/src/meta/meta.h | 33 +- Frameworks/vgmstream/vgmstream/src/meta/mss.c | 68 - .../vgmstream/src/meta/ngc_ffcc_str.c | 85 - .../vgmstream/vgmstream/src/meta/ngc_lps.c | 70 - .../vgmstream/src/meta/ngc_nst_dsp.c | 89 - .../vgmstream/src/meta/nst_monster.c | 48 + Frameworks/vgmstream/vgmstream/src/meta/oor.c | 8 +- .../vgmstream/vgmstream/src/meta/opus.c | 5 +- .../vgmstream/vgmstream/src/meta/pc_ast.c | 44 - .../vgmstream/vgmstream/src/meta/ps2_rnd.c | 56 - .../vgmstream/vgmstream/src/meta/ps2_vgv.c | 64 - .../vgmstream/vgmstream/src/meta/riff.c | 29 +- Frameworks/vgmstream/vgmstream/src/meta/sd9.c | 136 +- .../vgmstream/src/meta/sfx0_monster.c | 159 ++ .../vgmstream/vgmstream/src/meta/sfxb.c | 103 + .../vgmstream/src/meta/song_monster.c | 60 + .../vgmstream/vgmstream/src/meta/spsd.c | 4 +- Frameworks/vgmstream/vgmstream/src/meta/ssp.c | 74 + .../vgmstream/vgmstream/src/meta/str_sqex.c | 43 + .../vgmstream/vgmstream/src/meta/txth.c | 5 +- .../vgmstream/src/meta/txtp_process.c | 2 - Frameworks/vgmstream/vgmstream/src/meta/vai.c | 92 +- .../vgmstream/vgmstream/src/meta/vas_kceo.c | 4 +- Frameworks/vgmstream/vgmstream/src/meta/vgs.c | 102 +- Frameworks/vgmstream/vgmstream/src/meta/vgv.c | 33 + .../vgmstream/vgmstream/src/meta/wii_sng.c | 125 -- .../vgmstream/vgmstream/src/meta/xau_konami.c | 60 - Frameworks/vgmstream/vgmstream/src/meta/xmd.c | 138 +- Frameworks/vgmstream/vgmstream/src/meta/xps.c | 459 ++-- .../vgmstream/vgmstream/src/meta/xwav.c | 15 +- .../vgmstream/vgmstream/src/util/miniz.c | 152 +- .../vgmstream/vgmstream/src/util/miniz.h | 18 +- .../vgmstream/src/util/vorbis_codebooks.c | 40 +- .../vgmstream/vgmstream/src/vgmstream_init.c | 35 +- .../vgmstream/vgmstream/src/vgmstream_types.h | 52 +- 88 files changed, 5949 insertions(+), 5749 deletions(-) create mode 100644 Frameworks/vgmstream/vgmstream/src/coding/ualaw_decoder.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/layout/blocked_gsb.c create mode 100644 Frameworks/vgmstream/vgmstream/src/layout/blocked_gsnd.c create mode 100644 Frameworks/vgmstream/vgmstream/src/layout/blocked_vas_kceo.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/layout/blocked_xvas.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/astl.c rename Frameworks/vgmstream/vgmstream/src/meta/{cbx.c => chatterbox.c} (74%) delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/excitebots.c rename Frameworks/vgmstream/vgmstream/src/meta/{ps2_iab.c => iab.c} (51%) create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/lps.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/madp.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/mca.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/mcss.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/mss.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ngc_ffcc_str.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ngc_lps.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ngc_nst_dsp.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/nst_monster.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/pc_ast.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ps2_rnd.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ps2_vgv.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/sfx0_monster.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/sfxb.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/song_monster.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ssp.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/str_sqex.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/vgv.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/wii_sng.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/xau_konami.c diff --git a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj index 09ec5b5a1..eb1b0e50d 100644 --- a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj @@ -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 = ""; }; 8306B08A2098454D000302D4 /* blocked_ea_wve_au00.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ea_wve_au00.c; sourceTree = ""; }; 8306B08B2098454D000302D4 /* blocked_ea_wve_ad10.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ea_wve_ad10.c; sourceTree = ""; }; - 8306B08C2098454D000302D4 /* blocked_xvas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_xvas.c; sourceTree = ""; }; + 8306B08C2098454D000302D4 /* blocked_vas_kceo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_vas_kceo.c; sourceTree = ""; }; 8306B08D2098454D000302D4 /* blocked_ps2_iab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ps2_iab.c; sourceTree = ""; }; 8306B08E2098454E000302D4 /* blocked_adm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_adm.c; sourceTree = ""; }; 8306B08F2098454E000302D4 /* blocked_sthd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_sthd.c; sourceTree = ""; }; @@ -994,7 +995,7 @@ 8306B09D20984551000302D4 /* blocked_ws_aud.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ws_aud.c; sourceTree = ""; }; 8306B09E20984551000302D4 /* blocked_matx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_matx.c; sourceTree = ""; }; 8306B09F20984551000302D4 /* blocked_wsi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_wsi.c; sourceTree = ""; }; - 8306B0A020984551000302D4 /* blocked_gsb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_gsb.c; sourceTree = ""; }; + 8306B0A020984551000302D4 /* blocked_gsnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_gsnd.c; sourceTree = ""; }; 8306B0A120984551000302D4 /* blocked_vs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_vs.c; sourceTree = ""; }; 8306B0BD2098458B000302D4 /* ea_eaac_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ea_eaac_streamfile.h; sourceTree = ""; }; 8306B0BE2098458C000302D4 /* ngc_str_cauldron.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_str_cauldron.c; sourceTree = ""; }; @@ -1138,6 +1139,8 @@ 8346D97725BF838C00D1A8B0 /* mjb_mjh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mjb_mjh.c; sourceTree = ""; }; 8346D97825BF838C00D1A8B0 /* compresswave.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compresswave.c; sourceTree = ""; }; 834845772D27F2E9000E4928 /* decode_state.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = decode_state.h; sourceTree = ""; }; + 834960FB2DB5FD430019C8CA /* ssp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ssp.c; sourceTree = ""; }; + 834960FD2DB5FEF90019C8CA /* ualaw_decoder.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ualaw_decoder.c; sourceTree = ""; }; 8349A8E21FE6253800E26435 /* blocked_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_dec.c; sourceTree = ""; }; 8349A8E31FE6253800E26435 /* blocked_ea_1snh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ea_1snh.c; sourceTree = ""; }; 8349A8E41FE6253800E26435 /* blocked_ea_schl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ea_schl.c; sourceTree = ""; }; @@ -1145,7 +1148,7 @@ 8349A8E71FE6253900E26435 /* blocked_ea_sns.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ea_sns.c; sourceTree = ""; }; 8349A8EE1FE6257C00E26435 /* dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dec.c; sourceTree = ""; }; 8349A8EF1FE6257C00E26435 /* ezw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ezw.c; sourceTree = ""; }; - 8349A8F01FE6257C00E26435 /* pc_ast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pc_ast.c; sourceTree = ""; }; + 8349A8F01FE6257C00E26435 /* astl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = astl.c; sourceTree = ""; }; 8349A8F11FE6257D00E26435 /* sab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sab.c; sourceTree = ""; }; 8349A8F21FE6257D00E26435 /* pcm_kceje.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pcm_kceje.c; sourceTree = ""; }; 8349A8F41FE6257D00E26435 /* ubi_sb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ubi_sb.c; sourceTree = ""; }; @@ -1182,7 +1185,7 @@ 834F7D172C708701003AC386 /* awc_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = awc_streamfile.h; sourceTree = ""; }; 834F7D1A2C708719003AC386 /* cipher_xxtea.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cipher_xxtea.c; sourceTree = ""; }; 834F7D1B2C708719003AC386 /* cipher_xxtea.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cipher_xxtea.h; sourceTree = ""; }; - 834F7D242C7088B9003AC386 /* cbx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cbx.c; sourceTree = ""; }; + 834F7D242C7088B9003AC386 /* chatterbox.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = chatterbox.c; sourceTree = ""; }; 834F7D282C708A2F003AC386 /* vas_rockstar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vas_rockstar.c; sourceTree = ""; }; 834F7D2A2C708A5B003AC386 /* blocked_vas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_vas.c; sourceTree = ""; }; 834F7D2E2C708D31003AC386 /* rage_aud_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rage_aud_streamfile.h; sourceTree = ""; }; @@ -1372,7 +1375,7 @@ 834FE0CF215C79E8000A5D3D /* adpcm_capcom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adpcm_capcom.c; sourceTree = ""; }; 834FE0D0215C79E8000A5D3D /* wavebatch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wavebatch.c; sourceTree = ""; }; 834FE0D1215C79E9000A5D3D /* nus3bank.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nus3bank.c; sourceTree = ""; }; - 834FE0D2215C79E9000A5D3D /* xau_konami.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xau_konami.c; sourceTree = ""; }; + 834FE0D2215C79E9000A5D3D /* sfxb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sfxb.c; sourceTree = ""; }; 834FE0D3215C79E9000A5D3D /* vai.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vai.c; sourceTree = ""; }; 834FE0D4215C79E9000A5D3D /* vpk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vpk.c; sourceTree = ""; }; 834FE0D5215C79E9000A5D3D /* ps_headerless.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps_headerless.c; sourceTree = ""; }; @@ -1452,7 +1455,7 @@ 836F6E4318BDC2180095E648 /* dmsg_segh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dmsg_segh.c; sourceTree = ""; }; 836F6E4618BDC2180095E648 /* ea_schl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_schl.c; sourceTree = ""; }; 836F6E4918BDC2180095E648 /* exakt_sc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exakt_sc.c; sourceTree = ""; }; - 836F6E4A18BDC2180095E648 /* excitebots.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = excitebots.c; sourceTree = ""; }; + 836F6E4A18BDC2180095E648 /* sfx0_monster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sfx0_monster.c; sourceTree = ""; }; 836F6E4C18BDC2180095E648 /* fsb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fsb.c; sourceTree = ""; }; 836F6E4D18BDC2180095E648 /* gca.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gca.c; sourceTree = ""; }; 836F6E4E18BDC2180095E648 /* gcsw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gcsw.c; sourceTree = ""; }; @@ -1484,9 +1487,9 @@ 836F6E7218BDC2180095E648 /* mpds.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mpds.c; sourceTree = ""; }; 836F6E7318BDC2180095E648 /* ngc_dsp_std.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_dsp_std.c; sourceTree = ""; }; 836F6E7418BDC2180095E648 /* dsp_kceje.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dsp_kceje.c; sourceTree = ""; }; - 836F6E7518BDC2180095E648 /* ngc_ffcc_str.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_ffcc_str.c; sourceTree = ""; }; - 836F6E7718BDC2180095E648 /* ngc_lps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_lps.c; sourceTree = ""; }; - 836F6E7818BDC2180095E648 /* ngc_nst_dsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_nst_dsp.c; sourceTree = ""; }; + 836F6E7518BDC2180095E648 /* str_sqex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = str_sqex.c; sourceTree = ""; }; + 836F6E7718BDC2180095E648 /* lps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lps.c; sourceTree = ""; }; + 836F6E7818BDC2180095E648 /* nst_monster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nst_monster.c; sourceTree = ""; }; 836F6E7918BDC2180095E648 /* ngc_pdt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_pdt.c; sourceTree = ""; }; 836F6E7A18BDC2180095E648 /* ngc_sck_dsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_sck_dsp.c; sourceTree = ""; }; 836F6E7B18BDC2180095E648 /* ngc_ssm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_ssm.c; sourceTree = ""; }; @@ -1510,13 +1513,12 @@ 836F6E9D18BDC2180095E648 /* mcg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mcg.c; sourceTree = ""; }; 836F6E9E18BDC2180095E648 /* hgc1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hgc1.c; sourceTree = ""; }; 836F6E9F18BDC2180095E648 /* ps2_hsf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_hsf.c; sourceTree = ""; }; - 836F6EA018BDC2180095E648 /* ps2_iab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_iab.c; sourceTree = ""; }; + 836F6EA018BDC2180095E648 /* iab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iab.c; sourceTree = ""; }; 836F6EA218BDC2180095E648 /* ild.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ild.c; sourceTree = ""; }; 836F6EA418BDC2180095E648 /* ps2_joe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_joe.c; sourceTree = ""; }; 836F6EA618BDC2180095E648 /* vig_kces.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vig_kces.c; sourceTree = ""; }; 836F6EAC18BDC2180095E648 /* mic_koei.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mic_koei.c; sourceTree = ""; }; 836F6EB218BDC2180095E648 /* p2bt_move_visa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = p2bt_move_visa.c; sourceTree = ""; }; - 836F6EB618BDC2180095E648 /* ps2_rnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rnd.c; sourceTree = ""; }; 836F6EB818BDC2180095E648 /* rws_80d.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rws_80d.c; sourceTree = ""; }; 836F6EBA18BDC2180095E648 /* ster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ster.c; sourceTree = ""; }; 836F6EBB18BDC2180095E648 /* sl3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sl3.c; sourceTree = ""; }; @@ -1528,7 +1530,7 @@ 836F6EC818BDC2190095E648 /* vas_kceo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vas_kceo.c; sourceTree = ""; }; 836F6EC918BDC2190095E648 /* ps2_vbk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_vbk.c; sourceTree = ""; }; 836F6ECA18BDC2190095E648 /* vgs_ps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vgs_ps.c; sourceTree = ""; }; - 836F6ECB18BDC2190095E648 /* ps2_vgv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_vgv.c; sourceTree = ""; }; + 836F6ECB18BDC2190095E648 /* vgv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vgv.c; sourceTree = ""; }; 836F6ECC18BDC2190095E648 /* ps2_vms.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_vms.c; sourceTree = ""; }; 836F6ECD18BDC2190095E648 /* voi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = voi.c; sourceTree = ""; }; 836F6ECF18BDC2190095E648 /* ps2_wad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_wad.c; sourceTree = ""; }; @@ -1565,7 +1567,7 @@ 836F6F0018BDC2190095E648 /* bns.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bns.c; sourceTree = ""; }; 836F6F0118BDC2190095E648 /* mus_krome.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mus_krome.c; sourceTree = ""; }; 836F6F0218BDC2190095E648 /* ras.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ras.c; sourceTree = ""; }; - 836F6F0418BDC2190095E648 /* wii_sng.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wii_sng.c; sourceTree = ""; }; + 836F6F0418BDC2190095E648 /* song_monster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = song_monster.c; sourceTree = ""; }; 836F6F0618BDC2190095E648 /* sts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sts.c; sourceTree = ""; }; 836F6F0718BDC2190095E648 /* wpd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wpd.c; sourceTree = ""; }; 836F6F0818BDC2190095E648 /* ws_aud.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ws_aud.c; sourceTree = ""; }; @@ -1585,7 +1587,7 @@ 836F6F1D18BDC2190095E648 /* vgmstream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vgmstream.h; sourceTree = ""; }; 83709DFF1ECBC1A4005C03D3 /* ghs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ghs.c; sourceTree = ""; }; 83709E001ECBC1A4005C03D3 /* mpc3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mpc3.c; sourceTree = ""; }; - 83709E011ECBC1A4005C03D3 /* mss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mss.c; sourceTree = ""; }; + 83709E011ECBC1A4005C03D3 /* mcss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mcss.c; sourceTree = ""; }; 83709E031ECBC1A4005C03D3 /* aac_triace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aac_triace.c; sourceTree = ""; }; 8373341E23F60CDB00DE14DC /* deblock_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = deblock_streamfile.h; sourceTree = ""; }; 8373341F23F60CDB00DE14DC /* lrmd_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lrmd_streamfile.h; sourceTree = ""; }; @@ -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 = ""; }; - 83EDE5D61A70951A005F5D84 /* mca.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mca.c; sourceTree = ""; }; + 83EDE5D61A70951A005F5D84 /* madp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = madp.c; sourceTree = ""; }; 83EDE5D71A70951A005F5D84 /* btsnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = btsnd.c; sourceTree = ""; }; 83EED5D1203A8BC7008BEB45 /* ea_swvr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_swvr.c; sourceTree = ""; }; 83EED5D2203A8BC7008BEB45 /* aus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aus.c; sourceTree = ""; }; @@ -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 */, diff --git a/Frameworks/vgmstream/vgmstream/src/base/api_decode_base.c b/Frameworks/vgmstream/vgmstream/src/base/api_decode_base.c index 6a8c4d074..e5c6f6c30 100644 --- a/Frameworks/vgmstream/vgmstream/src/base/api_decode_base.c +++ b/Frameworks/vgmstream/vgmstream/src/base/api_decode_base.c @@ -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; diff --git a/Frameworks/vgmstream/vgmstream/src/base/api_decode_open.c b/Frameworks/vgmstream/vgmstream/src/base/api_decode_open.c index 0e249675d..518dd076e 100644 --- a/Frameworks/vgmstream/vgmstream/src/base/api_decode_open.c +++ b/Frameworks/vgmstream/vgmstream/src/base/api_decode_open.c @@ -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; } diff --git a/Frameworks/vgmstream/vgmstream/src/base/codec_info.c b/Frameworks/vgmstream/vgmstream/src/base/codec_info.c index a78bc829c..da61ae52a 100644 --- a/Frameworks/vgmstream/vgmstream/src/base/codec_info.c +++ b/Frameworks/vgmstream/vgmstream/src/base/codec_info.c @@ -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; } diff --git a/Frameworks/vgmstream/vgmstream/src/base/codec_info.h b/Frameworks/vgmstream/vgmstream/src/base/codec_info.h index 85c40976b..119f87f50 100644 --- a/Frameworks/vgmstream/vgmstream/src/base/codec_info.h +++ b/Frameworks/vgmstream/vgmstream/src/base/codec_info.h @@ -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) diff --git a/Frameworks/vgmstream/vgmstream/src/base/decode.c b/Frameworks/vgmstream/vgmstream/src/base/decode.c index 97d382d55..853e5fa06 100644 --- a/Frameworks/vgmstream/vgmstream/src/base/decode.c +++ b/Frameworks/vgmstream/vgmstream/src/base/decode.c @@ -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; } } diff --git a/Frameworks/vgmstream/vgmstream/src/base/decode_state.h b/Frameworks/vgmstream/vgmstream/src/base/decode_state.h index 3ad712742..655669bba 100644 --- a/Frameworks/vgmstream/vgmstream/src/base/decode_state.h +++ b/Frameworks/vgmstream/vgmstream/src/base/decode_state.h @@ -6,6 +6,7 @@ typedef struct { int discard; sbuf_t sbuf; + int samples_left; //info for some decoders } decode_state_t; #endif diff --git a/Frameworks/vgmstream/vgmstream/src/base/info.c b/Frameworks/vgmstream/vgmstream/src/base/info.c index a374e64f8..f8fcb7d5b 100644 --- a/Frameworks/vgmstream/vgmstream/src/base/info.c +++ b/Frameworks/vgmstream/vgmstream/src/base/info.c @@ -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 = "???"; } diff --git a/Frameworks/vgmstream/vgmstream/src/base/mixer.c b/Frameworks/vgmstream/vgmstream/src/base/mixer.c index 09a77ef90..642f7bb94 100644 --- a/Frameworks/vgmstream/vgmstream/src/base/mixer.c +++ b/Frameworks/vgmstream/vgmstream/src/base/mixer.c @@ -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)) diff --git a/Frameworks/vgmstream/vgmstream/src/base/render.c b/Frameworks/vgmstream/vgmstream/src/base/render.c index bdabb6e17..12a5cee52 100644 --- a/Frameworks/vgmstream/vgmstream/src/base/render.c +++ b/Frameworks/vgmstream/vgmstream/src/base/render.c @@ -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: diff --git a/Frameworks/vgmstream/vgmstream/src/base/sbuf.c b/Frameworks/vgmstream/vgmstream/src/base/sbuf.c index 070e22e9b..b97c80760 100644 --- a/Frameworks/vgmstream/vgmstream/src/base/sbuf.c +++ b/Frameworks/vgmstream/vgmstream/src/base/sbuf.c @@ -12,6 +12,119 @@ #include #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; + } + } +} diff --git a/Frameworks/vgmstream/vgmstream/src/base/sbuf.h b/Frameworks/vgmstream/vgmstream/src/base/sbuf.h index fc97f1923..74cd7d4db 100644 --- a/Frameworks/vgmstream/vgmstream/src/base/sbuf.h +++ b/Frameworks/vgmstream/vgmstream/src/base/sbuf.h @@ -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 diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding.h b/Frameworks/vgmstream/vgmstream/src/coding/coding.h index 1bb65c86a..06c53303d 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/coding.h +++ b/Frameworks/vgmstream/vgmstream/src/coding/coding.h @@ -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 diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c index 7a8e59638..182a10c03 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c @@ -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; diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_mp4.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_mp4.c index cfe6245f6..5b75b17b7 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_mp4.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_mp4.c @@ -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) { diff --git a/Frameworks/vgmstream/vgmstream/src/coding/libs/libacm.h b/Frameworks/vgmstream/vgmstream/src/coding/libs/libacm.h index a51573c2b..be23c87d6 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/libs/libacm.h +++ b/Frameworks/vgmstream/vgmstream/src/coding/libs/libacm.h @@ -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); diff --git a/Frameworks/vgmstream/vgmstream/src/coding/libs/libacm_decode.c b/Frameworks/vgmstream/vgmstream/src/coding/libs/libacm_decode.c index e3421563e..e8d7b57cc 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/libs/libacm_decode.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/libs/libacm_decode.c @@ -26,7 +26,7 @@ #include "libacm.h" -#define ACM_BUFLEN (64*1024) +#define ACM_BUFLEN (64*1024) #define ACM_EXPECTED_EOF -99 @@ -40,127 +40,127 @@ typedef int (*filler_t)(ACMStream *acm, unsigned ind, unsigned col); static int load_buf(ACMStream *acm) { - int res = 0; + int res = 0; - if (acm->file_eof) - return 0; + if (acm->file_eof) + return 0; - acm->buf_start_ofs += acm->buf_size; + acm->buf_start_ofs += acm->buf_size; - if (acm->io.read_func != NULL) - res = acm->io.read_func(acm->buf, 1, acm->buf_max, - acm->io_arg); + if (acm->io.read_func != NULL) + res = acm->io.read_func(acm->buf, 1, acm->buf_max, + acm->io_arg); - if (res < 0) - return ACM_ERR_READ_ERR; + if (res < 0) + return ACM_ERR_READ_ERR; - if (res == 0) { - acm->file_eof = 1; - /* add single zero byte */ - acm->buf[0] = 0; - acm->buf_size = 1; - } else { - acm->buf_size = res; - } - acm->buf_pos = 0; - return 0; + if (res == 0) { + acm->file_eof = 1; + /* add single zero byte */ + acm->buf[0] = 0; + acm->buf_size = 1; + } else { + acm->buf_size = res; + } + acm->buf_pos = 0; + return 0; } static int load_bits(ACMStream *acm) { - int err; - unsigned data, got; - unsigned char *p = acm->buf + acm->buf_pos; - switch (acm->buf_size - acm->buf_pos) { - default: - data = 0; - got = 0; - break; - case 1: - data = p[0]; - got = 8; - break; - case 2: - data = p[0] + (p[1] << 8); - got = 16; - break; - case 3: - data = p[0] + (p[1] << 8) + (p[2] << 16); - got = 24; - break; - } - - if ((err = load_buf(acm)) < 0) - return err; - - while (got < 32) { - if (acm->buf_size - acm->buf_pos == 0) - break; - data |= acm->buf[acm->buf_pos] << got; - got += 8; - acm->buf_pos++; - } - acm->bit_data = data; - acm->bit_avail = got; - return 0; + int err; + unsigned data, got; + unsigned char *p = acm->buf + acm->buf_pos; + switch (acm->buf_size - acm->buf_pos) { + default: + data = 0; + got = 0; + break; + case 1: + data = p[0]; + got = 8; + break; + case 2: + data = p[0] + (p[1] << 8); + got = 16; + break; + case 3: + data = p[0] + (p[1] << 8) + (p[2] << 16); + got = 24; + break; + } + + if ((err = load_buf(acm)) < 0) + return err; + + while (got < 32) { + if (acm->buf_size - acm->buf_pos == 0) + break; + data |= acm->buf[acm->buf_pos] << got; + got += 8; + acm->buf_pos++; + } + acm->bit_data = data; + acm->bit_avail = got; + return 0; } static int get_bits_reload(ACMStream *acm, unsigned bits) { - int got, err; - unsigned data, b_data, b_avail; + int got, err; + unsigned data, b_data, b_avail; - data = acm->bit_data; - got = acm->bit_avail; - bits -= got; + data = acm->bit_data; + got = acm->bit_avail; + bits -= got; - if (acm->buf_size - acm->buf_pos >= 4) { - unsigned char *p = acm->buf + acm->buf_pos; - acm->buf_pos += 4; - b_data = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); - b_avail = 32; - } else { - if ((err = load_bits(acm)) < 0) - return err; - if (acm->bit_avail < bits) - return ACM_ERR_UNEXPECTED_EOF; - b_data = acm->bit_data; - b_avail = acm->bit_avail; - } - - data |= (b_data & ((1 << bits) - 1)) << got; - acm->bit_data = b_data >> bits; - acm->bit_avail = b_avail - bits; - return data; + if (acm->buf_size - acm->buf_pos >= 4) { + unsigned char *p = acm->buf + acm->buf_pos; + acm->buf_pos += 4; + b_data = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); + b_avail = 32; + } else { + if ((err = load_bits(acm)) < 0) + return err; + if (acm->bit_avail < bits) + return ACM_ERR_UNEXPECTED_EOF; + b_data = acm->bit_data; + b_avail = acm->bit_avail; + } + + data |= (b_data & ((1 << bits) - 1)) << got; + acm->bit_data = b_data >> bits; + acm->bit_avail = b_avail - bits; + return data; } #define GET_BITS_NOERR(tmpval, acm, bits) do { \ - if (acm->bit_avail >= bits) { \ - tmpval = acm->bit_data & ((1 << bits) - 1); \ - acm->bit_data >>= bits; \ - acm->bit_avail -= bits; \ - } else \ - tmpval = get_bits_reload(acm, bits); \ - } while (0) + if (acm->bit_avail >= bits) { \ + tmpval = acm->bit_data & ((1 << bits) - 1); \ + acm->bit_data >>= bits; \ + acm->bit_avail -= bits; \ + } else \ + tmpval = get_bits_reload(acm, bits); \ + } while (0) #define GET_BITS(res, acm, bits) do { \ - int tmpval; \ - GET_BITS_NOERR(tmpval, acm, bits); \ - if (tmpval < 0) \ - return tmpval; \ - res = tmpval; \ - } while (0) + int tmpval; \ + GET_BITS_NOERR(tmpval, acm, bits); \ + if (tmpval < 0) \ + return tmpval; \ + res = tmpval; \ + } while (0) #define GET_BITS_EXPECT_EOF(res, acm, bits) do { \ - int tmpval; \ - GET_BITS_NOERR(tmpval, acm, bits); \ - if (tmpval < 0) { \ - if (tmpval == ACM_ERR_UNEXPECTED_EOF) \ - return ACM_EXPECTED_EOF; \ - return tmpval; \ - } \ - res = tmpval; \ - } while (0) + int tmpval; \ + GET_BITS_NOERR(tmpval, acm, bits); \ + if (tmpval < 0) { \ + if (tmpval == ACM_ERR_UNEXPECTED_EOF) \ + return ACM_EXPECTED_EOF; \ + return tmpval; \ + } \ + res = tmpval; \ + } while (0) /************************************************* * Table filling @@ -176,347 +176,347 @@ static int tables_generated; static void generate_tables(void) { - int x1, x2, x3; - if (tables_generated) - return; - for (x3 = 0; x3 < 3; x3++) - for (x2 = 0; x2 < 3; x2++) - for (x1 = 0; x1 < 3; x1++) - mul_3x3[x1 + x2*3 + x3*3*3] = - x1 + (x2 << 4) + (x3 << 8); - for (x3 = 0; x3 < 5; x3++) - for (x2 = 0; x2 < 5; x2++) - for (x1 = 0; x1 < 5; x1++) - mul_3x5[x1 + x2*5 + x3*5*5] = - x1 + (x2 << 4) + (x3 << 8); - for (x2 = 0; x2 < 11; x2++) - for (x1 = 0; x1 < 11; x1++) - mul_2x11[x1 + x2*11] = x1 + (x2 << 4); + int x1, x2, x3; + if (tables_generated) + return; + for (x3 = 0; x3 < 3; x3++) + for (x2 = 0; x2 < 3; x2++) + for (x1 = 0; x1 < 3; x1++) + mul_3x3[x1 + x2*3 + x3*3*3] = + x1 + (x2 << 4) + (x3 << 8); + for (x3 = 0; x3 < 5; x3++) + for (x2 = 0; x2 < 5; x2++) + for (x1 = 0; x1 < 5; x1++) + mul_3x5[x1 + x2*5 + x3*5*5] = + x1 + (x2 << 4) + (x3 << 8); + for (x2 = 0; x2 < 11; x2++) + for (x1 = 0; x1 < 11; x1++) + mul_2x11[x1 + x2*11] = x1 + (x2 << 4); - tables_generated = 1; + tables_generated = 1; } /* IOW: (r * acm->subblock_len) + c */ #define set_pos(acm, r, c, idx) do { \ - unsigned _pos = ((r) << acm->info.acm_level) + (c); \ - acm->block[_pos] = acm->midbuf[idx]; \ - } while (0) + unsigned _pos = ((r) << acm->info.acm_level) + (c); \ + acm->block[_pos] = acm->midbuf[idx]; \ + } while (0) /************ Fillers **********/ static int f_zero(ACMStream *acm, unsigned ind, unsigned col) { - unsigned i; - for (i = 0; i < acm->info.acm_rows; i++) - set_pos(acm, i, col, 0); - - return 1; + unsigned i; + for (i = 0; i < acm->info.acm_rows; i++) + set_pos(acm, i, col, 0); + + return 1; } static int f_bad(ACMStream *acm, unsigned ind, unsigned col) { - /* corrupt block? */ - return ACM_ERR_CORRUPT; + /* corrupt block? */ + return ACM_ERR_CORRUPT; } static int f_linear(ACMStream *acm, unsigned ind, unsigned col) { - unsigned int i; - int b, middle = 1 << (ind - 1); + unsigned int i; + int b, middle = 1 << (ind - 1); - for (i = 0; i < acm->info.acm_rows; i++) { - GET_BITS(b, acm, ind); - set_pos(acm, i, col, b - middle); - } - return 1; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, ind); + set_pos(acm, i, col, b - middle); + } + return 1; } static int f_k13(ACMStream *acm, unsigned ind, unsigned col) { - unsigned i, b; - for (i = 0; i < acm->info.acm_rows; i++) { - GET_BITS(b, acm, 1); - if (b == 0) { - /* 0 */ - set_pos(acm, i++, col, 0); - if (i >= acm->info.acm_rows) - break; - set_pos(acm, i, col, 0); - continue; - } - GET_BITS(b, acm, 1); - if (b == 0) { - /* 1, 0 */ - set_pos(acm, i, col, 0); - continue; - } - /* 1, 1, ? */ - GET_BITS(b, acm, 1); - set_pos(acm, i, col, map_1bit[b]); - } - return 1; + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i++, col, 0); + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i, col, 0); + continue; + } + GET_BITS(b, acm, 1); + if (b == 0) { + /* 1, 0 */ + set_pos(acm, i, col, 0); + continue; + } + /* 1, 1, ? */ + GET_BITS(b, acm, 1); + set_pos(acm, i, col, map_1bit[b]); + } + return 1; } static int f_k12(ACMStream *acm, unsigned ind, unsigned col) { - unsigned i, b; - for (i = 0; i < acm->info.acm_rows; i++) { - GET_BITS(b, acm, 1); - if (b == 0) { - /* 0 */ - set_pos(acm, i, col, 0); - continue; - } - - /* 1, ? */ - GET_BITS(b, acm, 1); - set_pos(acm, i, col, map_1bit[b]); - } - return 1; + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i, col, 0); + continue; + } + + /* 1, ? */ + GET_BITS(b, acm, 1); + set_pos(acm, i, col, map_1bit[b]); + } + return 1; } static int f_k24(ACMStream *acm, unsigned ind, unsigned col) { - unsigned i, b; - for (i = 0; i < acm->info.acm_rows; i++) { - GET_BITS(b, acm, 1); - if (b == 0) { - /* 0 */ - set_pos(acm, i++, col, 0); - if (i >= acm->info.acm_rows) break; - set_pos(acm, i, col, 0); - continue; - } - - GET_BITS(b, acm, 1); - if (b == 0) { - /* 1, 0 */ - set_pos(acm, i, col, 0); - continue; - } - - /* 1, 1, ?, ? */ - GET_BITS(b, acm, 2); - set_pos(acm, i, col, map_2bit_near[b]); - } - return 1; + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i++, col, 0); + if (i >= acm->info.acm_rows) break; + set_pos(acm, i, col, 0); + continue; + } + + GET_BITS(b, acm, 1); + if (b == 0) { + /* 1, 0 */ + set_pos(acm, i, col, 0); + continue; + } + + /* 1, 1, ?, ? */ + GET_BITS(b, acm, 2); + set_pos(acm, i, col, map_2bit_near[b]); + } + return 1; } static int f_k23(ACMStream *acm, unsigned ind, unsigned col) { - unsigned i, b; - for (i = 0; i < acm->info.acm_rows; i++) { - GET_BITS(b, acm, 1); - if (b == 0) { - /* 0 */ - set_pos(acm, i, col, 0); - continue; - } + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i, col, 0); + continue; + } - /* 1, ?, ? */ - GET_BITS(b, acm, 2); - set_pos(acm, i, col, map_2bit_near[b]); - } - return 1; + /* 1, ?, ? */ + GET_BITS(b, acm, 2); + set_pos(acm, i, col, map_2bit_near[b]); + } + return 1; } static int f_k35(ACMStream *acm, unsigned ind, unsigned col) { - unsigned i, b; - for (i = 0; i < acm->info.acm_rows; i++) { - GET_BITS(b, acm, 1); - if (b == 0) { - /* 0 */ - set_pos(acm, i++, col, 0); - if (i >= acm->info.acm_rows) - break; - set_pos(acm, i, col, 0); - continue; - } - - GET_BITS(b, acm, 1); - if (b == 0) { - /* 1, 0 */ - set_pos(acm, i, col, 0); - continue; - } - - GET_BITS(b, acm, 1); - if (b == 0) { - /* 1, 1, 0, ? */ - GET_BITS(b, acm, 1); - set_pos(acm, i, col, map_1bit[b]); - continue; - } - - /* 1, 1, 1, ?, ? */ - GET_BITS(b, acm, 2); - set_pos(acm, i, col, map_2bit_far[b]); - } - return 1; + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i++, col, 0); + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i, col, 0); + continue; + } + + GET_BITS(b, acm, 1); + if (b == 0) { + /* 1, 0 */ + set_pos(acm, i, col, 0); + continue; + } + + GET_BITS(b, acm, 1); + if (b == 0) { + /* 1, 1, 0, ? */ + GET_BITS(b, acm, 1); + set_pos(acm, i, col, map_1bit[b]); + continue; + } + + /* 1, 1, 1, ?, ? */ + GET_BITS(b, acm, 2); + set_pos(acm, i, col, map_2bit_far[b]); + } + return 1; } static int f_k34(ACMStream *acm, unsigned ind, unsigned col) { - unsigned i, b; - for (i = 0; i < acm->info.acm_rows; i++) { - GET_BITS(b, acm, 1); - if (b == 0) { - /* 0 */ - set_pos(acm, i, col, 0); - continue; - } - - GET_BITS(b, acm, 1); - if (b == 0) { - /* 1, 0, ? */ - GET_BITS(b, acm, 1); - set_pos(acm, i, col, map_1bit[b]); - continue; - } - - /* 1, 1, ?, ? */ - GET_BITS(b, acm, 2); - set_pos(acm, i, col, map_2bit_far[b]); - } - return 1; + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i, col, 0); + continue; + } + + GET_BITS(b, acm, 1); + if (b == 0) { + /* 1, 0, ? */ + GET_BITS(b, acm, 1); + set_pos(acm, i, col, map_1bit[b]); + continue; + } + + /* 1, 1, ?, ? */ + GET_BITS(b, acm, 2); + set_pos(acm, i, col, map_2bit_far[b]); + } + return 1; } static int f_k45(ACMStream *acm, unsigned ind, unsigned col) { - unsigned i, b; - for (i = 0; i < acm->info.acm_rows; i++) { - GET_BITS(b, acm, 1); - if (b == 0) { - /* 0 */ - set_pos(acm, i, col, 0); i++; - if (i >= acm->info.acm_rows) - break; - set_pos(acm, i, col, 0); - continue; - } - - GET_BITS(b, acm, 1); - if (b == 0) { - /* 1, 0 */ - set_pos(acm, i, col, 0); - continue; - } - - /* 1, 1, ?, ?, ? */ - GET_BITS(b, acm, 3); - set_pos(acm, i, col, map_3bit[b]); - } - return 1; + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i, col, 0); i++; + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i, col, 0); + continue; + } + + GET_BITS(b, acm, 1); + if (b == 0) { + /* 1, 0 */ + set_pos(acm, i, col, 0); + continue; + } + + /* 1, 1, ?, ?, ? */ + GET_BITS(b, acm, 3); + set_pos(acm, i, col, map_3bit[b]); + } + return 1; } static int f_k44(ACMStream *acm, unsigned ind, unsigned col) { - unsigned i, b; - for (i = 0; i < acm->info.acm_rows; i++) { - GET_BITS(b, acm, 1); - if (b == 0) { - /* 0 */ - set_pos(acm, i, col, 0); - continue; - } - - /* 1, ?, ?, ? */ - GET_BITS(b, acm, 3); - set_pos(acm, i, col, map_3bit[b]); - } - return 1; + unsigned i, b; + for (i = 0; i < acm->info.acm_rows; i++) { + GET_BITS(b, acm, 1); + if (b == 0) { + /* 0 */ + set_pos(acm, i, col, 0); + continue; + } + + /* 1, ?, ?, ? */ + GET_BITS(b, acm, 3); + set_pos(acm, i, col, map_3bit[b]); + } + return 1; } static int f_t15(ACMStream *acm, unsigned ind, unsigned col) { - unsigned i, b; - int n1, n2, n3; - for (i = 0; i < acm->info.acm_rows; i++) { - /* b = (x1) + (x2 * 3) + (x3 * 9) */ - GET_BITS(b, acm, 5); - - n1 = (mul_3x3[b] & 0x0F) - 1; - n2 = ((mul_3x3[b] >> 4) & 0x0F) - 1; - n3 = ((mul_3x3[b] >> 8) & 0x0F) - 1; - - set_pos(acm, i++, col, n1); - if (i >= acm->info.acm_rows) - break; - set_pos(acm, i++, col, n2); - if (i >= acm->info.acm_rows) - break; - set_pos(acm, i, col, n3); - } - return 1; + unsigned i, b; + int n1, n2, n3; + for (i = 0; i < acm->info.acm_rows; i++) { + /* b = (x1) + (x2 * 3) + (x3 * 9) */ + GET_BITS(b, acm, 5); + + n1 = (mul_3x3[b] & 0x0F) - 1; + n2 = ((mul_3x3[b] >> 4) & 0x0F) - 1; + n3 = ((mul_3x3[b] >> 8) & 0x0F) - 1; + + set_pos(acm, i++, col, n1); + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i++, col, n2); + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i, col, n3); + } + return 1; } static int f_t27(ACMStream *acm, unsigned ind, unsigned col) { - unsigned i, b; - int n1, n2, n3; - for (i = 0; i < acm->info.acm_rows; i++) { - /* b = (x1) + (x2 * 5) + (x3 * 25) */ - GET_BITS(b, acm, 7); + unsigned i, b; + int n1, n2, n3; + for (i = 0; i < acm->info.acm_rows; i++) { + /* b = (x1) + (x2 * 5) + (x3 * 25) */ + GET_BITS(b, acm, 7); - n1 = (mul_3x5[b] & 0x0F) - 2; - n2 = ((mul_3x5[b] >> 4) & 0x0F) - 2; - n3 = ((mul_3x5[b] >> 8) & 0x0F) - 2; - - set_pos(acm, i++, col, n1); - if (i >= acm->info.acm_rows) - break; - set_pos(acm, i++, col, n2); - if (i >= acm->info.acm_rows) - break; - set_pos(acm, i, col, n3); - } - return 1; + n1 = (mul_3x5[b] & 0x0F) - 2; + n2 = ((mul_3x5[b] >> 4) & 0x0F) - 2; + n3 = ((mul_3x5[b] >> 8) & 0x0F) - 2; + + set_pos(acm, i++, col, n1); + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i++, col, n2); + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i, col, n3); + } + return 1; } static int f_t37(ACMStream *acm, unsigned ind, unsigned col) { - unsigned i, b; - int n1, n2; - for (i = 0; i < acm->info.acm_rows; i++) { - /* b = (x1) + (x2 * 11) */ - GET_BITS(b, acm, 7); - - n1 = (mul_2x11[b] & 0x0F) - 5; - n2 = ((mul_2x11[b] >> 4) & 0x0F) - 5; - - set_pos(acm, i++, col, n1); - if (i >= acm->info.acm_rows) - break; - set_pos(acm, i, col, n2); - } - return 1; + unsigned i, b; + int n1, n2; + for (i = 0; i < acm->info.acm_rows; i++) { + /* b = (x1) + (x2 * 11) */ + GET_BITS(b, acm, 7); + + n1 = (mul_2x11[b] & 0x0F) - 5; + n2 = ((mul_2x11[b] >> 4) & 0x0F) - 5; + + set_pos(acm, i++, col, n1); + if (i >= acm->info.acm_rows) + break; + set_pos(acm, i, col, n2); + } + return 1; } /****************/ static const filler_t filler_list[] = { - f_zero, f_bad, f_bad, f_linear, /* 0..3 */ - f_linear, f_linear, f_linear, f_linear, /* 4..7 */ - f_linear, f_linear, f_linear, f_linear, /* 8..11 */ - f_linear, f_linear, f_linear, f_linear, /* 12..15 */ - f_linear, f_k13, f_k12, f_t15, /* 16..19 */ - f_k24, f_k23, f_t27, f_k35, /* 20..23 */ - f_k34, f_bad, f_k45, f_k44, /* 24..27 */ - f_bad, f_t37, f_bad, f_bad /* 28..31 */ + f_zero, f_bad, f_bad, f_linear, /* 0..3 */ + f_linear, f_linear, f_linear, f_linear, /* 4..7 */ + f_linear, f_linear, f_linear, f_linear, /* 8..11 */ + f_linear, f_linear, f_linear, f_linear, /* 12..15 */ + f_linear, f_k13, f_k12, f_t15, /* 16..19 */ + f_k24, f_k23, f_t27, f_k35, /* 20..23 */ + f_k34, f_bad, f_k45, f_k44, /* 24..27 */ + f_bad, f_t37, f_bad, f_bad /* 28..31 */ }; static int fill_block(ACMStream *acm) { - unsigned i, ind; - int err; - for (i = 0; i < acm->info.acm_cols; i++) { - GET_BITS_EXPECT_EOF(ind, acm, 5); - err = filler_list[ind](acm, ind, i); - if (err < 0) - return err; - } - return 1; + unsigned i, ind; + int err; + for (i = 0; i < acm->info.acm_cols; i++) { + GET_BITS_EXPECT_EOF(ind, acm, 5); + err = filler_list[ind](acm, ind, i); + if (err < 0) + return err; + } + return 1; } /********************************************** @@ -525,106 +525,106 @@ static int fill_block(ACMStream *acm) static void juggle(int *wrap_p, int *block_p, unsigned sub_len, unsigned sub_count) { - unsigned int i, j; - int *p, r0, r1, r2, r3; - for (i = 0; i < sub_len; i++) { - p = block_p; - r0 = wrap_p[0]; - r1 = wrap_p[1]; - for (j = 0; j < sub_count/2; j++) { - r2 = *p; *p = r1*2 + (r0 + r2); p += sub_len; - r3 = *p; *p = r2*2 - (r1 + r3); p += sub_len; - r0 = r2; r1 = r3; - } - *wrap_p++ = r0; - *wrap_p++ = r1; - block_p++; - } + unsigned int i, j; + int *p, r0, r1, r2, r3; + for (i = 0; i < sub_len; i++) { + p = block_p; + r0 = wrap_p[0]; + r1 = wrap_p[1]; + for (j = 0; j < sub_count/2; j++) { + r2 = *p; *p = r1*2 + (r0 + r2); p += sub_len; + r3 = *p; *p = r2*2 - (r1 + r3); p += sub_len; + r0 = r2; r1 = r3; + } + *wrap_p++ = r0; + *wrap_p++ = r1; + block_p++; + } } static void juggle_block(ACMStream *acm) { - unsigned sub_count, sub_len, todo_count, step_subcount, i; - int *wrap_p, *block_p, *p; - - /* juggle only if subblock_len > 1 */ - if (acm->info.acm_level == 0) - return; + unsigned sub_count, sub_len, todo_count, step_subcount, i; + int *wrap_p, *block_p, *p; + + /* juggle only if subblock_len > 1 */ + if (acm->info.acm_level == 0) + return; - /* 2048 / subblock_len */ - if (acm->info.acm_level > 9) - step_subcount = 1; - else - step_subcount = (2048 >> acm->info.acm_level) - 2; + /* 2048 / subblock_len */ + if (acm->info.acm_level > 9) + step_subcount = 1; + else + step_subcount = (2048 >> acm->info.acm_level) - 2; - /* Apply juggle() (rows)x(cols) - * from (step_subcount * 2) x (subblock_len/2) - * to (step_subcount * subblock_len) x (1) - */ - todo_count = acm->info.acm_rows; - block_p = acm->block; - while (1) { - wrap_p = acm->wrapbuf; - sub_count = step_subcount; - if (sub_count > todo_count) - sub_count = todo_count; + /* Apply juggle() (rows)x(cols) + * from (step_subcount * 2) x (subblock_len/2) + * to (step_subcount * subblock_len) x (1) + */ + todo_count = acm->info.acm_rows; + block_p = acm->block; + while (1) { + wrap_p = acm->wrapbuf; + sub_count = step_subcount; + if (sub_count > todo_count) + sub_count = todo_count; - sub_len = acm->info.acm_cols / 2; - sub_count *= 2; - - juggle(wrap_p, block_p, sub_len, sub_count); - wrap_p += sub_len*2; - - for (i = 0, p = block_p; i < sub_count; i++) { - p[0]++; - p += sub_len; - } - - while (sub_len > 1) { - sub_len /= 2; - sub_count *= 2; - juggle(wrap_p, block_p, sub_len, sub_count); - wrap_p += sub_len*2; - } - if (todo_count <= step_subcount) - break; - todo_count -= step_subcount; - block_p += step_subcount << acm->info.acm_level; - } + sub_len = acm->info.acm_cols / 2; + sub_count *= 2; + + juggle(wrap_p, block_p, sub_len, sub_count); + wrap_p += sub_len*2; + + for (i = 0, p = block_p; i < sub_count; i++) { + p[0]++; + p += sub_len; + } + + while (sub_len > 1) { + sub_len /= 2; + sub_count *= 2; + juggle(wrap_p, block_p, sub_len, sub_count); + wrap_p += sub_len*2; + } + if (todo_count <= step_subcount) + break; + todo_count -= step_subcount; + block_p += step_subcount << acm->info.acm_level; + } } /***************************************************************/ static int decode_block(ACMStream *acm) { - int pwr, count, val, i, x, err; + int pwr, count, val, i, x, err; - acm->block_ready = 0; - acm->block_pos = 0; + acm->block_ready = 0; + acm->block_pos = 0; - /* read header */ - GET_BITS_EXPECT_EOF(pwr, acm, 4); - GET_BITS_EXPECT_EOF(val, acm, 16); + /* read header */ + GET_BITS_EXPECT_EOF(pwr, acm, 4); + GET_BITS_EXPECT_EOF(val, acm, 16); - /* generate tables */ - count = 1 << pwr; - for (i = 0, x = 0; i < count; i++) { - acm->midbuf[i] = x; - x += val; - } - for (i = 1, x = -val; i <= count; i++) { - acm->midbuf[-i] = x; - x -= val; - } + /* generate tables */ + count = 1 << pwr; + for (i = 0, x = 0; i < count; i++) { + acm->midbuf[i] = x; + x += val; + } + for (i = 1, x = -val; i <= count; i++) { + acm->midbuf[-i] = x; + x -= val; + } - /* to_check? */ - if ((err = fill_block(acm)) <= 0) - return err; + /* to_check? */ + if ((err = fill_block(acm)) <= 0) + return err; - juggle_block(acm); + juggle_block(acm); - acm->block_ready = 1; + acm->block_ready = 1; - return 1; + return 1; } /****************************** @@ -633,64 +633,64 @@ static int decode_block(ACMStream *acm) static unsigned char *out_s16le(int *src, unsigned char *dst, unsigned n, unsigned shift) { - while (n--) { - int val = *src++ >> shift; - *dst++ = val & 0xFF; - *dst++ = (val >> 8) & 0xFF; - } - return dst; + while (n--) { + int val = *src++ >> shift; + *dst++ = val & 0xFF; + *dst++ = (val >> 8) & 0xFF; + } + return dst; } static unsigned char *out_s16be(int *src, unsigned char *dst, unsigned n, unsigned shift) { - while (n--) { - int val = *src++ >> shift; - *dst++ = (val >> 8) & 0xFF; - *dst++ = val & 0xFF; - } - return dst; + while (n--) { + int val = *src++ >> shift; + *dst++ = (val >> 8) & 0xFF; + *dst++ = val & 0xFF; + } + return dst; } static unsigned char *out_u16le(int *src, unsigned char *dst, unsigned n, unsigned shift) { - while (n--) { - int val = (*src++ >> shift) + 0x8000; - *dst++ = val & 0xFF; - *dst++ = (val >> 8) & 0xFF; - } - return dst; + while (n--) { + int val = (*src++ >> shift) + 0x8000; + *dst++ = val & 0xFF; + *dst++ = (val >> 8) & 0xFF; + } + return dst; } static unsigned char *out_u16be(int *src, unsigned char *dst, unsigned n, unsigned shift) { - while (n--) { - int val = (*src++ >> shift) + 0x8000; - *dst++ = (val >> 8) & 0xFF; - *dst++ = val & 0xFF; - } - return dst; + while (n--) { + int val = (*src++ >> shift) + 0x8000; + *dst++ = (val >> 8) & 0xFF; + *dst++ = val & 0xFF; + } + return dst; } static int output_values(int *src, unsigned char *dst, int n, - int acm_level, int bigendianp, int wordlen, int sgned) + int acm_level, int bigendianp, int wordlen, int sgned) { - unsigned char *res = NULL; - if (wordlen == 2) { - if (bigendianp == 0) { - if (sgned) - res = out_s16le(src, dst, n, acm_level); - else - res = out_u16le(src, dst, n, acm_level); - } else { - if (sgned) - res = out_s16be(src, dst, n, acm_level); - else - res = out_u16be(src, dst, n, acm_level); - } - } - if (res != NULL) - return res - dst; - return ACM_ERR_BADFMT; + unsigned char *res = NULL; + if (wordlen == 2) { + if (bigendianp == 0) { + if (sgned) + res = out_s16le(src, dst, n, acm_level); + else + res = out_u16le(src, dst, n, acm_level); + } else { + if (sgned) + res = out_s16be(src, dst, n, acm_level); + else + res = out_u16be(src, dst, n, acm_level); + } + } + if (res != NULL) + return res - dst; + return ACM_ERR_BADFMT; } /* @@ -703,69 +703,69 @@ static int output_values(int *src, unsigned char *dst, int n, static int read_wavc_header(ACMStream *acm) { - static const unsigned short expect[12] = { - /* 'V1.0', raw_size, acm_size */ - 0x3156, 0x302E, 0,0, 0,0, - /* hdrlen?, chans?, bits?, hz */ - 28,0, 1, 16, 22050, 0 - }; - unsigned short i, buf[12]; + static const unsigned short expect[12] = { + /* 'V1.0', raw_size, acm_size */ + 0x3156, 0x302E, 0,0, 0,0, + /* hdrlen?, chans?, bits?, hz */ + 28,0, 1, 16, 22050, 0 + }; + unsigned short i, buf[12]; - for (i = 0; i < 12; i++) - GET_BITS(buf[i], acm, 16); - if (memcmp(buf, expect, 4) != 0) - return -1; - /* full comparision is too strict */ - if (0 && memcmp(buf + 6, expect + 6, 12) != 0) - return -1; - /* just make sure the magic 28 is there */ - if (expect[6] != buf[6]) - return -1; + for (i = 0; i < 12; i++) + GET_BITS(buf[i], acm, 16); + if (memcmp(buf, expect, 4) != 0) + return -1; + /* full comparision is too strict */ + if (0 && memcmp(buf + 6, expect + 6, 12) != 0) + return -1; + /* just make sure the magic 28 is there */ + if (expect[6] != buf[6]) + return -1; - acm->wavc_file = 1; - return 0; + acm->wavc_file = 1; + return 0; } static int read_header(ACMStream *acm) { - unsigned int tmp; + unsigned int tmp; - /* read header */ + /* read header */ - GET_BITS(tmp, acm, 24); - if (tmp == WAVC_ID) { - GET_BITS(tmp, acm, 8); - if (tmp != 'C') - return ACM_ERR_NOT_ACM; - if (read_wavc_header(acm) < 0) - return ACM_ERR_NOT_ACM; - GET_BITS(tmp, acm, 24); - } - if (tmp != ACM_ID) - return ACM_ERR_NOT_ACM; - acm->info.acm_id = tmp; + GET_BITS(tmp, acm, 24); + if (tmp == WAVC_ID) { + GET_BITS(tmp, acm, 8); + if (tmp != 'C') + return ACM_ERR_NOT_ACM; + if (read_wavc_header(acm) < 0) + return ACM_ERR_NOT_ACM; + GET_BITS(tmp, acm, 24); + } + if (tmp != ACM_ID) + return ACM_ERR_NOT_ACM; + acm->info.acm_id = tmp; - GET_BITS(acm->info.acm_version, acm, 8); - if (acm->info.acm_version != 1) - return ACM_ERR_NOT_ACM; - GET_BITS(acm->total_values, acm, 16); - GET_BITS(tmp, acm, 16); - acm->total_values += tmp << 16; - if (acm->total_values == 0) - return ACM_ERR_NOT_ACM; - GET_BITS(acm->info.channels, acm, 16); - if (acm->info.channels < 1 || acm->info.channels > 2) - return ACM_ERR_NOT_ACM; - acm->info.acm_channels = acm->info.channels; - GET_BITS(acm->info.rate, acm, 16); - if (acm->info.rate < 4096) - return ACM_ERR_NOT_ACM; - - GET_BITS(acm->info.acm_level, acm, 4); - GET_BITS(acm->info.acm_rows, acm, 12); - if (!acm->info.acm_rows) - return ACM_ERR_NOT_ACM; - return 0; + GET_BITS(acm->info.acm_version, acm, 8); + if (acm->info.acm_version != 1) + return ACM_ERR_NOT_ACM; + GET_BITS(acm->total_values, acm, 16); + GET_BITS(tmp, acm, 16); + acm->total_values += tmp << 16; + if (acm->total_values == 0) + return ACM_ERR_NOT_ACM; + GET_BITS(acm->info.channels, acm, 16); + if (acm->info.channels < 1 || acm->info.channels > 2) + return ACM_ERR_NOT_ACM; + acm->info.acm_channels = acm->info.channels; + GET_BITS(acm->info.rate, acm, 16); + if (acm->info.rate < 4096) + return ACM_ERR_NOT_ACM; + + GET_BITS(acm->info.acm_level, acm, 4); + GET_BITS(acm->info.acm_rows, acm, 12); + if (!acm->info.acm_rows) + return ACM_ERR_NOT_ACM; + return 0; } /*********************************************** @@ -774,139 +774,139 @@ static int read_header(ACMStream *acm) int acm_open_decoder(ACMStream **res, void *arg, acm_io_callbacks io_cb, int force_chans) { - int err = ACM_ERR_OTHER; - ACMStream *acm; - - acm = malloc(sizeof(*acm)); - if (!acm) - return err; - memset(acm, 0, sizeof(*acm)); + int err = ACM_ERR_OTHER; + ACMStream *acm; + + acm = malloc(sizeof(*acm)); + if (!acm) + return err; + memset(acm, 0, sizeof(*acm)); - acm->io_arg = arg; - acm->io = io_cb; + acm->io_arg = arg; + acm->io = io_cb; - if (acm->io.get_length_func) { - acm->data_len = acm->io.get_length_func(acm->io_arg); - } else { - acm->data_len = 0; - } - - acm->buf_max = ACM_BUFLEN; - acm->buf = malloc(acm->buf_max); - if (!acm->buf) - goto err_out; + if (acm->io.get_length_func) { + acm->data_len = acm->io.get_length_func(acm->io_arg); + } else { + acm->data_len = 0; + } + + acm->buf_max = ACM_BUFLEN; + acm->buf = malloc(acm->buf_max); + if (!acm->buf) + goto err_out; - /* read header data */ - err = ACM_ERR_NOT_ACM; - if (read_header(acm) < 0) - goto err_out; + /* read header data */ + err = ACM_ERR_NOT_ACM; + if (read_header(acm) < 0) + goto err_out; - /* - * Overwrite channel info if requested, otherwise - * ignore the channel count on plain ACM files, - * it is frequently wrong, and actual 1-channel - * files are not interising to listen to anyway (samples). - * - * Trust WAVC files, as they seem to be correct? - */ - if (force_chans > 0) - acm->info.channels = force_chans; - else if (!acm->wavc_file && acm->info.channels < 2) - acm->info.channels = 2; + /* + * Overwrite channel info if requested, otherwise + * ignore the channel count on plain ACM files, + * it is frequently wrong, and actual 1-channel + * files are not interising to listen to anyway (samples). + * + * Trust WAVC files, as they seem to be correct? + */ + if (force_chans > 0) + acm->info.channels = force_chans; + else if (!acm->wavc_file && acm->info.channels < 2) + acm->info.channels = 2; - /* calculate blocks */ - acm->info.acm_cols = 1 << acm->info.acm_level; - acm->wrapbuf_len = 2 * acm->info.acm_cols - 2; - acm->block_len = acm->info.acm_rows * acm->info.acm_cols; + /* calculate blocks */ + acm->info.acm_cols = 1 << acm->info.acm_level; + acm->wrapbuf_len = 2 * acm->info.acm_cols - 2; + acm->block_len = acm->info.acm_rows * acm->info.acm_cols; - /* allocate */ - acm->block = malloc(acm->block_len * sizeof(int)); - acm->wrapbuf = malloc(acm->wrapbuf_len * sizeof(int)); - acm->ampbuf = malloc(0x10000 * sizeof(int)); - acm->midbuf = acm->ampbuf + 0x8000; + /* allocate */ + acm->block = malloc(acm->block_len * sizeof(int)); + acm->wrapbuf = malloc(acm->wrapbuf_len * sizeof(int)); + acm->ampbuf = malloc(0x10000 * sizeof(int)); + acm->midbuf = acm->ampbuf + 0x8000; - memset(acm->wrapbuf, 0, acm->wrapbuf_len * sizeof(int)); + memset(acm->wrapbuf, 0, acm->wrapbuf_len * sizeof(int)); - generate_tables(); + generate_tables(); - *res = acm; - return ACM_OK; + *res = acm; + return ACM_OK; err_out: - /* disable callbacks */ - memset(&acm->io, 0, sizeof(acm->io)); - acm->io_arg = NULL; + /* disable callbacks */ + memset(&acm->io, 0, sizeof(acm->io)); + acm->io_arg = NULL; - acm_close(acm); - return err; + acm_close(acm); + return err; } int acm_read(ACMStream *acm, void *dst, unsigned numbytes, - int bigendianp, int wordlen, int sgned) + int bigendianp, int wordlen, int sgned) { - int avail, gotbytes = 0, err; - int *src, numwords; + int avail, gotbytes = 0, err; + int *src, numwords; - if (wordlen == 2) - numwords = numbytes / 2; - else - return ACM_ERR_BADFMT; + if (wordlen == 2) + numwords = numbytes / 2; + else + return ACM_ERR_BADFMT; - if (acm->stream_pos >= acm->total_values) - return 0; + if (acm->stream_pos >= acm->total_values) + return 0; - if (!acm->block_ready) { - err = decode_block(acm); - if (err == ACM_EXPECTED_EOF) - return 0; - if (err < 0) - return err; - } + if (!acm->block_ready) { + err = decode_block(acm); + if (err == ACM_EXPECTED_EOF) + return 0; + if (err < 0) + return err; + } - /* check how many words can be read */ - avail = acm->block_len - acm->block_pos; - if (avail < numwords) - numwords = avail; + /* check how many words can be read */ + avail = acm->block_len - acm->block_pos; + if (avail < numwords) + numwords = avail; - if (acm->stream_pos + numwords > acm->total_values) - numwords = acm->total_values - acm->stream_pos; + if (acm->stream_pos + numwords > acm->total_values) + numwords = acm->total_values - acm->stream_pos; - if (acm->info.channels > 1) - numwords -= numwords % acm->info.channels; + if (acm->info.channels > 1) + numwords -= numwords % acm->info.channels; - /* convert, but if dst == NULL, simulate */ - if (dst != NULL) { - src = acm->block + acm->block_pos; - gotbytes = output_values(src, dst, numwords, - acm->info.acm_level, - bigendianp, wordlen, sgned); - } else - gotbytes = numwords * wordlen; + /* convert, but if dst == NULL, simulate */ + if (dst != NULL) { + src = acm->block + acm->block_pos; + gotbytes = output_values(src, dst, numwords, + acm->info.acm_level, + bigendianp, wordlen, sgned); + } else + gotbytes = numwords * wordlen; - if (gotbytes >= 0) { - acm->stream_pos += numwords; - acm->block_pos += numwords; - if (acm->block_pos == acm->block_len) - acm->block_ready = 0; - } + if (gotbytes >= 0) { + acm->stream_pos += numwords; + acm->block_pos += numwords; + if (acm->block_pos == acm->block_len) + acm->block_ready = 0; + } - return gotbytes; + return gotbytes; } void acm_close(ACMStream *acm) { - if (acm == NULL) - return; - if (acm->io.close_func) - acm->io.close_func(acm->io_arg); - if (acm->buf) - free(acm->buf); - if (acm->block) - free(acm->block); - if (acm->wrapbuf) - free(acm->wrapbuf); - if (acm->ampbuf) - free(acm->ampbuf); - free(acm); + if (acm == NULL) + return; + if (acm->io.close_func) + acm->io.close_func(acm->io_arg); + if (acm->buf) + free(acm->buf); + if (acm->block) + free(acm->block); + if (acm->wrapbuf) + free(acm->wrapbuf); + if (acm->ampbuf) + free(acm->ampbuf); + free(acm); } diff --git a/Frameworks/vgmstream/vgmstream/src/coding/libs/libacm_util.c b/Frameworks/vgmstream/vgmstream/src/coding/libs/libacm_util.c index 57e917432..2864a3ea4 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/libs/libacm_util.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/libs/libacm_util.c @@ -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; } diff --git a/Frameworks/vgmstream/vgmstream/src/coding/libs/mio_erisacontext.c b/Frameworks/vgmstream/vgmstream/src/coding/libs/mio_erisacontext.c index 759734a4e..4e1e19431 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/libs/mio_erisacontext.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/libs/mio_erisacontext.c @@ -1,869 +1,869 @@ -/***************************************************************************** - E R I S A - L i b r a r y - ----------------------------------------------------------------------------- - Copyright (C) 2002-2003 Leshade Entis, Entis-soft. All rights reserved. - *****************************************************************************/ - -#include -#include "mio_xerisa.h" - -#define MIO_ERISA_SYMBOL_ERROR -1 - -/************************/ -/* huffman tree helpers */ -/************************/ - -static void EHT_Initialize(ERINA_HUFFMAN_TREE* tree) { - for (int i = 0; i < MIO_HUFFMAN_SYMBOLS; i++) { - tree->m_iSymLookup[i] = ERINA_HUFFMAN_NULL; - } - tree->m_iEscape = ERINA_HUFFMAN_NULL; - tree->m_iTreePointer = ERINA_HUFFMAN_ROOT; - tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight = 0; - tree->m_hnTree[ERINA_HUFFMAN_ROOT].parent = ERINA_HUFFMAN_NULL; - tree->m_hnTree[ERINA_HUFFMAN_ROOT].child_code = ERINA_HUFFMAN_NULL; -} - -static void EHT_RecountOccuredCount(ERINA_HUFFMAN_TREE* tree, int iParent) { - int iChild = tree->m_hnTree[iParent].child_code; - tree->m_hnTree[iParent].weight = tree->m_hnTree[iChild].weight + tree->m_hnTree[iChild + 1].weight; -} - -static void EHT_Normalize(ERINA_HUFFMAN_TREE* tree, int iEntry) { - while (iEntry < ERINA_HUFFMAN_ROOT) { - // find swap entry - int iSwap = iEntry + 1; - WORD weight = tree->m_hnTree[iEntry].weight; - while (iSwap < ERINA_HUFFMAN_ROOT) { - if (tree->m_hnTree[iSwap].weight >= weight) break; - ++iSwap; - } - if (iEntry == --iSwap) { - iEntry = tree->m_hnTree[iEntry].parent; - EHT_RecountOccuredCount(tree, iEntry); - continue; - } - - // swap - int iChild, nCode; - if (!(tree->m_hnTree[iEntry].child_code & ERINA_CODE_FLAG)) { - iChild = tree->m_hnTree[iEntry].child_code; - tree->m_hnTree[iChild].parent = iSwap; - tree->m_hnTree[iChild + 1].parent = iSwap; - } - else { - nCode = tree->m_hnTree[iEntry].child_code & ~ERINA_CODE_FLAG; - if (nCode != ERINA_HUFFMAN_ESCAPE) - tree->m_iSymLookup[nCode & 0xFF] = iSwap; - else - tree->m_iEscape = iSwap; - } - if (!(tree->m_hnTree[iSwap].child_code & ERINA_CODE_FLAG)) { - int iChild = tree->m_hnTree[iSwap].child_code; - tree->m_hnTree[iChild].parent = iEntry; - tree->m_hnTree[iChild + 1].parent = iEntry; - } - else { - int nCode = tree->m_hnTree[iSwap].child_code & ~ERINA_CODE_FLAG; - if (nCode != ERINA_HUFFMAN_ESCAPE) - tree->m_iSymLookup[nCode & 0xFF] = iEntry; - else - tree->m_iEscape = iEntry; - } - - ERINA_HUFFMAN_NODE node; - WORD iEntryParent = tree->m_hnTree[iEntry].parent; - WORD iSwapParent = tree->m_hnTree[iSwap].parent; - node = tree->m_hnTree[iSwap]; - tree->m_hnTree[iSwap] = tree->m_hnTree[iEntry]; - tree->m_hnTree[iEntry] = node; - tree->m_hnTree[iSwap].parent = iSwapParent; - tree->m_hnTree[iEntry].parent = iEntryParent; - - // recalc parent weight - EHT_RecountOccuredCount(tree, iSwapParent); - iEntry = iSwapParent; - } -} - -static void EHT_AddNewEntry(ERINA_HUFFMAN_TREE* tree, int nNewCode) { - if (tree->m_iTreePointer > 0) { - // reserve 2 areas - int i = tree->m_iTreePointer = tree->m_iTreePointer - 2; - - // setup new entry - ERINA_HUFFMAN_NODE* phnNew = &tree->m_hnTree[i]; - phnNew->weight = 1; - phnNew->child_code = ERINA_CODE_FLAG | nNewCode; - tree->m_iSymLookup[nNewCode & 0xFF] = i; - - ERINA_HUFFMAN_NODE* phnRoot = &tree->m_hnTree[ERINA_HUFFMAN_ROOT]; - if (phnRoot->child_code != ERINA_HUFFMAN_NULL) { - // add new entry - ERINA_HUFFMAN_NODE* phnParent = &tree->m_hnTree[i + 2]; - ERINA_HUFFMAN_NODE* phnChild = &tree->m_hnTree[i + 1]; - tree->m_hnTree[i + 1] = tree->m_hnTree[i + 2]; - - if (phnChild->child_code & ERINA_CODE_FLAG) { - int nCode = phnChild->child_code & ~ERINA_CODE_FLAG; - if (nCode != ERINA_HUFFMAN_ESCAPE) - tree->m_iSymLookup[nCode & 0xFF] = i + 1; - else - tree->m_iEscape = i + 1; - } - - phnParent->weight = phnNew->weight + phnChild->weight; - phnParent->parent = phnChild->parent; - phnParent->child_code = i; - - phnNew->parent = phnChild->parent = i + 2; - - // fix parent entry - EHT_Normalize(tree, i + 2); - } - else { - // create initial tree state - phnNew->parent = ERINA_HUFFMAN_ROOT; - - ERINA_HUFFMAN_NODE* phnEscape = &tree->m_hnTree[tree->m_iEscape = i + 1]; - phnEscape->weight = 1; - phnEscape->parent = ERINA_HUFFMAN_ROOT; - phnEscape->child_code = ERINA_CODE_FLAG | ERINA_HUFFMAN_ESCAPE; - - phnRoot->weight = 2; - phnRoot->child_code = i; - } - } - else { - // replace least ocurring symbol with new symbol - int i = tree->m_iTreePointer; - ERINA_HUFFMAN_NODE* phnEntry = &tree->m_hnTree[i]; - if (phnEntry->child_code == (ERINA_CODE_FLAG | ERINA_HUFFMAN_ESCAPE)) { - phnEntry = &tree->m_hnTree[i + 1]; - } - phnEntry->child_code = ERINA_CODE_FLAG | nNewCode; - } -} - -static void EHT_HalfAndRebuild(ERINA_HUFFMAN_TREE* tree) { - // halve ocurrence count and rebuild the tree - int iNextEntry = ERINA_HUFFMAN_ROOT; - for (int i = ERINA_HUFFMAN_ROOT - 1; i >= tree->m_iTreePointer; i--) { - if (tree->m_hnTree[i].child_code & ERINA_CODE_FLAG) { - tree->m_hnTree[i].weight = (tree->m_hnTree[i].weight + 1) >> 1; - tree->m_hnTree[iNextEntry--] = tree->m_hnTree[i]; - } - } - ++iNextEntry; - - // rebuild tree - int iChild, nCode; - int i = tree->m_iTreePointer; - for (;;) { - // put the smallest 2 entries into the huffman tree - tree->m_hnTree[i] = tree->m_hnTree[iNextEntry]; - tree->m_hnTree[i + 1] = tree->m_hnTree[iNextEntry + 1]; - iNextEntry += 2; - ERINA_HUFFMAN_NODE* phnChild1 = &tree->m_hnTree[i]; - ERINA_HUFFMAN_NODE* phnChild2 = &tree->m_hnTree[i + 1]; - - if (!(phnChild1->child_code & ERINA_CODE_FLAG)) { - iChild = phnChild1->child_code; - tree->m_hnTree[iChild].parent = i; - tree->m_hnTree[iChild + 1].parent = i; - } - else { - nCode = phnChild1->child_code & ~ERINA_CODE_FLAG; - if (nCode == ERINA_HUFFMAN_ESCAPE) - tree->m_iEscape = i; - else - tree->m_iSymLookup[nCode & 0xFF] = i; - } - - if (!(phnChild2->child_code & ERINA_CODE_FLAG)) { - iChild = phnChild2->child_code; - tree->m_hnTree[iChild].parent = i + 1; - tree->m_hnTree[iChild + 1].parent = i + 1; - } - else { - nCode = phnChild2->child_code & ~ERINA_CODE_FLAG; - if (nCode == ERINA_HUFFMAN_ESCAPE) - tree->m_iEscape = i + 1; - else - tree->m_iSymLookup[nCode & 0xFF] = i + 1; - } - - WORD weight = phnChild1->weight + phnChild2->weight; - - // include parent entry in list - if (iNextEntry <= ERINA_HUFFMAN_ROOT) { - int j = iNextEntry; - for (;;) { - if (weight <= tree->m_hnTree[j].weight) { - tree->m_hnTree[j - 1].weight = weight; - tree->m_hnTree[j - 1].child_code = i; - break; - } - tree->m_hnTree[j - 1] = tree->m_hnTree[j]; - if (++j > ERINA_HUFFMAN_ROOT) { - tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight = weight; - tree->m_hnTree[ERINA_HUFFMAN_ROOT].child_code = i; - break; - } - } - --iNextEntry; - } - else { - tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight = weight; - tree->m_hnTree[ERINA_HUFFMAN_ROOT].parent = ERINA_HUFFMAN_NULL; - tree->m_hnTree[ERINA_HUFFMAN_ROOT].child_code = i; - phnChild1->parent = ERINA_HUFFMAN_ROOT; - phnChild2->parent = ERINA_HUFFMAN_ROOT; - break; - } - - i += 2; - } -} - -static void EHT_IncreaseOccuredCount(ERINA_HUFFMAN_TREE* tree, int iEntry) { - tree->m_hnTree[iEntry].weight++; - EHT_Normalize(tree, iEntry); - - if (tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight >= ERINA_HUFFMAN_MAX) { - EHT_HalfAndRebuild(tree); - } -} - -/*****************************/ -/* arithmetic coding helpers */ -/*****************************/ - -static void EPM_Initialize(ERISA_PROB_MODEL* prob) { - prob->dwTotalCount = ERISA_SYMBOL_SORTS; - prob->dwSymbolSorts = ERISA_SYMBOL_SORTS; - - for (int i = 0; i < 0x100; i++) { - prob->acsSymTable[i].wOccured = 1; - prob->acsSymTable[i].wSymbol = (SWORD)(BYTE)i; - } - prob->acsSymTable[0x100].wOccured = 1; - prob->acsSymTable[0x100].wSymbol = (SWORD)ERISA_ESCAPE_CODE; - - for (int i = 0; i < ERISA_SUB_SORT_MAX; i++) { - prob->acsSubModel[i].wOccured = 0; - prob->acsSubModel[i].wSymbol = (SWORD)-1; - } -} - -static void EPM_HalfOccuredCount(ERISA_PROB_MODEL* prob) { - UDWORD i; - - prob->dwTotalCount = 0; - for (i = 0; i < prob->dwSymbolSorts; i++) { - prob->dwTotalCount += prob->acsSymTable[i].wOccured = ((prob->acsSymTable[i].wOccured + 1) >> 1); - } - for (i = 0; i < ERISA_SUB_SORT_MAX; i++) { - prob->acsSubModel[i].wOccured >>= 1; - } -} - -static int EPM_IncreaseSymbol(ERISA_PROB_MODEL* prob, int index) { - WORD wOccured = ++prob->acsSymTable[index].wOccured; - SWORD wSymbol = prob->acsSymTable[index].wSymbol; - - while (--index >= 0) { - if (prob->acsSymTable[index].wOccured >= wOccured) - break; - prob->acsSymTable[index + 1] = prob->acsSymTable[index]; - } - prob->acsSymTable[++index].wOccured = wOccured; - prob->acsSymTable[index].wSymbol = wSymbol; - - if (++prob->dwTotalCount >= ERISA_TOTAL_LIMIT) { - EPM_HalfOccuredCount(prob); - } - - return index; -} - -/**************************/ -/* general decode context */ -/**************************/ - -ULONG MIOContext_DecodeSymbolBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount) { - - /* (assert) */ - if (context->m_pfnDecodeSymbolBytes == NULL) - return 0; - - return (context->m_pfnDecodeSymbolBytes)(context, ptrDst, nCount); -} - - -static const SBYTE /*BYTE*/ nGammaCodeLookup[512] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 6, 8, 6, 8, 6, 8, 6, 16, 8, -1, -1, 17, 8, -1, -1, 9, 6, 9, 6, 9, 6, 9, 6, 18, - 8, -1, -1, 19, 8, -1, -1, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, - 5, 4, 10, 6, 10, 6, 10, 6, 10, 6, 20, 8, -1, -1, 21, 8, -1, -1, 11, 6, 11, 6, 11, 6, 11, 6, 22, 8, -1, -1, 23, 8, -1, -1, 3, 2, 3, - 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, - 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, - 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, - 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, - 4, 6, 4, 6, 4, 6, 4, 6, 4, 12, 6, 12, 6, 12, 6, 12, 6, 24, 8, -1, -1, 25, 8, -1, -1, 13, 6, 13, 6, 13, 6, 13, 6, 26, 8, -1, -1, - 27, 8, -1, -1, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 14, - 6, 14, 6, 14, 6, 14, 6, 28, 8, -1, -1, 29, 8, -1, -1, 15, 6, 15, 6, 15, 6, 15, 6, 30, 8, -1, -1, 31, 8, -1, -1 -}; - - -static ESLError MIOContext_PrefetchBuffer(MIOContext* context) { - if (context->m_nIntBufCount != 0) - return eslErrSuccess; - - if (context->m_pFilePos >= context->m_pFileLength) - return eslErrGeneral; - - // read next int32 BE - int dwLeft = context->m_pFileLength - context->m_pFilePos; - if (dwLeft < 4) { - // read partially at buffer edge - context->m_dwIntBuffer = 0; - for (int i = 0; i < dwLeft; i++) { - context->m_dwIntBuffer |= (UDWORD)context->m_pFileBuf[context->m_pFilePos + i] << (24 - 8*i); - } - context->m_pFilePos += dwLeft; - } - else { - context->m_dwIntBuffer = - ((UDWORD)context->m_pFileBuf[context->m_pFilePos + 0] << 24) | - ((UDWORD)context->m_pFileBuf[context->m_pFilePos + 1] << 16) | - ((UDWORD)context->m_pFileBuf[context->m_pFilePos + 2] << 8) | - ((UDWORD)context->m_pFileBuf[context->m_pFilePos + 3]); - context->m_pFilePos += 4; - } - - // get next int32 - context->m_nIntBufCount = 32; - - return eslErrSuccess; -} - -int MIOContext_GetABit(MIOContext* context) { - if (MIOContext_PrefetchBuffer(context)) { - return 1; // on error does return 1 - } - - // returns one bit ("0 or -1" according to original comment) - int nValue = (int)(((SDWORD)context->m_dwIntBuffer) >> 31); - --context->m_nIntBufCount; - context->m_dwIntBuffer <<= 1; - return nValue; -} - -UINT MIOContext_GetNBits(MIOContext* context, int n) { - UINT nCode = 0; - while (n != 0) { - if (MIOContext_PrefetchBuffer(context)) - break; - - int nCopyBits = n; - if (nCopyBits > context->m_nIntBufCount) - nCopyBits = context->m_nIntBufCount; - - nCode = (nCode << nCopyBits) | (context->m_dwIntBuffer >> (32 - nCopyBits)); - n -= nCopyBits; - context->m_nIntBufCount -= nCopyBits; - context->m_dwIntBuffer <<= nCopyBits; - } - return nCode; -} - -static int MIOContext_GetGammaCode(MIOContext* context) { - // test 1 - if (MIOContext_PrefetchBuffer(context)) { - return 0; - } - - /*register*/ UDWORD dwIntBuf; - context->m_nIntBufCount--; - dwIntBuf = context->m_dwIntBuffer; - context->m_dwIntBuffer <<= 1; - if (!(dwIntBuf & 0x80000000)) { - return 1; - } - - - // test end code - if (MIOContext_PrefetchBuffer(context)) { - return 0; - } - - if ((~context->m_dwIntBuffer & 0x55000000) && (context->m_nIntBufCount >= 8)) { - int i = (context->m_dwIntBuffer >> 24) << 1; - int nCode = nGammaCodeLookup[i]; - int nBitCount = nGammaCodeLookup[i + 1]; - - /* (assert) */ - if (nBitCount > context->m_nIntBufCount || nCode <= 0) - return 0; - - context->m_nIntBufCount -= nBitCount; - context->m_dwIntBuffer <<= nBitCount; - return nCode; - } - - // regular routine - int nCode = 0, nBase = 2; - for (;;) { - if (context->m_nIntBufCount >= 2) { - // process 2 bits - dwIntBuf = context->m_dwIntBuffer; - context->m_dwIntBuffer <<= 2; - nCode = (nCode << 1) | (dwIntBuf >> 31); - context->m_nIntBufCount -= 2; - if (!(dwIntBuf & 0x40000000)) { - return nCode + nBase; - } - nBase <<= 1; - } - else { - // extract 1-bit - if (MIOContext_PrefetchBuffer(context)) { - return 0; - } - nCode = (nCode << 1) | (context->m_dwIntBuffer >> 31); - context->m_nIntBufCount--; - context->m_dwIntBuffer <<= 1; - - // test end code - if (MIOContext_PrefetchBuffer(context)) { - return 0; - } - - dwIntBuf = context->m_dwIntBuffer; - context->m_nIntBufCount--; - context->m_dwIntBuffer <<= 1; - if (!(dwIntBuf & 0x80000000)) { - return nCode + nBase; - } - nBase <<= 1; - } - } -} - -/* original clones this into 2 functions with different escape codes but here we use a flag */ -static int MIOContext_GetHuffmanCommon(MIOContext* context, ERINA_HUFFMAN_TREE* tree, int escapeGamma) { - // get one huffman code - int nCode; - if (tree->m_iEscape != ERINA_HUFFMAN_NULL) { - int iEntry = ERINA_HUFFMAN_ROOT; - int iChild = tree->m_hnTree[ERINA_HUFFMAN_ROOT].child_code; - - // decode codes - do { - if (MIOContext_PrefetchBuffer(context)) { - return ERINA_HUFFMAN_ESCAPE; - } - - // extract 1-bit - iEntry = iChild + (context->m_dwIntBuffer >> 31); - --context->m_nIntBufCount; - iChild = tree->m_hnTree[iEntry].child_code; - context->m_dwIntBuffer <<= 1; - } while (!(iChild & ERINA_CODE_FLAG)); - - // increase code occurence - if ((context->m_dwERINAFlags != ERINAEncodingFlag_efERINAOrder0) || (tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight < ERINA_HUFFMAN_MAX - 1)) { - EHT_IncreaseOccuredCount(tree, iEntry); - } - - // regular code - nCode = iChild & ~ERINA_CODE_FLAG; - if (nCode != ERINA_HUFFMAN_ESCAPE) { - return nCode; - } - } - - if (escapeGamma) { - // escape code: gamma code - nCode = MIOContext_GetGammaCode(context); - if (nCode == -1) { - return ERINA_HUFFMAN_ESCAPE; - } - } - else { - // escape code: 8-bit code - nCode = MIOContext_GetNBits(context, 8); - } - EHT_AddNewEntry(tree, nCode); - - return nCode; -} - -// get one "regular huffman" code -static int MIOContext_GetHuffmanCode(MIOContext* context, ERINA_HUFFMAN_TREE* tree) { - return MIOContext_GetHuffmanCommon(context, tree, 0); -} - -// get one "length huffman" code -static int MIOContext_GetHuffmanLength(MIOContext* context, ERINA_HUFFMAN_TREE* tree) { - return MIOContext_GetHuffmanCommon(context, tree, 1); -} - -////////////////////////////////////////////////////////////////////////////// - -/* decode ERINA (huffman-coded) */ -ULONG MIOContext_DecodeERINACodeBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount) { - ERINA_HUFFMAN_TREE* tree = context->m_pLastHuffmanTree; - int symbol, length; - ULONG i = 0; - if (context->m_nLength > 0) { - length = context->m_nLength; - if (length > (int)nCount) { - length = nCount; - } - context->m_nLength -= length; - do { - ptrDst[i++] = 0; - } while (--length); - } - while (i < nCount) { - symbol = MIOContext_GetHuffmanCode(context, tree); - if (symbol == ERINA_HUFFMAN_ESCAPE) { - break; - } - ptrDst[i++] = (SBYTE)symbol; - - if (symbol == 0) { - length = MIOContext_GetHuffmanLength(context, context->m_ppHuffmanTree[0x100]); - if (length == ERINA_HUFFMAN_ESCAPE) { - break; - } - if (--length) { - context->m_nLength = length; - if (i + length > nCount) { - length = nCount - i; - } - context->m_nLength -= length; - if (length > 0) { - do { - ptrDst[i++] = 0; - } while (--length); - } - } - } - tree = context->m_ppHuffmanTree[symbol & 0xFF]; - } - context->m_pLastHuffmanTree = tree; - - return i; -} - -static int MIOContext_DecodeERISACodeIndex(MIOContext* context, ERISA_PROB_MODEL* pModel) { - // serach via index - UDWORD dwAcc = context->m_dwCodeRegister * pModel->dwTotalCount / context->m_dwAugendRegister; - if (dwAcc >= ERISA_TOTAL_LIMIT) { - return MIO_ERISA_SYMBOL_ERROR; - } - - int iSym = 0; - WORD wAcc = (WORD)dwAcc; - WORD wFs = 0; - WORD wOccured; - for (;;) { - wOccured = pModel->acsSymTable[iSym].wOccured; - if (wAcc < wOccured) { - break; - } - wAcc -= wOccured; - wFs += wOccured; - if ((UDWORD)++iSym >= pModel->dwSymbolSorts) { - return MIO_ERISA_SYMBOL_ERROR; - } - } - - // update code and augend registers - context->m_dwCodeRegister -= (context->m_dwAugendRegister * wFs + pModel->dwTotalCount - 1) / pModel->dwTotalCount; - context->m_dwAugendRegister = context->m_dwAugendRegister * wOccured / pModel->dwTotalCount; - - /* (assert) */ - if (context->m_dwAugendRegister == 0) - return MIO_ERISA_SYMBOL_ERROR; - - // normalize augend register and load into code register - while (!(context->m_dwAugendRegister & 0x8000)) { - int nNextBit = MIOContext_GetABit(context); - if (nNextBit == 1) { - if ((++context->m_nPostBitCount) >= 256) { - return MIO_ERISA_SYMBOL_ERROR; - } - nNextBit = 0; - } - context->m_dwCodeRegister = (context->m_dwCodeRegister << 1) | (nNextBit & 0x01); - - context->m_dwAugendRegister <<= 1; - } - - - /* (assert) */ - if ((context->m_dwAugendRegister & 0x8000) == 0) - return MIO_ERISA_SYMBOL_ERROR; - - context->m_dwCodeRegister &= 0xFFFF; - - return iSym; -} - -/* decode ERISA (arithmetic-coded, using designated statistical model) */ -int MIOContext_DecodeERISACode(MIOContext* context, ERISA_PROB_MODEL* pModel) { - int iSym = MIOContext_DecodeERISACodeIndex(context, pModel); - int nSymbol = ERISA_ESCAPE_CODE; - if (iSym >= 0) { - nSymbol = pModel->acsSymTable[iSym].wSymbol; - EPM_IncreaseSymbol(pModel, iSym); - } - return nSymbol; -} - -////////////////////////////////////////////////////////////////////////////// - -MIOContext* MIOContext_Open() { - MIOContext* context = malloc(sizeof(MIOContext)); - if (!context) return NULL; - - context->m_nIntBufCount = 0; - - context->m_pfnDecodeSymbolBytes = NULL; - - context->m_ppHuffmanTree = NULL; - context->m_pPhraseLenProb = NULL; - context->m_pPhraseIndexProb = NULL; - context->m_pRunLenProb = NULL; - context->m_ppTableERISA = NULL; - - return context; -} - -void MIOContext_Close(MIOContext* context) { - if (!context) return; - - free(context->m_ppHuffmanTree); - free(context->m_pPhraseLenProb); - free(context->m_pPhraseIndexProb); - free(context->m_pRunLenProb); - free(context->m_ppTableERISA); - - free(context); -} - -void MIOContext_AttachInputFile(MIOContext* context, uint8_t* pFileBuf, int pFileLength) { - context->m_pFileBuf = pFileBuf; - context->m_pFileLength = pFileLength; - context->m_pFilePos = 0; -} - -void MIOContext_FlushBuffer(MIOContext* context) { - context->m_nIntBufCount = 0; -} - -////////////////////////////////////////////////////////////////////////////// - -ESLError MIOContext_PrepareToDecodeERINACode(MIOContext* context, UDWORD dwFlags) { - if (context->m_ppHuffmanTree == NULL) { - UDWORD dwSize = (sizeof(ERINA_HUFFMAN_TREE*) + sizeof(ERINA_HUFFMAN_TREE)) * 0x101; - dwSize = (dwSize + 0x0F) & ~0x0F; - context->m_ppHuffmanTree = (ERINA_HUFFMAN_TREE**)malloc(dwSize); - if (!context->m_ppHuffmanTree) - return eslErrGeneral; - - BYTE* ptrBuf = (BYTE*)(context->m_ppHuffmanTree + 0x101); - for (int i = 0; i < 0x101; i++) { - void* ptrTmp = ptrBuf; - context->m_ppHuffmanTree[i] = ptrTmp; - ptrBuf += sizeof(ERINA_HUFFMAN_TREE); - } - } - - // init huffman - context->m_dwERINAFlags = dwFlags; - context->m_nLength = 0; - if (dwFlags == ERINAEncodingFlag_efERINAOrder0) { // not used in audio actually - EHT_Initialize(context->m_ppHuffmanTree[0]); - EHT_Initialize(context->m_ppHuffmanTree[0x100]); - for (int i = 1; i < 0x100; i++) { - context->m_ppHuffmanTree[i] = context->m_ppHuffmanTree[0]; - } - } - else { - for (int i = 0; i < 0x101; i++) { - EHT_Initialize(context->m_ppHuffmanTree[i]); - } - } - - context->m_pLastHuffmanTree = context->m_ppHuffmanTree[0]; - - context->m_pfnDecodeSymbolBytes = &MIOContext_DecodeERINACodeBytes; - - return eslErrSuccess; -} - -ESLError MIOContext_PrepareToDecodeERISACode(MIOContext* context) { - // init memory - if (context->m_ppTableERISA == NULL) { //TODO improve - UDWORD dwBytes = sizeof(ERISA_PROB_MODEL*) * 0x104 + sizeof(ERISA_PROB_MODEL) * 0x101; - dwBytes = (dwBytes + 0x100F) & (~0xFFF); - context->m_ppTableERISA = (ERISA_PROB_MODEL**)malloc(dwBytes); - if (!context->m_ppTableERISA) - return eslErrGeneral; - } - - if (context->m_pPhraseLenProb == NULL) - context->m_pPhraseLenProb = malloc(sizeof(ERISA_PROB_MODEL)); - if (context->m_pPhraseIndexProb == NULL) - context->m_pPhraseIndexProb = malloc(sizeof(ERISA_PROB_MODEL)); - if (context->m_pRunLenProb == NULL) - context->m_pRunLenProb = malloc(sizeof(ERISA_PROB_MODEL)); - if (!context->m_pPhraseLenProb || !context->m_pPhraseIndexProb || !context->m_pRunLenProb) - return eslErrGeneral; - - // init probability model - ERISA_PROB_MODEL* pNextProb = (ERISA_PROB_MODEL*)(context->m_ppTableERISA + 0x104); - context->m_pLastERISAProb = pNextProb; - for (int i = 0; i < 0x101; i++) { - EPM_Initialize(pNextProb); - context->m_ppTableERISA[i] = pNextProb; - pNextProb++; - } - EPM_Initialize(context->m_pPhraseLenProb); - EPM_Initialize(context->m_pPhraseIndexProb); - EPM_Initialize(context->m_pRunLenProb); - - // init register - context->m_nLength = 0; - context->m_dwCodeRegister = MIOContext_GetNBits(context, 32); - context->m_dwAugendRegister = 0xFFFF; - context->m_nPostBitCount = 0; - - context->m_pfnDecodeSymbolBytes = &MIOContext_DecodeERISACodeBytes; - - return eslErrSuccess; -} - -// init "arithtmetic code" -void MIOContext_InitializeERISACode(MIOContext* context) { - context->m_nLength = 0; - context->m_dwCodeRegister = MIOContext_GetNBits(context, 32); - context->m_dwAugendRegister = 0xFFFF; - context->m_nPostBitCount = 0; -} - -ULONG MIOContext_DecodeERISACodeBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount) { - ERISA_PROB_MODEL* pProb = context->m_pLastERISAProb; - int nSymbol, iSym; - int i = 0; - - while ((ULONG)i < nCount) { - if (context->m_nLength > 0) { - // zero-length - ULONG nCurrent = nCount - i; - if (nCurrent > context->m_nLength) - nCurrent = context->m_nLength; - - context->m_nLength -= nCurrent; - for (ULONG j = 0; j < nCurrent; j++) { - ptrDst[i++] = 0; - } - - continue; - } - - // decode next arithmetic code - iSym = MIOContext_DecodeERISACodeIndex(context, pProb); - if (iSym < 0) - break; - nSymbol = pProb->acsSymTable[iSym].wSymbol; - EPM_IncreaseSymbol(pProb, iSym); - ptrDst[i++] = (SBYTE)nSymbol; - - if (nSymbol == 0) { - // get zero-length - iSym = MIOContext_DecodeERISACodeIndex(context, context->m_pRunLenProb); - if (iSym < 0) - break; - context->m_nLength = context->m_pRunLenProb->acsSymTable[iSym].wSymbol; - EPM_IncreaseSymbol(context->m_pRunLenProb, iSym); - } - - pProb = context->m_ppTableERISA[(nSymbol & 0xFF)]; - } - context->m_pLastERISAProb = pProb; - - return i; -} - -ULONG MIOContext_DecodeERISACodeWords(MIOContext* context, SWORD* ptrDst, ULONG nCount) { - ERISA_PROB_MODEL* pProb = context->m_pLastERISAProb; - int nSymbol, iSym; - int i = 0; - - while ((ULONG)i < nCount) { - if (context->m_nLength > 0) { - // zero-length - ULONG nCurrent = nCount - i; - if (nCurrent > context->m_nLength) - nCurrent = context->m_nLength; - - context->m_nLength -= nCurrent; - for (ULONG j = 0; j < nCurrent; j++) { - ptrDst[i++] = 0; - } - - continue; - } - - // decode next arithmetic code - iSym = MIOContext_DecodeERISACodeIndex(context, pProb); - if (iSym < 0) - break; - nSymbol = pProb->acsSymTable[iSym].wSymbol; - EPM_IncreaseSymbol(pProb, iSym); - - - if (nSymbol == ERISA_ESCAPE_CODE) { - iSym = MIOContext_DecodeERISACodeIndex(context, context->m_pPhraseIndexProb); - if (iSym < 0) - break; - nSymbol = context->m_pPhraseIndexProb->acsSymTable[iSym].wSymbol; - EPM_IncreaseSymbol(context->m_pPhraseIndexProb, iSym); - - iSym = MIOContext_DecodeERISACodeIndex(context, context->m_pPhraseLenProb); - if (iSym < 0) - break; - nSymbol = (nSymbol << 8) | (context->m_pPhraseLenProb->acsSymTable[iSym].wSymbol & 0xFF); - EPM_IncreaseSymbol(context->m_pPhraseLenProb, iSym); - - ptrDst[i++] = (SWORD)nSymbol; - pProb = context->m_ppTableERISA[0x100]; - } - else { - ptrDst[i++] = (SWORD)(SBYTE)nSymbol; - pProb = context->m_ppTableERISA[(nSymbol & 0xFF)]; - - if (nSymbol == 0) { - // get zero-length - iSym = MIOContext_DecodeERISACodeIndex(context, context->m_pRunLenProb); - if (iSym < 0) - break; - context->m_nLength = context->m_pRunLenProb->acsSymTable[iSym].wSymbol; - EPM_IncreaseSymbol(context->m_pRunLenProb, iSym); - } - } - } - - context->m_pLastERISAProb = pProb; - - return i; -} +/***************************************************************************** + E R I S A - L i b r a r y + ----------------------------------------------------------------------------- + Copyright (C) 2002-2003 Leshade Entis, Entis-soft. All rights reserved. + *****************************************************************************/ + +#include +#include "mio_xerisa.h" + +#define MIO_ERISA_SYMBOL_ERROR -1 + +/************************/ +/* huffman tree helpers */ +/************************/ + +static void EHT_Initialize(ERINA_HUFFMAN_TREE* tree) { + for (int i = 0; i < MIO_HUFFMAN_SYMBOLS; i++) { + tree->m_iSymLookup[i] = ERINA_HUFFMAN_NULL; + } + tree->m_iEscape = ERINA_HUFFMAN_NULL; + tree->m_iTreePointer = ERINA_HUFFMAN_ROOT; + tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight = 0; + tree->m_hnTree[ERINA_HUFFMAN_ROOT].parent = ERINA_HUFFMAN_NULL; + tree->m_hnTree[ERINA_HUFFMAN_ROOT].child_code = ERINA_HUFFMAN_NULL; +} + +static void EHT_RecountOccuredCount(ERINA_HUFFMAN_TREE* tree, int iParent) { + int iChild = tree->m_hnTree[iParent].child_code; + tree->m_hnTree[iParent].weight = tree->m_hnTree[iChild].weight + tree->m_hnTree[iChild + 1].weight; +} + +static void EHT_Normalize(ERINA_HUFFMAN_TREE* tree, int iEntry) { + while (iEntry < ERINA_HUFFMAN_ROOT) { + // find swap entry + int iSwap = iEntry + 1; + WORD weight = tree->m_hnTree[iEntry].weight; + while (iSwap < ERINA_HUFFMAN_ROOT) { + if (tree->m_hnTree[iSwap].weight >= weight) break; + ++iSwap; + } + if (iEntry == --iSwap) { + iEntry = tree->m_hnTree[iEntry].parent; + EHT_RecountOccuredCount(tree, iEntry); + continue; + } + + // swap + int iChild, nCode; + if (!(tree->m_hnTree[iEntry].child_code & ERINA_CODE_FLAG)) { + iChild = tree->m_hnTree[iEntry].child_code; + tree->m_hnTree[iChild].parent = iSwap; + tree->m_hnTree[iChild + 1].parent = iSwap; + } + else { + nCode = tree->m_hnTree[iEntry].child_code & ~ERINA_CODE_FLAG; + if (nCode != ERINA_HUFFMAN_ESCAPE) + tree->m_iSymLookup[nCode & 0xFF] = iSwap; + else + tree->m_iEscape = iSwap; + } + if (!(tree->m_hnTree[iSwap].child_code & ERINA_CODE_FLAG)) { + int iChild = tree->m_hnTree[iSwap].child_code; + tree->m_hnTree[iChild].parent = iEntry; + tree->m_hnTree[iChild + 1].parent = iEntry; + } + else { + int nCode = tree->m_hnTree[iSwap].child_code & ~ERINA_CODE_FLAG; + if (nCode != ERINA_HUFFMAN_ESCAPE) + tree->m_iSymLookup[nCode & 0xFF] = iEntry; + else + tree->m_iEscape = iEntry; + } + + ERINA_HUFFMAN_NODE node; + WORD iEntryParent = tree->m_hnTree[iEntry].parent; + WORD iSwapParent = tree->m_hnTree[iSwap].parent; + node = tree->m_hnTree[iSwap]; + tree->m_hnTree[iSwap] = tree->m_hnTree[iEntry]; + tree->m_hnTree[iEntry] = node; + tree->m_hnTree[iSwap].parent = iSwapParent; + tree->m_hnTree[iEntry].parent = iEntryParent; + + // recalc parent weight + EHT_RecountOccuredCount(tree, iSwapParent); + iEntry = iSwapParent; + } +} + +static void EHT_AddNewEntry(ERINA_HUFFMAN_TREE* tree, int nNewCode) { + if (tree->m_iTreePointer > 0) { + // reserve 2 areas + int i = tree->m_iTreePointer = tree->m_iTreePointer - 2; + + // setup new entry + ERINA_HUFFMAN_NODE* phnNew = &tree->m_hnTree[i]; + phnNew->weight = 1; + phnNew->child_code = ERINA_CODE_FLAG | nNewCode; + tree->m_iSymLookup[nNewCode & 0xFF] = i; + + ERINA_HUFFMAN_NODE* phnRoot = &tree->m_hnTree[ERINA_HUFFMAN_ROOT]; + if (phnRoot->child_code != ERINA_HUFFMAN_NULL) { + // add new entry + ERINA_HUFFMAN_NODE* phnParent = &tree->m_hnTree[i + 2]; + ERINA_HUFFMAN_NODE* phnChild = &tree->m_hnTree[i + 1]; + tree->m_hnTree[i + 1] = tree->m_hnTree[i + 2]; + + if (phnChild->child_code & ERINA_CODE_FLAG) { + int nCode = phnChild->child_code & ~ERINA_CODE_FLAG; + if (nCode != ERINA_HUFFMAN_ESCAPE) + tree->m_iSymLookup[nCode & 0xFF] = i + 1; + else + tree->m_iEscape = i + 1; + } + + phnParent->weight = phnNew->weight + phnChild->weight; + phnParent->parent = phnChild->parent; + phnParent->child_code = i; + + phnNew->parent = phnChild->parent = i + 2; + + // fix parent entry + EHT_Normalize(tree, i + 2); + } + else { + // create initial tree state + phnNew->parent = ERINA_HUFFMAN_ROOT; + + ERINA_HUFFMAN_NODE* phnEscape = &tree->m_hnTree[tree->m_iEscape = i + 1]; + phnEscape->weight = 1; + phnEscape->parent = ERINA_HUFFMAN_ROOT; + phnEscape->child_code = ERINA_CODE_FLAG | ERINA_HUFFMAN_ESCAPE; + + phnRoot->weight = 2; + phnRoot->child_code = i; + } + } + else { + // replace least ocurring symbol with new symbol + int i = tree->m_iTreePointer; + ERINA_HUFFMAN_NODE* phnEntry = &tree->m_hnTree[i]; + if (phnEntry->child_code == (ERINA_CODE_FLAG | ERINA_HUFFMAN_ESCAPE)) { + phnEntry = &tree->m_hnTree[i + 1]; + } + phnEntry->child_code = ERINA_CODE_FLAG | nNewCode; + } +} + +static void EHT_HalfAndRebuild(ERINA_HUFFMAN_TREE* tree) { + // halve ocurrence count and rebuild the tree + int iNextEntry = ERINA_HUFFMAN_ROOT; + for (int i = ERINA_HUFFMAN_ROOT - 1; i >= tree->m_iTreePointer; i--) { + if (tree->m_hnTree[i].child_code & ERINA_CODE_FLAG) { + tree->m_hnTree[i].weight = (tree->m_hnTree[i].weight + 1) >> 1; + tree->m_hnTree[iNextEntry--] = tree->m_hnTree[i]; + } + } + ++iNextEntry; + + // rebuild tree + int iChild, nCode; + int i = tree->m_iTreePointer; + for (;;) { + // put the smallest 2 entries into the huffman tree + tree->m_hnTree[i] = tree->m_hnTree[iNextEntry]; + tree->m_hnTree[i + 1] = tree->m_hnTree[iNextEntry + 1]; + iNextEntry += 2; + ERINA_HUFFMAN_NODE* phnChild1 = &tree->m_hnTree[i]; + ERINA_HUFFMAN_NODE* phnChild2 = &tree->m_hnTree[i + 1]; + + if (!(phnChild1->child_code & ERINA_CODE_FLAG)) { + iChild = phnChild1->child_code; + tree->m_hnTree[iChild].parent = i; + tree->m_hnTree[iChild + 1].parent = i; + } + else { + nCode = phnChild1->child_code & ~ERINA_CODE_FLAG; + if (nCode == ERINA_HUFFMAN_ESCAPE) + tree->m_iEscape = i; + else + tree->m_iSymLookup[nCode & 0xFF] = i; + } + + if (!(phnChild2->child_code & ERINA_CODE_FLAG)) { + iChild = phnChild2->child_code; + tree->m_hnTree[iChild].parent = i + 1; + tree->m_hnTree[iChild + 1].parent = i + 1; + } + else { + nCode = phnChild2->child_code & ~ERINA_CODE_FLAG; + if (nCode == ERINA_HUFFMAN_ESCAPE) + tree->m_iEscape = i + 1; + else + tree->m_iSymLookup[nCode & 0xFF] = i + 1; + } + + WORD weight = phnChild1->weight + phnChild2->weight; + + // include parent entry in list + if (iNextEntry <= ERINA_HUFFMAN_ROOT) { + int j = iNextEntry; + for (;;) { + if (weight <= tree->m_hnTree[j].weight) { + tree->m_hnTree[j - 1].weight = weight; + tree->m_hnTree[j - 1].child_code = i; + break; + } + tree->m_hnTree[j - 1] = tree->m_hnTree[j]; + if (++j > ERINA_HUFFMAN_ROOT) { + tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight = weight; + tree->m_hnTree[ERINA_HUFFMAN_ROOT].child_code = i; + break; + } + } + --iNextEntry; + } + else { + tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight = weight; + tree->m_hnTree[ERINA_HUFFMAN_ROOT].parent = ERINA_HUFFMAN_NULL; + tree->m_hnTree[ERINA_HUFFMAN_ROOT].child_code = i; + phnChild1->parent = ERINA_HUFFMAN_ROOT; + phnChild2->parent = ERINA_HUFFMAN_ROOT; + break; + } + + i += 2; + } +} + +static void EHT_IncreaseOccuredCount(ERINA_HUFFMAN_TREE* tree, int iEntry) { + tree->m_hnTree[iEntry].weight++; + EHT_Normalize(tree, iEntry); + + if (tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight >= ERINA_HUFFMAN_MAX) { + EHT_HalfAndRebuild(tree); + } +} + +/*****************************/ +/* arithmetic coding helpers */ +/*****************************/ + +static void EPM_Initialize(ERISA_PROB_MODEL* prob) { + prob->dwTotalCount = ERISA_SYMBOL_SORTS; + prob->dwSymbolSorts = ERISA_SYMBOL_SORTS; + + for (int i = 0; i < 0x100; i++) { + prob->acsSymTable[i].wOccured = 1; + prob->acsSymTable[i].wSymbol = (SWORD)(BYTE)i; + } + prob->acsSymTable[0x100].wOccured = 1; + prob->acsSymTable[0x100].wSymbol = (SWORD)ERISA_ESCAPE_CODE; + + for (int i = 0; i < ERISA_SUB_SORT_MAX; i++) { + prob->acsSubModel[i].wOccured = 0; + prob->acsSubModel[i].wSymbol = (SWORD)-1; + } +} + +static void EPM_HalfOccuredCount(ERISA_PROB_MODEL* prob) { + UDWORD i; + + prob->dwTotalCount = 0; + for (i = 0; i < prob->dwSymbolSorts; i++) { + prob->dwTotalCount += prob->acsSymTable[i].wOccured = ((prob->acsSymTable[i].wOccured + 1) >> 1); + } + for (i = 0; i < ERISA_SUB_SORT_MAX; i++) { + prob->acsSubModel[i].wOccured >>= 1; + } +} + +static int EPM_IncreaseSymbol(ERISA_PROB_MODEL* prob, int index) { + WORD wOccured = ++prob->acsSymTable[index].wOccured; + SWORD wSymbol = prob->acsSymTable[index].wSymbol; + + while (--index >= 0) { + if (prob->acsSymTable[index].wOccured >= wOccured) + break; + prob->acsSymTable[index + 1] = prob->acsSymTable[index]; + } + prob->acsSymTable[++index].wOccured = wOccured; + prob->acsSymTable[index].wSymbol = wSymbol; + + if (++prob->dwTotalCount >= ERISA_TOTAL_LIMIT) { + EPM_HalfOccuredCount(prob); + } + + return index; +} + +/**************************/ +/* general decode context */ +/**************************/ + +ULONG MIOContext_DecodeSymbolBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount) { + + /* (assert) */ + if (context->m_pfnDecodeSymbolBytes == NULL) + return 0; + + return (context->m_pfnDecodeSymbolBytes)(context, ptrDst, nCount); +} + + +static const SBYTE /*BYTE*/ nGammaCodeLookup[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 6, 8, 6, 8, 6, 8, 6, 16, 8, -1, -1, 17, 8, -1, -1, 9, 6, 9, 6, 9, 6, 9, 6, 18, + 8, -1, -1, 19, 8, -1, -1, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, + 5, 4, 10, 6, 10, 6, 10, 6, 10, 6, 20, 8, -1, -1, 21, 8, -1, -1, 11, 6, 11, 6, 11, 6, 11, 6, 22, 8, -1, -1, 23, 8, -1, -1, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, 4, 6, + 4, 6, 4, 6, 4, 6, 4, 6, 4, 12, 6, 12, 6, 12, 6, 12, 6, 24, 8, -1, -1, 25, 8, -1, -1, 13, 6, 13, 6, 13, 6, 13, 6, 26, 8, -1, -1, + 27, 8, -1, -1, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 7, 4, 14, + 6, 14, 6, 14, 6, 14, 6, 28, 8, -1, -1, 29, 8, -1, -1, 15, 6, 15, 6, 15, 6, 15, 6, 30, 8, -1, -1, 31, 8, -1, -1 +}; + + +static ESLError MIOContext_PrefetchBuffer(MIOContext* context) { + if (context->m_nIntBufCount != 0) + return eslErrSuccess; + + if (context->m_pFilePos >= context->m_pFileLength) + return eslErrGeneral; + + // read next int32 BE + int dwLeft = context->m_pFileLength - context->m_pFilePos; + if (dwLeft < 4) { + // read partially at buffer edge + context->m_dwIntBuffer = 0; + for (int i = 0; i < dwLeft; i++) { + context->m_dwIntBuffer |= (UDWORD)context->m_pFileBuf[context->m_pFilePos + i] << (24 - 8*i); + } + context->m_pFilePos += dwLeft; + } + else { + context->m_dwIntBuffer = + ((UDWORD)context->m_pFileBuf[context->m_pFilePos + 0] << 24) | + ((UDWORD)context->m_pFileBuf[context->m_pFilePos + 1] << 16) | + ((UDWORD)context->m_pFileBuf[context->m_pFilePos + 2] << 8) | + ((UDWORD)context->m_pFileBuf[context->m_pFilePos + 3]); + context->m_pFilePos += 4; + } + + // get next int32 + context->m_nIntBufCount = 32; + + return eslErrSuccess; +} + +int MIOContext_GetABit(MIOContext* context) { + if (MIOContext_PrefetchBuffer(context)) { + return 1; // on error does return 1 + } + + // returns one bit ("0 or -1" according to original comment) + int nValue = (int)(((SDWORD)context->m_dwIntBuffer) >> 31); + --context->m_nIntBufCount; + context->m_dwIntBuffer <<= 1; + return nValue; +} + +UINT MIOContext_GetNBits(MIOContext* context, int n) { + UINT nCode = 0; + while (n != 0) { + if (MIOContext_PrefetchBuffer(context)) + break; + + int nCopyBits = n; + if (nCopyBits > context->m_nIntBufCount) + nCopyBits = context->m_nIntBufCount; + + nCode = (nCode << nCopyBits) | (context->m_dwIntBuffer >> (32 - nCopyBits)); + n -= nCopyBits; + context->m_nIntBufCount -= nCopyBits; + context->m_dwIntBuffer <<= nCopyBits; + } + return nCode; +} + +static int MIOContext_GetGammaCode(MIOContext* context) { + // test 1 + if (MIOContext_PrefetchBuffer(context)) { + return 0; + } + + /*register*/ UDWORD dwIntBuf; + context->m_nIntBufCount--; + dwIntBuf = context->m_dwIntBuffer; + context->m_dwIntBuffer <<= 1; + if (!(dwIntBuf & 0x80000000)) { + return 1; + } + + + // test end code + if (MIOContext_PrefetchBuffer(context)) { + return 0; + } + + if ((~context->m_dwIntBuffer & 0x55000000) && (context->m_nIntBufCount >= 8)) { + int i = (context->m_dwIntBuffer >> 24) << 1; + int nCode = nGammaCodeLookup[i]; + int nBitCount = nGammaCodeLookup[i + 1]; + + /* (assert) */ + if (nBitCount > context->m_nIntBufCount || nCode <= 0) + return 0; + + context->m_nIntBufCount -= nBitCount; + context->m_dwIntBuffer <<= nBitCount; + return nCode; + } + + // regular routine + int nCode = 0, nBase = 2; + for (;;) { + if (context->m_nIntBufCount >= 2) { + // process 2 bits + dwIntBuf = context->m_dwIntBuffer; + context->m_dwIntBuffer <<= 2; + nCode = (nCode << 1) | (dwIntBuf >> 31); + context->m_nIntBufCount -= 2; + if (!(dwIntBuf & 0x40000000)) { + return nCode + nBase; + } + nBase <<= 1; + } + else { + // extract 1-bit + if (MIOContext_PrefetchBuffer(context)) { + return 0; + } + nCode = (nCode << 1) | (context->m_dwIntBuffer >> 31); + context->m_nIntBufCount--; + context->m_dwIntBuffer <<= 1; + + // test end code + if (MIOContext_PrefetchBuffer(context)) { + return 0; + } + + dwIntBuf = context->m_dwIntBuffer; + context->m_nIntBufCount--; + context->m_dwIntBuffer <<= 1; + if (!(dwIntBuf & 0x80000000)) { + return nCode + nBase; + } + nBase <<= 1; + } + } +} + +/* original clones this into 2 functions with different escape codes but here we use a flag */ +static int MIOContext_GetHuffmanCommon(MIOContext* context, ERINA_HUFFMAN_TREE* tree, int escapeGamma) { + // get one huffman code + int nCode; + if (tree->m_iEscape != ERINA_HUFFMAN_NULL) { + int iEntry = ERINA_HUFFMAN_ROOT; + int iChild = tree->m_hnTree[ERINA_HUFFMAN_ROOT].child_code; + + // decode codes + do { + if (MIOContext_PrefetchBuffer(context)) { + return ERINA_HUFFMAN_ESCAPE; + } + + // extract 1-bit + iEntry = iChild + (context->m_dwIntBuffer >> 31); + --context->m_nIntBufCount; + iChild = tree->m_hnTree[iEntry].child_code; + context->m_dwIntBuffer <<= 1; + } while (!(iChild & ERINA_CODE_FLAG)); + + // increase code occurence + if ((context->m_dwERINAFlags != ERINAEncodingFlag_efERINAOrder0) || (tree->m_hnTree[ERINA_HUFFMAN_ROOT].weight < ERINA_HUFFMAN_MAX - 1)) { + EHT_IncreaseOccuredCount(tree, iEntry); + } + + // regular code + nCode = iChild & ~ERINA_CODE_FLAG; + if (nCode != ERINA_HUFFMAN_ESCAPE) { + return nCode; + } + } + + if (escapeGamma) { + // escape code: gamma code + nCode = MIOContext_GetGammaCode(context); + if (nCode == -1) { + return ERINA_HUFFMAN_ESCAPE; + } + } + else { + // escape code: 8-bit code + nCode = MIOContext_GetNBits(context, 8); + } + EHT_AddNewEntry(tree, nCode); + + return nCode; +} + +// get one "regular huffman" code +static int MIOContext_GetHuffmanCode(MIOContext* context, ERINA_HUFFMAN_TREE* tree) { + return MIOContext_GetHuffmanCommon(context, tree, 0); +} + +// get one "length huffman" code +static int MIOContext_GetHuffmanLength(MIOContext* context, ERINA_HUFFMAN_TREE* tree) { + return MIOContext_GetHuffmanCommon(context, tree, 1); +} + +////////////////////////////////////////////////////////////////////////////// + +/* decode ERINA (huffman-coded) */ +ULONG MIOContext_DecodeERINACodeBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount) { + ERINA_HUFFMAN_TREE* tree = context->m_pLastHuffmanTree; + int symbol, length; + ULONG i = 0; + if (context->m_nLength > 0) { + length = context->m_nLength; + if (length > (int)nCount) { + length = nCount; + } + context->m_nLength -= length; + do { + ptrDst[i++] = 0; + } while (--length); + } + while (i < nCount) { + symbol = MIOContext_GetHuffmanCode(context, tree); + if (symbol == ERINA_HUFFMAN_ESCAPE) { + break; + } + ptrDst[i++] = (SBYTE)symbol; + + if (symbol == 0) { + length = MIOContext_GetHuffmanLength(context, context->m_ppHuffmanTree[0x100]); + if (length == ERINA_HUFFMAN_ESCAPE) { + break; + } + if (--length) { + context->m_nLength = length; + if (i + length > nCount) { + length = nCount - i; + } + context->m_nLength -= length; + if (length > 0) { + do { + ptrDst[i++] = 0; + } while (--length); + } + } + } + tree = context->m_ppHuffmanTree[symbol & 0xFF]; + } + context->m_pLastHuffmanTree = tree; + + return i; +} + +static int MIOContext_DecodeERISACodeIndex(MIOContext* context, ERISA_PROB_MODEL* pModel) { + // serach via index + UDWORD dwAcc = context->m_dwCodeRegister * pModel->dwTotalCount / context->m_dwAugendRegister; + if (dwAcc >= ERISA_TOTAL_LIMIT) { + return MIO_ERISA_SYMBOL_ERROR; + } + + int iSym = 0; + WORD wAcc = (WORD)dwAcc; + WORD wFs = 0; + WORD wOccured; + for (;;) { + wOccured = pModel->acsSymTable[iSym].wOccured; + if (wAcc < wOccured) { + break; + } + wAcc -= wOccured; + wFs += wOccured; + if ((UDWORD)++iSym >= pModel->dwSymbolSorts) { + return MIO_ERISA_SYMBOL_ERROR; + } + } + + // update code and augend registers + context->m_dwCodeRegister -= (context->m_dwAugendRegister * wFs + pModel->dwTotalCount - 1) / pModel->dwTotalCount; + context->m_dwAugendRegister = context->m_dwAugendRegister * wOccured / pModel->dwTotalCount; + + /* (assert) */ + if (context->m_dwAugendRegister == 0) + return MIO_ERISA_SYMBOL_ERROR; + + // normalize augend register and load into code register + while (!(context->m_dwAugendRegister & 0x8000)) { + int nNextBit = MIOContext_GetABit(context); + if (nNextBit == 1) { + if ((++context->m_nPostBitCount) >= 256) { + return MIO_ERISA_SYMBOL_ERROR; + } + nNextBit = 0; + } + context->m_dwCodeRegister = (context->m_dwCodeRegister << 1) | (nNextBit & 0x01); + + context->m_dwAugendRegister <<= 1; + } + + + /* (assert) */ + if ((context->m_dwAugendRegister & 0x8000) == 0) + return MIO_ERISA_SYMBOL_ERROR; + + context->m_dwCodeRegister &= 0xFFFF; + + return iSym; +} + +/* decode ERISA (arithmetic-coded, using designated statistical model) */ +int MIOContext_DecodeERISACode(MIOContext* context, ERISA_PROB_MODEL* pModel) { + int iSym = MIOContext_DecodeERISACodeIndex(context, pModel); + int nSymbol = ERISA_ESCAPE_CODE; + if (iSym >= 0) { + nSymbol = pModel->acsSymTable[iSym].wSymbol; + EPM_IncreaseSymbol(pModel, iSym); + } + return nSymbol; +} + +////////////////////////////////////////////////////////////////////////////// + +MIOContext* MIOContext_Open() { + MIOContext* context = malloc(sizeof(MIOContext)); + if (!context) return NULL; + + context->m_nIntBufCount = 0; + + context->m_pfnDecodeSymbolBytes = NULL; + + context->m_ppHuffmanTree = NULL; + context->m_pPhraseLenProb = NULL; + context->m_pPhraseIndexProb = NULL; + context->m_pRunLenProb = NULL; + context->m_ppTableERISA = NULL; + + return context; +} + +void MIOContext_Close(MIOContext* context) { + if (!context) return; + + free(context->m_ppHuffmanTree); + free(context->m_pPhraseLenProb); + free(context->m_pPhraseIndexProb); + free(context->m_pRunLenProb); + free(context->m_ppTableERISA); + + free(context); +} + +void MIOContext_AttachInputFile(MIOContext* context, uint8_t* pFileBuf, int pFileLength) { + context->m_pFileBuf = pFileBuf; + context->m_pFileLength = pFileLength; + context->m_pFilePos = 0; +} + +void MIOContext_FlushBuffer(MIOContext* context) { + context->m_nIntBufCount = 0; +} + +////////////////////////////////////////////////////////////////////////////// + +ESLError MIOContext_PrepareToDecodeERINACode(MIOContext* context, UDWORD dwFlags) { + if (context->m_ppHuffmanTree == NULL) { + UDWORD dwSize = (sizeof(ERINA_HUFFMAN_TREE*) + sizeof(ERINA_HUFFMAN_TREE)) * 0x101; + dwSize = (dwSize + 0x0F) & ~0x0F; + context->m_ppHuffmanTree = (ERINA_HUFFMAN_TREE**)malloc(dwSize); + if (!context->m_ppHuffmanTree) + return eslErrGeneral; + + BYTE* ptrBuf = (BYTE*)(context->m_ppHuffmanTree + 0x101); + for (int i = 0; i < 0x101; i++) { + void* ptrTmp = ptrBuf; + context->m_ppHuffmanTree[i] = ptrTmp; + ptrBuf += sizeof(ERINA_HUFFMAN_TREE); + } + } + + // init huffman + context->m_dwERINAFlags = dwFlags; + context->m_nLength = 0; + if (dwFlags == ERINAEncodingFlag_efERINAOrder0) { // not used in audio actually + EHT_Initialize(context->m_ppHuffmanTree[0]); + EHT_Initialize(context->m_ppHuffmanTree[0x100]); + for (int i = 1; i < 0x100; i++) { + context->m_ppHuffmanTree[i] = context->m_ppHuffmanTree[0]; + } + } + else { + for (int i = 0; i < 0x101; i++) { + EHT_Initialize(context->m_ppHuffmanTree[i]); + } + } + + context->m_pLastHuffmanTree = context->m_ppHuffmanTree[0]; + + context->m_pfnDecodeSymbolBytes = &MIOContext_DecodeERINACodeBytes; + + return eslErrSuccess; +} + +ESLError MIOContext_PrepareToDecodeERISACode(MIOContext* context) { + // init memory + if (context->m_ppTableERISA == NULL) { //TODO improve + UDWORD dwBytes = sizeof(ERISA_PROB_MODEL*) * 0x104 + sizeof(ERISA_PROB_MODEL) * 0x101; + dwBytes = (dwBytes + 0x100F) & (~0xFFF); + context->m_ppTableERISA = (ERISA_PROB_MODEL**)malloc(dwBytes); + if (!context->m_ppTableERISA) + return eslErrGeneral; + } + + if (context->m_pPhraseLenProb == NULL) + context->m_pPhraseLenProb = malloc(sizeof(ERISA_PROB_MODEL)); + if (context->m_pPhraseIndexProb == NULL) + context->m_pPhraseIndexProb = malloc(sizeof(ERISA_PROB_MODEL)); + if (context->m_pRunLenProb == NULL) + context->m_pRunLenProb = malloc(sizeof(ERISA_PROB_MODEL)); + if (!context->m_pPhraseLenProb || !context->m_pPhraseIndexProb || !context->m_pRunLenProb) + return eslErrGeneral; + + // init probability model + ERISA_PROB_MODEL* pNextProb = (ERISA_PROB_MODEL*)(context->m_ppTableERISA + 0x104); + context->m_pLastERISAProb = pNextProb; + for (int i = 0; i < 0x101; i++) { + EPM_Initialize(pNextProb); + context->m_ppTableERISA[i] = pNextProb; + pNextProb++; + } + EPM_Initialize(context->m_pPhraseLenProb); + EPM_Initialize(context->m_pPhraseIndexProb); + EPM_Initialize(context->m_pRunLenProb); + + // init register + context->m_nLength = 0; + context->m_dwCodeRegister = MIOContext_GetNBits(context, 32); + context->m_dwAugendRegister = 0xFFFF; + context->m_nPostBitCount = 0; + + context->m_pfnDecodeSymbolBytes = &MIOContext_DecodeERISACodeBytes; + + return eslErrSuccess; +} + +// init "arithtmetic code" +void MIOContext_InitializeERISACode(MIOContext* context) { + context->m_nLength = 0; + context->m_dwCodeRegister = MIOContext_GetNBits(context, 32); + context->m_dwAugendRegister = 0xFFFF; + context->m_nPostBitCount = 0; +} + +ULONG MIOContext_DecodeERISACodeBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount) { + ERISA_PROB_MODEL* pProb = context->m_pLastERISAProb; + int nSymbol, iSym; + int i = 0; + + while ((ULONG)i < nCount) { + if (context->m_nLength > 0) { + // zero-length + ULONG nCurrent = nCount - i; + if (nCurrent > context->m_nLength) + nCurrent = context->m_nLength; + + context->m_nLength -= nCurrent; + for (ULONG j = 0; j < nCurrent; j++) { + ptrDst[i++] = 0; + } + + continue; + } + + // decode next arithmetic code + iSym = MIOContext_DecodeERISACodeIndex(context, pProb); + if (iSym < 0) + break; + nSymbol = pProb->acsSymTable[iSym].wSymbol; + EPM_IncreaseSymbol(pProb, iSym); + ptrDst[i++] = (SBYTE)nSymbol; + + if (nSymbol == 0) { + // get zero-length + iSym = MIOContext_DecodeERISACodeIndex(context, context->m_pRunLenProb); + if (iSym < 0) + break; + context->m_nLength = context->m_pRunLenProb->acsSymTable[iSym].wSymbol; + EPM_IncreaseSymbol(context->m_pRunLenProb, iSym); + } + + pProb = context->m_ppTableERISA[(nSymbol & 0xFF)]; + } + context->m_pLastERISAProb = pProb; + + return i; +} + +ULONG MIOContext_DecodeERISACodeWords(MIOContext* context, SWORD* ptrDst, ULONG nCount) { + ERISA_PROB_MODEL* pProb = context->m_pLastERISAProb; + int nSymbol, iSym; + int i = 0; + + while ((ULONG)i < nCount) { + if (context->m_nLength > 0) { + // zero-length + ULONG nCurrent = nCount - i; + if (nCurrent > context->m_nLength) + nCurrent = context->m_nLength; + + context->m_nLength -= nCurrent; + for (ULONG j = 0; j < nCurrent; j++) { + ptrDst[i++] = 0; + } + + continue; + } + + // decode next arithmetic code + iSym = MIOContext_DecodeERISACodeIndex(context, pProb); + if (iSym < 0) + break; + nSymbol = pProb->acsSymTable[iSym].wSymbol; + EPM_IncreaseSymbol(pProb, iSym); + + + if (nSymbol == ERISA_ESCAPE_CODE) { + iSym = MIOContext_DecodeERISACodeIndex(context, context->m_pPhraseIndexProb); + if (iSym < 0) + break; + nSymbol = context->m_pPhraseIndexProb->acsSymTable[iSym].wSymbol; + EPM_IncreaseSymbol(context->m_pPhraseIndexProb, iSym); + + iSym = MIOContext_DecodeERISACodeIndex(context, context->m_pPhraseLenProb); + if (iSym < 0) + break; + nSymbol = (nSymbol << 8) | (context->m_pPhraseLenProb->acsSymTable[iSym].wSymbol & 0xFF); + EPM_IncreaseSymbol(context->m_pPhraseLenProb, iSym); + + ptrDst[i++] = (SWORD)nSymbol; + pProb = context->m_ppTableERISA[0x100]; + } + else { + ptrDst[i++] = (SWORD)(SBYTE)nSymbol; + pProb = context->m_ppTableERISA[(nSymbol & 0xFF)]; + + if (nSymbol == 0) { + // get zero-length + iSym = MIOContext_DecodeERISACodeIndex(context, context->m_pRunLenProb); + if (iSym < 0) + break; + context->m_nLength = context->m_pRunLenProb->acsSymTable[iSym].wSymbol; + EPM_IncreaseSymbol(context->m_pRunLenProb, iSym); + } + } + } + + context->m_pLastERISAProb = pProb; + + return i; +} diff --git a/Frameworks/vgmstream/vgmstream/src/coding/libs/mio_erisafile.c b/Frameworks/vgmstream/vgmstream/src/coding/libs/mio_erisafile.c index aaaa73f86..f2c42d1ac 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/libs/mio_erisafile.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/libs/mio_erisafile.c @@ -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 -#include -#include -#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 +#include +#include +#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; +} diff --git a/Frameworks/vgmstream/vgmstream/src/coding/libs/mio_erisasound.c b/Frameworks/vgmstream/vgmstream/src/coding/libs/mio_erisasound.c index b6c06cfe2..a85896179 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/libs/mio_erisasound.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/libs/mio_erisasound.c @@ -1,991 +1,991 @@ -/***************************************************************************** - E R I S A - L i b r a r y - ----------------------------------------------------------------------------- - Copyright (C) 2002-2003 Leshade Entis, Entis-soft. All rights reserved. - *****************************************************************************/ - -#include -#include -#include "mio_xerisa.h" - -static const double ERI_PI = 3.141592653589; -#define MIO_MAX_CHANNELS 2 - - -/*******************/ -/* audio converter */ -/*******************/ - -MIODecoder* MIODecoder_Open() { - MIODecoder* dec = calloc(1, sizeof(MIODecoder)); - if (!dec) - return NULL; - - dec->m_nBufLength = 0; - dec->m_ptrBuffer1 = NULL; - dec->m_ptrBuffer2 = NULL; - dec->m_ptrBuffer3 = NULL; - dec->m_ptrDivisionTable = NULL; - dec->m_ptrRevolveCode = NULL; - dec->m_ptrWeightCode = NULL; - dec->m_ptrCoefficient = NULL; - dec->m_ptrMatrixBuf = NULL; - dec->m_ptrInternalBuf = NULL; - dec->m_ptrWorkBuf = NULL; - dec->m_ptrWeightTable = NULL; - dec->m_ptrLastDCT = NULL; - dec->m_pRevolveParam = NULL; - return dec; -} - -static void MIODecoder_Delete(MIODecoder* dec) { - free(dec->m_ptrBuffer1); - dec->m_ptrBuffer1 = NULL; - free(dec->m_ptrBuffer2); - dec->m_ptrBuffer2 = NULL; - free(dec->m_ptrBuffer3); - dec->m_ptrBuffer3 = NULL; - free(dec->m_ptrDivisionTable); - dec->m_ptrDivisionTable = NULL; - free(dec->m_ptrRevolveCode); - dec->m_ptrRevolveCode = NULL; - free(dec->m_ptrWeightCode); - dec->m_ptrWeightCode = NULL; - free(dec->m_ptrCoefficient); - dec->m_ptrCoefficient = NULL; - free(dec->m_ptrMatrixBuf); - dec->m_ptrMatrixBuf = NULL; - free(dec->m_ptrInternalBuf); - dec->m_ptrInternalBuf = NULL; - free(dec->m_ptrWorkBuf); - dec->m_ptrWorkBuf = NULL; - free(dec->m_ptrWeightTable); - dec->m_ptrWeightTable = NULL; - free(dec->m_ptrLastDCT); - dec->m_ptrLastDCT = NULL; - free(dec->m_pRevolveParam); - dec->m_pRevolveParam = NULL; - - dec->m_nBufLength = 0; -} - -void MIODecoder_Close(MIODecoder* dec) { - if (!dec) - return; - MIODecoder_Delete(dec); - free(dec); -} - -// recalculate matrix size when params change -static int MIODecoder_InitializeWithDegree(MIODecoder* dec, unsigned int nSubbandDegree) { - free(dec->m_pRevolveParam); - dec->m_pRevolveParam = EMT_eriCreateRevolveParameter(nSubbandDegree); - if (!dec->m_pRevolveParam) return eslErrGeneral; - - // params for inverse quantization - static const int freq_width[7] = { -6, -6, -5, -4, -3, -2, -1 }; - for (int i = 0, j = 0; i < 7; i++) { - int nFrequencyWidth = 1 << (nSubbandDegree + freq_width[i]); - dec->m_nFrequencyPoint[i] = j + (nFrequencyWidth / 2); - j += nFrequencyWidth; - } - - dec->m_nSubbandDegree = nSubbandDegree; - dec->m_nDegreeNum = (1 << nSubbandDegree); - - return eslErrSuccess; -} - -ESLError MIODecoder_Initialize(MIODecoder* dec, const MIO_INFO_HEADER* infhdr) { - MIODecoder_Delete(dec); - - dec->m_mioih = *infhdr; /* copy */ - - if (dec->m_mioih.fdwTransformation == CVTYPE_LOSSLESS_ERI) { - if (dec->m_mioih.dwArchitecture != ERI_RUNLENGTH_HUFFMAN) - return eslErrGeneral; - - if ((dec->m_mioih.dwChannelCount != 1) && (dec->m_mioih.dwChannelCount != 2)) - return eslErrGeneral; - - if ((dec->m_mioih.dwBitsPerSample != 8) && (dec->m_mioih.dwBitsPerSample != 16)) - return eslErrGeneral; - } - else if ((dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI) || (dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI_MSS)) { - - if ((dec->m_mioih.dwArchitecture != ERI_RUNLENGTH_GAMMA) && - (dec->m_mioih.dwArchitecture != ERI_RUNLENGTH_HUFFMAN) && - (dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE)) - return eslErrGeneral; /* unknown code format */ - - if ((dec->m_mioih.dwChannelCount != 1) && (dec->m_mioih.dwChannelCount != 2)) - return eslErrGeneral; - - if (dec->m_mioih.dwBitsPerSample != 16) - return eslErrGeneral; - - if ((dec->m_mioih.dwSubbandDegree < 8) || (dec->m_mioih.dwSubbandDegree > MAX_DCT_DEGREE)) - return eslErrGeneral; - - if (dec->m_mioih.dwLappedDegree != 1) - return eslErrGeneral; - - // DCT buffers - { - int channel_size = sizeof(float) << dec->m_mioih.dwSubbandDegree; - int buf_size = dec->m_mioih.dwChannelCount * channel_size; - dec->m_ptrBuffer1 = malloc(buf_size); - dec->m_ptrMatrixBuf = malloc(buf_size); - dec->m_ptrInternalBuf = malloc(buf_size); - dec->m_ptrWorkBuf = malloc(channel_size); - if (!dec->m_ptrBuffer1 || !dec->m_ptrMatrixBuf || !dec->m_ptrInternalBuf || !dec->m_ptrWorkBuf) - return eslErrGeneral; - } - - // dequantization buffers - { - int channel_size = sizeof(float) << dec->m_mioih.dwSubbandDegree; - dec->m_ptrWeightTable = malloc(channel_size); - if (!dec->m_ptrWeightTable) - return eslErrGeneral; - } - - // LOT buffers - { - int nBlocksetSamples = dec->m_mioih.dwChannelCount << dec->m_mioih.dwSubbandDegree; - int nLappedSamples = nBlocksetSamples * dec->m_mioih.dwLappedDegree; - if (nLappedSamples > 0) { - dec->m_ptrLastDCT = malloc(sizeof(float) * nLappedSamples); - if (!dec->m_ptrLastDCT) - return eslErrGeneral; - - for (int i = 0; i < nLappedSamples; i++) { - dec->m_ptrLastDCT[i] = 0.0F; - } - } - } - - if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree)) - return eslErrGeneral; - } - else { - return eslErrGeneral; - } - - return eslErrSuccess; -} - -static ESLError MIODecoder_DecodeSoundPCM8(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) { - unsigned int nSampleCount = datahdr->dwSampleCount; - unsigned int nChannelCount = dec->m_mioih.dwChannelCount; - unsigned int nAllSampleCount = nSampleCount * nChannelCount; - ULONG nBytes = nAllSampleCount * sizeof(BYTE); - - if (nSampleCount > dec->m_nBufLength) { - free(dec->m_ptrBuffer1); - dec->m_ptrBuffer1 = malloc(nBytes); - if (!dec->m_ptrBuffer1) - return eslErrGeneral; - - dec->m_nBufLength = nSampleCount; - } - - // prepare huffman codes - if (datahdr->bytFlags & MIO_LEAD_BLOCK) { - ESLError err = MIOContext_PrepareToDecodeERINACode(context, ERINAEncodingFlag_efERINAOrder1); - if (err != eslErrSuccess) return err; - } - - if (MIOContext_DecodeSymbolBytes(context, (SBYTE*)dec->m_ptrBuffer1, nBytes) < nBytes) { - return eslErrGeneral; - } - - // differential processing output - BYTE* ptrSrcBuf = dec->m_ptrBuffer1; - BYTE* ptrDstBuf; - unsigned int nStep = nChannelCount; - unsigned int i, j; - for (i = 0; i < dec->m_mioih.dwChannelCount; i++) { - ptrDstBuf = ptrWaveBuf; - ptrDstBuf += i; - - BYTE bytValue = 0; - for (j = 0; j < nSampleCount; j++) { - bytValue += *(ptrSrcBuf++); - *ptrDstBuf = bytValue; - ptrDstBuf += nStep; - } - } - - return eslErrSuccess; -} - -static ESLError MIODecoder_DecodeSoundPCM16(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) { - unsigned int i, j; - unsigned int nSampleCount = datahdr->dwSampleCount; - unsigned int nChannelCount = dec->m_mioih.dwChannelCount; - unsigned int nAllSampleCount = nSampleCount * nChannelCount; - ULONG nBytes = nAllSampleCount * sizeof(SWORD); - - if (nSampleCount > dec->m_nBufLength) { - free(dec->m_ptrBuffer1); - free(dec->m_ptrBuffer2); - dec->m_ptrBuffer1 = malloc(nBytes); - dec->m_ptrBuffer2 = malloc(nBytes); - if (!dec->m_ptrBuffer1 || !dec->m_ptrBuffer2) - return eslErrGeneral; - - dec->m_nBufLength = nSampleCount; - } - - // prepare huffman codes - if (datahdr->bytFlags & MIO_LEAD_BLOCK) { - ESLError err = MIOContext_PrepareToDecodeERINACode(context, ERINAEncodingFlag_efERINAOrder1); - if (err != eslErrSuccess) return err; - } - - if (MIOContext_DecodeSymbolBytes(context, (SBYTE*)dec->m_ptrBuffer1, nBytes) < nBytes) { - return eslErrGeneral; - } - - // pack hi/lo bytes - BYTE* pbytSrcBuf1; - BYTE* pbytSrcBuf2; - BYTE* pbytDstBuf; - for (i = 0; i < nChannelCount; i++) { - unsigned int nOffset = i * nSampleCount * sizeof(SWORD); - pbytSrcBuf1 = ((BYTE*)dec->m_ptrBuffer1) + nOffset; - pbytSrcBuf2 = pbytSrcBuf1 + nSampleCount; - pbytDstBuf = ((BYTE*)dec->m_ptrBuffer2) + nOffset; - - for (j = 0; j < nSampleCount; j++) { - SBYTE bytLow = pbytSrcBuf2[j]; - SBYTE bytHigh = pbytSrcBuf1[j]; - pbytDstBuf[j * sizeof(SWORD) + 0] = bytLow; - pbytDstBuf[j * sizeof(SWORD) + 1] = bytHigh ^ (bytLow >> 7); - } - } - - // differential processing output - SWORD* ptrSrcBuf = dec->m_ptrBuffer2; - SWORD* ptrDstBuf; - unsigned int nStep = dec->m_mioih.dwChannelCount; - for (i = 0; i < dec->m_mioih.dwChannelCount; i++) { - ptrDstBuf = ptrWaveBuf; - ptrDstBuf += i; - - SWORD wValue = 0; - SWORD wDelta = 0; - for (j = 0; j < nSampleCount; j++) { - wDelta += *(ptrSrcBuf++); - wValue += wDelta; - *ptrDstBuf = wValue; - ptrDstBuf += nStep; - } - } - - return eslErrSuccess; -} - -////////////////////////////////////////////////////////////////////////////// - -static void MIODecoder_IQuantumize(MIODecoder* dec, float* ptrDestination, const INT* ptrQuantumized, int nDegreeNum, SDWORD nWeightCode, int nCoefficient) { - int i, j; - double rMatrixScale = sqrt(2.0 / nDegreeNum); - double rCoefficient = rMatrixScale * nCoefficient; - - // generate weight table - double rAvgRatio[7]; - for (i = 0; i < 6; i++) { - rAvgRatio[i] = 1.0 / pow(2.0, (((nWeightCode >> (i * 5)) & 0x1F) - 15) * 0.5); - } - rAvgRatio[6] = 1.0; - - for (i = 0; i < dec->m_nFrequencyPoint[0]; i++) { - dec->m_ptrWeightTable[i] = (float)rAvgRatio[0]; - } - - for (j = 1; j < 7; j++) { - double a = rAvgRatio[j - 1]; - double k = (rAvgRatio[j] - a) / (dec->m_nFrequencyPoint[j] - dec->m_nFrequencyPoint[j - 1]); - while (i < dec->m_nFrequencyPoint[j]) { - dec->m_ptrWeightTable[i] = (float)(k * (i - dec->m_nFrequencyPoint[j - 1]) + a); - i++; - } - } - - while (i < nDegreeNum) { - dec->m_ptrWeightTable[i] = (float)rAvgRatio[6]; - i++; - } - - float rOddWeight = (float)((((nWeightCode >> 30) & 0x03) + 0x02) / 2.0); - for (i = 15; i < nDegreeNum; i += 16) { - dec->m_ptrWeightTable[i] *= rOddWeight; - } - dec->m_ptrWeightTable[nDegreeNum - 1] = (float)nCoefficient; - - for (i = 0; i < nDegreeNum; i++) { - dec->m_ptrWeightTable[i] = 1.0F / dec->m_ptrWeightTable[i]; - } - - // dequantize - for (i = 0; i < nDegreeNum; i++) { - ptrDestination[i] = (float)(rCoefficient * dec->m_ptrWeightTable[i] * ptrQuantumized[i]); - } -} - -////////////////////////////////////////////////////////////////////////////// - -/* Dequantizes and transforms block frames. Lib divides them into "lead" (keyframes), - * "internal" (standard) and "post" blocks, handled slightly differently. All of them can be MSS - * blocks, which OG code handles in a separate function (presumably as a minor optimization to - * avoid setting extra FORs), but here are handled with a flag since they are very similar. */ - -static ESLError MIODecoder_DecodeLeadBlock_All(MIODecoder* dec, int is_mss) { - unsigned int ch, i; - unsigned int nHalfDegree = dec->m_nDegreeNum / 2; - int internal_channels = is_mss ? 2 : 1; - //int output_channels = is_mss ? 2 : dec->m_mioih.dwChannelCount; - - SDWORD nWeightCode = *(dec->m_ptrNextWeight++); - int nCoefficient = *(dec->m_ptrNextCoefficient++); - - float* ptrLapBuf; - - - // dequantize - ptrLapBuf = dec->m_ptrLastDCTBuf; - for (ch = 0; ch < internal_channels; ch++) { - INT* ptrTempBuf = dec->m_ptrBuffer1; - for (i = 0; i < nHalfDegree; i++) { - ptrTempBuf[i * 2] = 0; - ptrTempBuf[i * 2 + 1] = *(dec->m_ptrNextSource++); - } - MIODecoder_IQuantumize(dec, ptrLapBuf, ptrTempBuf, dec->m_nDegreeNum, nWeightCode, nCoefficient); - - ptrLapBuf += dec->m_nDegreeNum; - } - - // revolve - if (is_mss) { - float rSin, rCos; - int nRevCode = *(dec->m_ptrNextRevCode++); - - float* ptrLapBuf1 = dec->m_ptrLastDCT; - float* ptrLapBuf2 = dec->m_ptrLastDCT + dec->m_nDegreeNum; - - rSin = (float)sin(nRevCode * ERI_PI / 8); - rCos = (float)cos(nRevCode * ERI_PI / 8); - EMT_eriRevolve2x2(ptrLapBuf1, ptrLapBuf2, rSin, rCos, 1, dec->m_nDegreeNum); - } - - // set duplicate parameters - ptrLapBuf = dec->m_ptrLastDCTBuf; - for (ch = 0; ch < internal_channels; ch++) { - EMT_eriOddGivensInverseMatrix(ptrLapBuf, dec->m_pRevolveParam, dec->m_nSubbandDegree); - - for (i = 0; i < dec->m_nDegreeNum; i += 2) { - ptrLapBuf[i] = ptrLapBuf[i + 1]; - } - - EMT_eriFastIPLOT(ptrLapBuf, dec->m_nSubbandDegree); - - ptrLapBuf += dec->m_nDegreeNum; - } - - return eslErrSuccess; -} - -static ESLError MIODecoder_DecodeInternalBlock_All(MIODecoder* dec, SWORD* ptrDst, unsigned int nSamples, int is_mss) { - unsigned int ch, i; - int internal_channels = is_mss ? 2 : 1; - int output_channels = is_mss ? 2 : dec->m_mioih.dwChannelCount; - - SDWORD nWeightCode = *(dec->m_ptrNextWeight++); - int nCoefficient = *(dec->m_ptrNextCoefficient++); - - float* ptrLapBuf; - float* ptrSrcBuf; - - // dequantize - ptrSrcBuf = dec->m_ptrMatrixBuf; - for (ch = 0; ch < internal_channels; ch++) { - MIODecoder_IQuantumize(dec, ptrSrcBuf, dec->m_ptrNextSource, dec->m_nDegreeNum, nWeightCode, nCoefficient); - dec->m_ptrNextSource += dec->m_nDegreeNum; - - ptrSrcBuf += dec->m_nDegreeNum; - } - - // revolve - if (is_mss) { - float rSin, rCos; - int nRevCode = *(dec->m_ptrNextRevCode++); - int nRevCode1 = (nRevCode >> 2) & 0x03; - int nRevCode2 = (nRevCode & 0x03); - - float* ptrSrcBuf1 = dec->m_ptrMatrixBuf; - float* ptrSrcBuf2 = dec->m_ptrMatrixBuf + dec->m_nDegreeNum; - - rSin = (float)sin(nRevCode1 * ERI_PI / 8); - rCos = (float)cos(nRevCode1 * ERI_PI / 8); - EMT_eriRevolve2x2(ptrSrcBuf1, ptrSrcBuf2, rSin, rCos, 2, dec->m_nDegreeNum / 2); - - rSin = (float)sin(nRevCode2 * ERI_PI / 8); - rCos = (float)cos(nRevCode2 * ERI_PI / 8); - EMT_eriRevolve2x2(ptrSrcBuf1 + 1, ptrSrcBuf2 + 1, rSin, rCos, 2, dec->m_nDegreeNum / 2); - } - - // inverse LOT + DCT - ptrLapBuf = dec->m_ptrLastDCTBuf; - ptrSrcBuf = dec->m_ptrMatrixBuf; - for (ch = 0; ch < internal_channels; ch++) { - EMT_eriOddGivensInverseMatrix(ptrSrcBuf, dec->m_pRevolveParam, dec->m_nSubbandDegree); - - EMT_eriFastIPLOT(ptrSrcBuf, dec->m_nSubbandDegree); - EMT_eriFastILOT(dec->m_ptrWorkBuf, ptrLapBuf, ptrSrcBuf, dec->m_nSubbandDegree); - - for (i = 0; i < dec->m_nDegreeNum; i++) { - ptrLapBuf[i] = ptrSrcBuf[i]; - ptrSrcBuf[i] = dec->m_ptrWorkBuf[i]; - } - - EMT_eriFastIDCT(dec->m_ptrInternalBuf, ptrSrcBuf, 1, dec->m_ptrWorkBuf, dec->m_nSubbandDegree); - - EMT_eriRoundR32ToWordArray(ptrDst + ch, output_channels, dec->m_ptrInternalBuf, nSamples); - - ptrLapBuf += dec->m_nDegreeNum; - ptrSrcBuf += dec->m_nDegreeNum; - } - - return eslErrSuccess; -} - -static ESLError MIODecoder_DecodePostBlock_All(MIODecoder* dec, SWORD* ptrDst, unsigned int nSamples, int is_mss) { - unsigned int ch, i; - unsigned int nHalfDegree = dec->m_nDegreeNum / 2; - int internal_channels = is_mss ? 2 : 1; - int output_channels = is_mss ? 2 : dec->m_mioih.dwChannelCount; - - SDWORD nWeightCode = *(dec->m_ptrNextWeight++); - int nCoefficient = *(dec->m_ptrNextCoefficient++); - - float* ptrLapBuf; - float* ptrSrcBuf; - - - // dequantize - ptrSrcBuf = dec->m_ptrMatrixBuf; - for (ch = 0; ch < internal_channels; ch++) { - INT* ptrTempBuf = dec->m_ptrBuffer1; - for (i = 0; i < nHalfDegree; i++) { - ptrTempBuf[i * 2] = 0; - ptrTempBuf[i * 2 + 1] = *(dec->m_ptrNextSource++); - } - MIODecoder_IQuantumize(dec, ptrSrcBuf, ptrTempBuf, dec->m_nDegreeNum, nWeightCode, nCoefficient); - - ptrSrcBuf += dec->m_nDegreeNum; - } - - // revolve - if (is_mss) { - float rSin, rCos; - int nRevCode = *(dec->m_ptrNextRevCode++); - - float* ptrSrcBuf1 = dec->m_ptrMatrixBuf; //L - float* ptrSrcBuf2 = dec->m_ptrMatrixBuf + dec->m_nDegreeNum; //R - - rSin = (float)sin(nRevCode * ERI_PI / 8); - rCos = (float)cos(nRevCode * ERI_PI / 8); - EMT_eriRevolve2x2(ptrSrcBuf1, ptrSrcBuf2, rSin, rCos, 1, dec->m_nDegreeNum); - } - - // inverse LOT + DCT - ptrLapBuf = dec->m_ptrLastDCTBuf; - ptrSrcBuf = dec->m_ptrMatrixBuf; - for (ch = 0; ch < internal_channels; ch++) { - EMT_eriOddGivensInverseMatrix(ptrSrcBuf, dec->m_pRevolveParam, dec->m_nSubbandDegree); - - for (i = 0; i < dec->m_nDegreeNum; i += 2) { - ptrSrcBuf[i] = -ptrSrcBuf[i + 1]; - } - - EMT_eriFastIPLOT(ptrSrcBuf, dec->m_nSubbandDegree); - EMT_eriFastILOT(dec->m_ptrWorkBuf, ptrLapBuf, ptrSrcBuf, dec->m_nSubbandDegree); - - for (i = 0; i < dec->m_nDegreeNum; i++) { - ptrSrcBuf[i] = dec->m_ptrWorkBuf[i]; - } - - EMT_eriFastIDCT(dec->m_ptrInternalBuf, ptrSrcBuf, 1, dec->m_ptrWorkBuf, dec->m_nSubbandDegree); - - EMT_eriRoundR32ToWordArray(ptrDst + ch, output_channels, dec->m_ptrInternalBuf, nSamples); - - ptrLapBuf += dec->m_nDegreeNum; - ptrSrcBuf += dec->m_nDegreeNum; - } - - return eslErrSuccess; -} - -////////////////////////////////////////////////////////////////////////////// - -static ESLError MIODecoder_DecodeSoundDCT_Std(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) { - unsigned int i, j, k; - unsigned int nDegreeWidth = (1 << dec->m_mioih.dwSubbandDegree); - unsigned int nSampleCount = (datahdr->dwSampleCount + nDegreeWidth - 1) & ~(nDegreeWidth - 1); - unsigned int nSubbandCount = (nSampleCount >> dec->m_mioih.dwSubbandDegree); - unsigned int nChannelCount = dec->m_mioih.dwChannelCount; - unsigned int nAllSampleCount = nSampleCount * nChannelCount; - unsigned int nAllSubbandCount = nSubbandCount * nChannelCount; - - if (nSampleCount > dec->m_nBufLength) { - free(dec->m_ptrBuffer2); - free(dec->m_ptrBuffer3); - free(dec->m_ptrDivisionTable); - free(dec->m_ptrWeightCode); - free(dec->m_ptrCoefficient); - - dec->m_ptrBuffer2 = malloc(nAllSampleCount * sizeof(INT)); - dec->m_ptrBuffer3 = malloc(nAllSampleCount * sizeof(SWORD)); - dec->m_ptrDivisionTable = malloc(nAllSubbandCount * sizeof(BYTE)); - dec->m_ptrWeightCode = malloc(nAllSubbandCount * 5 * sizeof(SDWORD)); - dec->m_ptrCoefficient = malloc(nAllSubbandCount * 5 * sizeof(INT)); - if (!dec->m_ptrBuffer2 || !dec->m_ptrBuffer3 || !dec->m_ptrDivisionTable || !dec->m_ptrWeightCode || !dec->m_ptrCoefficient) - return eslErrGeneral; - - dec->m_nBufLength = nSampleCount; - } - - // decode quantization table - if (MIOContext_GetABit(context) != 0) { - return eslErrGeneral; - } - - unsigned int pLastDivision[MIO_MAX_CHANNELS]; - for (i = 0; i < nChannelCount; i++) { - pLastDivision[i] = -1; - } - - dec->m_ptrNextDivision = dec->m_ptrDivisionTable; - dec->m_ptrNextWeight = dec->m_ptrWeightCode; - dec->m_ptrNextCoefficient = dec->m_ptrCoefficient; - - for (i = 0; i < nSubbandCount; i++) { - for (j = 0; j < nChannelCount; j++) { - unsigned int nDivisionCode = MIOContext_GetNBits(context, 2); - *(dec->m_ptrNextDivision++) = (BYTE)nDivisionCode; - - if (nDivisionCode != pLastDivision[j]) { - if (i != 0) { - *(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32); - *(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16); - } - pLastDivision[j] = nDivisionCode; - } - - unsigned int nDivisionCount = (1 << nDivisionCode); - for (k = 0; k < nDivisionCount; k++) { - *(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32); - *(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16); - } - } - } - if (nSubbandCount > 0) { - for (i = 0; i < nChannelCount; i++) { - *(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32); - *(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16); - } - } - - /* sync? */ - if (MIOContext_GetABit(context) != 0) { - return eslErrGeneral; - } - - // init code model if needed - if (datahdr->bytFlags & MIO_LEAD_BLOCK) { - if (dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE) { - ESLError err = MIOContext_PrepareToDecodeERINACode(context, ERINAEncodingFlag_efERINAOrder1); - if (err != eslErrSuccess) return err; - } - else { - ESLError err = MIOContext_PrepareToDecodeERISACode(context); - if (err != eslErrSuccess) return err; - } - } - else if (dec->m_mioih.dwArchitecture == ERISA_NEMESIS_CODE) { - MIOContext_InitializeERISACode(context); - } - - // decode and deinterleave - if (dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE) { - if (MIOContext_DecodeSymbolBytes(context, dec->m_ptrBuffer3, nAllSampleCount * 2) < nAllSampleCount * 2) { - return eslErrGeneral; - } - - SBYTE* ptrHBuf = dec->m_ptrBuffer3; - SBYTE* ptrLBuf = ptrHBuf + nAllSampleCount; - - for (i = 0; i < nDegreeWidth; i++) { - INT* ptrQuantumized = ((INT*)dec->m_ptrBuffer2) + i; - - for (j = 0; j < nAllSubbandCount; j++) { - INT nLow = *(ptrLBuf++); - INT nHigh = *(ptrHBuf++) ^ (nLow >> 8); - *ptrQuantumized = (nLow & 0xFF) | (nHigh << 8); - ptrQuantumized += nDegreeWidth; - } - } - } - else { - if (MIOContext_DecodeERISACodeWords(context, (SWORD*)dec->m_ptrBuffer3, nAllSampleCount) < nAllSampleCount) { - return eslErrGeneral; - } - SWORD* ptrTmp = dec->m_ptrBuffer3; - for (i = 0; i < nAllSampleCount; i++) { - ((INT*)dec->m_ptrBuffer2)[i] = (ptrTmp)[i]; - } - } - - // apply iDCT to subband units - unsigned int nSamples; - unsigned int pRestSamples[MIO_MAX_CHANNELS]; - SWORD* ptrDstBuf[MIO_MAX_CHANNELS]; - - dec->m_ptrNextDivision = dec->m_ptrDivisionTable; - dec->m_ptrNextWeight = dec->m_ptrWeightCode; - dec->m_ptrNextCoefficient = dec->m_ptrCoefficient; - dec->m_ptrNextSource = dec->m_ptrBuffer2; - - for (i = 0; i < nChannelCount; i++) { - pLastDivision[i] = -1; - pRestSamples[i] = datahdr->dwSampleCount; - ptrDstBuf[i] = ((SWORD*)ptrWaveBuf) + i; - } - unsigned int nCurrentDivision = -1; - - for (i = 0; i < nSubbandCount; i++) { - for (j = 0; j < nChannelCount; j++) { - // get division/decomposition code - unsigned int nDivisionCode = *(dec->m_ptrNextDivision++); - unsigned int nDivisionCount = (1 << nDivisionCode); - - // get buffer for duplicate processing - int nChannelStep = nDegreeWidth * dec->m_mioih.dwLappedDegree * j; - dec->m_ptrLastDCTBuf = dec->m_ptrLastDCT + nChannelStep; - - // processing when matrix size changes - int bLeadBlock = 0; - - if (pLastDivision[j] != nDivisionCode) { - // complete until last moment - if (i != 0) { - if (nCurrentDivision != pLastDivision[j]) { - if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree - pLastDivision[j])) - return eslErrGeneral; - nCurrentDivision = pLastDivision[j]; - } - nSamples = pRestSamples[j]; - if (nSamples > dec->m_nDegreeNum) { - nSamples = dec->m_nDegreeNum; - } - if (MIODecoder_DecodePostBlock_All(dec, ptrDstBuf[j], nSamples, 0)) { - return eslErrGeneral; - } - pRestSamples[j] -= nSamples; - ptrDstBuf[j] += nSamples * nChannelCount; - } - - // set params to change matrix size - pLastDivision[j] = nDivisionCode; - bLeadBlock = 1; - } - if (nCurrentDivision != nDivisionCode) { - if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree - nDivisionCode)) - return eslErrGeneral; - nCurrentDivision = nDivisionCode; - } - - // perform sequential iLOT - for (k = 0; k < nDivisionCount; k++) { - if (bLeadBlock) { - // decode lead block - if (MIODecoder_DecodeLeadBlock_All(dec, 0)) { - return eslErrGeneral; - } - - bLeadBlock = 0; - } - else { - // decode regular block - nSamples = pRestSamples[j]; - if (nSamples > dec->m_nDegreeNum) { - nSamples = dec->m_nDegreeNum; - } - if (MIODecoder_DecodeInternalBlock_All(dec, ptrDstBuf[j], nSamples, 0)) { - return eslErrGeneral; - } - pRestSamples[j] -= nSamples; - ptrDstBuf[j] += nSamples * nChannelCount; - } - } - } - } - - // complete the matrix - if (nSubbandCount > 0) { - for (i = 0; i < nChannelCount; i++) { - int nChannelStep = nDegreeWidth * dec->m_mioih.dwLappedDegree * i; - dec->m_ptrLastDCTBuf = dec->m_ptrLastDCT + nChannelStep; - - if (nCurrentDivision != pLastDivision[i]) { - if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree - pLastDivision[i])) - return eslErrGeneral; - nCurrentDivision = pLastDivision[i]; - } - nSamples = pRestSamples[i]; - if (nSamples > dec->m_nDegreeNum) { - nSamples = dec->m_nDegreeNum; - } - if (MIODecoder_DecodePostBlock_All(dec, ptrDstBuf[i], nSamples, 0)) { - return eslErrGeneral; - } - pRestSamples[i] -= nSamples; - ptrDstBuf[i] += nSamples * nChannelCount; - } - } - - return eslErrSuccess; -} - -static ESLError MIODecoder_DecodeSoundDCT_MSS(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) { - unsigned int i, j, k; - unsigned int nDegreeWidth = (1 << dec->m_mioih.dwSubbandDegree); - unsigned int nSampleCount = (datahdr->dwSampleCount + nDegreeWidth - 1) & ~(nDegreeWidth - 1); - unsigned int nSubbandCount = (nSampleCount >> dec->m_mioih.dwSubbandDegree); - unsigned int nChannelCount = dec->m_mioih.dwChannelCount; // usually 2 - unsigned int nAllSampleCount = nSampleCount * nChannelCount; - unsigned int nAllSubbandCount = nSubbandCount; - - if (nSampleCount > dec->m_nBufLength) { - free(dec->m_ptrBuffer2); - free(dec->m_ptrBuffer3); - free(dec->m_ptrDivisionTable); - free(dec->m_ptrRevolveCode); - free(dec->m_ptrWeightCode); - free(dec->m_ptrCoefficient); - - dec->m_ptrBuffer2 = malloc(nAllSampleCount * sizeof(INT)); - dec->m_ptrBuffer3 = malloc(nAllSampleCount * sizeof(SWORD)); - dec->m_ptrDivisionTable = malloc(nAllSubbandCount * sizeof(BYTE)); - dec->m_ptrRevolveCode = malloc(nAllSubbandCount * 10 * sizeof(BYTE)); - dec->m_ptrWeightCode = malloc(nAllSubbandCount * 10 * sizeof(SDWORD)); - dec->m_ptrCoefficient = malloc(nAllSubbandCount * 10 * sizeof(INT)); - if (!dec->m_ptrBuffer2 || !dec->m_ptrBuffer3 || !dec->m_ptrDivisionTable || !dec->m_ptrRevolveCode || !dec->m_ptrWeightCode || !dec->m_ptrCoefficient) - return eslErrGeneral; - - dec->m_nBufLength = nSampleCount; - } - - // decode quantization table - if (MIOContext_GetABit(context) != 0) { - return eslErrGeneral; - } - - unsigned int nLastDivision = -1; - - dec->m_ptrNextDivision = dec->m_ptrDivisionTable; - dec->m_ptrNextRevCode = dec->m_ptrRevolveCode; - dec->m_ptrNextWeight = dec->m_ptrWeightCode; - dec->m_ptrNextCoefficient = dec->m_ptrCoefficient; - - for (i = 0; i < nSubbandCount; i++) { - unsigned int nDivisionCode = MIOContext_GetNBits(context, 2); - *(dec->m_ptrNextDivision++) = (BYTE)nDivisionCode; - - int bLeadBlock = 0; - if (nDivisionCode != nLastDivision) { - if (i != 0) { - *(dec->m_ptrNextRevCode++) = MIOContext_GetNBits(context, 2); - *(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32); - *(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16); - } - bLeadBlock = 1; - nLastDivision = nDivisionCode; - } - - unsigned int nDivisionCount = (1 << nDivisionCode); - for (k = 0; k < nDivisionCount; k++) { - if (bLeadBlock) { - *(dec->m_ptrNextRevCode++) = MIOContext_GetNBits(context, 2); - bLeadBlock = 0; - } - else { - *(dec->m_ptrNextRevCode++) = MIOContext_GetNBits(context, 4); - } - *(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32); - *(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16); - } - } - if (nSubbandCount > 0) { - *(dec->m_ptrNextRevCode++) = MIOContext_GetNBits(context, 2); - *(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32); - *(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16); - } - - if (MIOContext_GetABit(context) != 0) { - return eslErrGeneral; - } - - if (datahdr->bytFlags & MIO_LEAD_BLOCK) { - if (dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE) { - ESLError err = MIOContext_PrepareToDecodeERINACode(context, ERINAEncodingFlag_efERINAOrder1); - if (err != eslErrSuccess) return err; - } - else { - ESLError err = MIOContext_PrepareToDecodeERISACode(context); - if (err != eslErrSuccess) return err; - } - } - else if (dec->m_mioih.dwArchitecture == ERISA_NEMESIS_CODE) { - MIOContext_InitializeERISACode(context); - } - - // decode and deinterleave - if (dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE) { - if (MIOContext_DecodeSymbolBytes(context, dec->m_ptrBuffer3, nAllSampleCount * 2) < nAllSampleCount * 2) { - return eslErrGeneral; - } - - SBYTE* ptrHBuf = dec->m_ptrBuffer3; - SBYTE* ptrLBuf = ptrHBuf + nAllSampleCount; - - for (i = 0; i < nDegreeWidth * 2; i++) { - INT* ptrQuantumized = ((INT*)dec->m_ptrBuffer2) + i; - - for (j = 0; j < nAllSubbandCount; j++) { - INT nLow = *(ptrLBuf++); - INT nHigh = *(ptrHBuf++) ^ (nLow >> 8); - *ptrQuantumized = (nLow & 0xFF) | (nHigh << 8); - ptrQuantumized += nDegreeWidth * 2; - } - } - } - else { - if (MIOContext_DecodeERISACodeWords(context, (SWORD*)dec->m_ptrBuffer3, nAllSampleCount) < nAllSampleCount) { - return eslErrGeneral; - } - SWORD* ptrTmp = dec->m_ptrBuffer3; - for (i = 0; i < nAllSampleCount; i++) { - ((INT*)dec->m_ptrBuffer2)[i] = (ptrTmp)[i]; - } - } - - // apply iDCT to subband units - unsigned int nSamples; - unsigned int nRestSamples = datahdr->dwSampleCount; - SWORD* ptrDstBuf = ptrWaveBuf; - - nLastDivision = -1; - dec->m_ptrNextDivision = dec->m_ptrDivisionTable; - dec->m_ptrNextRevCode = dec->m_ptrRevolveCode; - dec->m_ptrNextWeight = dec->m_ptrWeightCode; - dec->m_ptrNextCoefficient = dec->m_ptrCoefficient; - dec->m_ptrNextSource = dec->m_ptrBuffer2; - - for (i = 0; i < nSubbandCount; i++) { - // get division/decomposition code - unsigned int nDivisionCode = *(dec->m_ptrNextDivision++); - unsigned int nDivisionCount = (1 << nDivisionCode); - - // processing when matrix size changes - int bLeadBlock = 0; - dec->m_ptrLastDCTBuf = dec->m_ptrLastDCT; - - if (nLastDivision != nDivisionCode) { - // complete until last moment - if (i != 0) { - nSamples = nRestSamples; - if (nSamples > dec->m_nDegreeNum) { - nSamples = dec->m_nDegreeNum; - } - if (MIODecoder_DecodePostBlock_All(dec, ptrDstBuf, nSamples, 1)) { - return eslErrGeneral; - } - nRestSamples -= nSamples; - ptrDstBuf += nSamples * nChannelCount; - } - - // set params to change matrix size - if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree - nDivisionCode)) - return eslErrGeneral; - nLastDivision = nDivisionCode; - bLeadBlock = 1; - } - - // perform sequential iLOT - for (k = 0; k < nDivisionCount; k++) { - if (bLeadBlock) { - // decode lead block - if (MIODecoder_DecodeLeadBlock_All(dec, 1)) { - return eslErrGeneral; - } - - bLeadBlock = 0; - } - else { - // decode regular block - nSamples = nRestSamples; - if (nSamples > dec->m_nDegreeNum) { - nSamples = dec->m_nDegreeNum; - } - if (MIODecoder_DecodeInternalBlock_All(dec, ptrDstBuf, nSamples, 1)) { - return eslErrGeneral; - } - nRestSamples -= nSamples; - ptrDstBuf += nSamples * nChannelCount; - } - } - } - - // complete the matrix - if (nSubbandCount > 0) { - dec->m_ptrLastDCTBuf = dec->m_ptrLastDCT; - - nSamples = nRestSamples; - if (nSamples > dec->m_nDegreeNum) - nSamples = dec->m_nDegreeNum; - - if (MIODecoder_DecodePostBlock_All(dec, ptrDstBuf, nSamples, 1)) { - return eslErrGeneral; - } - nRestSamples -= nSamples; - ptrDstBuf += nSamples * nChannelCount; - } - - return eslErrSuccess; -} - -ESLError MIODecoder_DecodeSound(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) { - MIOContext_FlushBuffer(context); - - if (dec->m_mioih.fdwTransformation == CVTYPE_LOSSLESS_ERI) { - if (dec->m_mioih.dwBitsPerSample == 8) { - return MIODecoder_DecodeSoundPCM8(dec, context, datahdr, ptrWaveBuf); - } - else if (dec->m_mioih.dwBitsPerSample == 16) { - return MIODecoder_DecodeSoundPCM16(dec, context, datahdr, ptrWaveBuf); - } - } - else if ((dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI) || (dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI_MSS)) { - if ((dec->m_mioih.dwChannelCount != 2) || (dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI)) { - return MIODecoder_DecodeSoundDCT_Std(dec, context, datahdr, ptrWaveBuf); - } - else { - return MIODecoder_DecodeSoundDCT_MSS(dec, context, datahdr, ptrWaveBuf); - } - } - - return eslErrGeneral; -} +/***************************************************************************** + E R I S A - L i b r a r y + ----------------------------------------------------------------------------- + Copyright (C) 2002-2003 Leshade Entis, Entis-soft. All rights reserved. + *****************************************************************************/ + +#include +#include +#include "mio_xerisa.h" + +static const double ERI_PI = 3.141592653589; +#define MIO_MAX_CHANNELS 2 + + +/*******************/ +/* audio converter */ +/*******************/ + +MIODecoder* MIODecoder_Open() { + MIODecoder* dec = calloc(1, sizeof(MIODecoder)); + if (!dec) + return NULL; + + dec->m_nBufLength = 0; + dec->m_ptrBuffer1 = NULL; + dec->m_ptrBuffer2 = NULL; + dec->m_ptrBuffer3 = NULL; + dec->m_ptrDivisionTable = NULL; + dec->m_ptrRevolveCode = NULL; + dec->m_ptrWeightCode = NULL; + dec->m_ptrCoefficient = NULL; + dec->m_ptrMatrixBuf = NULL; + dec->m_ptrInternalBuf = NULL; + dec->m_ptrWorkBuf = NULL; + dec->m_ptrWeightTable = NULL; + dec->m_ptrLastDCT = NULL; + dec->m_pRevolveParam = NULL; + return dec; +} + +static void MIODecoder_Delete(MIODecoder* dec) { + free(dec->m_ptrBuffer1); + dec->m_ptrBuffer1 = NULL; + free(dec->m_ptrBuffer2); + dec->m_ptrBuffer2 = NULL; + free(dec->m_ptrBuffer3); + dec->m_ptrBuffer3 = NULL; + free(dec->m_ptrDivisionTable); + dec->m_ptrDivisionTable = NULL; + free(dec->m_ptrRevolveCode); + dec->m_ptrRevolveCode = NULL; + free(dec->m_ptrWeightCode); + dec->m_ptrWeightCode = NULL; + free(dec->m_ptrCoefficient); + dec->m_ptrCoefficient = NULL; + free(dec->m_ptrMatrixBuf); + dec->m_ptrMatrixBuf = NULL; + free(dec->m_ptrInternalBuf); + dec->m_ptrInternalBuf = NULL; + free(dec->m_ptrWorkBuf); + dec->m_ptrWorkBuf = NULL; + free(dec->m_ptrWeightTable); + dec->m_ptrWeightTable = NULL; + free(dec->m_ptrLastDCT); + dec->m_ptrLastDCT = NULL; + free(dec->m_pRevolveParam); + dec->m_pRevolveParam = NULL; + + dec->m_nBufLength = 0; +} + +void MIODecoder_Close(MIODecoder* dec) { + if (!dec) + return; + MIODecoder_Delete(dec); + free(dec); +} + +// recalculate matrix size when params change +static int MIODecoder_InitializeWithDegree(MIODecoder* dec, unsigned int nSubbandDegree) { + free(dec->m_pRevolveParam); + dec->m_pRevolveParam = EMT_eriCreateRevolveParameter(nSubbandDegree); + if (!dec->m_pRevolveParam) return eslErrGeneral; + + // params for inverse quantization + static const int freq_width[7] = { -6, -6, -5, -4, -3, -2, -1 }; + for (int i = 0, j = 0; i < 7; i++) { + int nFrequencyWidth = 1 << (nSubbandDegree + freq_width[i]); + dec->m_nFrequencyPoint[i] = j + (nFrequencyWidth / 2); + j += nFrequencyWidth; + } + + dec->m_nSubbandDegree = nSubbandDegree; + dec->m_nDegreeNum = (1 << nSubbandDegree); + + return eslErrSuccess; +} + +ESLError MIODecoder_Initialize(MIODecoder* dec, const MIO_INFO_HEADER* infhdr) { + MIODecoder_Delete(dec); + + dec->m_mioih = *infhdr; /* copy */ + + if (dec->m_mioih.fdwTransformation == CVTYPE_LOSSLESS_ERI) { + if (dec->m_mioih.dwArchitecture != ERI_RUNLENGTH_HUFFMAN) + return eslErrGeneral; + + if ((dec->m_mioih.dwChannelCount != 1) && (dec->m_mioih.dwChannelCount != 2)) + return eslErrGeneral; + + if ((dec->m_mioih.dwBitsPerSample != 8) && (dec->m_mioih.dwBitsPerSample != 16)) + return eslErrGeneral; + } + else if ((dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI) || (dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI_MSS)) { + + if ((dec->m_mioih.dwArchitecture != ERI_RUNLENGTH_GAMMA) && + (dec->m_mioih.dwArchitecture != ERI_RUNLENGTH_HUFFMAN) && + (dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE)) + return eslErrGeneral; /* unknown code format */ + + if ((dec->m_mioih.dwChannelCount != 1) && (dec->m_mioih.dwChannelCount != 2)) + return eslErrGeneral; + + if (dec->m_mioih.dwBitsPerSample != 16) + return eslErrGeneral; + + if ((dec->m_mioih.dwSubbandDegree < 8) || (dec->m_mioih.dwSubbandDegree > MAX_DCT_DEGREE)) + return eslErrGeneral; + + if (dec->m_mioih.dwLappedDegree != 1) + return eslErrGeneral; + + // DCT buffers + { + int channel_size = sizeof(float) << dec->m_mioih.dwSubbandDegree; + int buf_size = dec->m_mioih.dwChannelCount * channel_size; + dec->m_ptrBuffer1 = malloc(buf_size); + dec->m_ptrMatrixBuf = malloc(buf_size); + dec->m_ptrInternalBuf = malloc(buf_size); + dec->m_ptrWorkBuf = malloc(channel_size); + if (!dec->m_ptrBuffer1 || !dec->m_ptrMatrixBuf || !dec->m_ptrInternalBuf || !dec->m_ptrWorkBuf) + return eslErrGeneral; + } + + // dequantization buffers + { + int channel_size = sizeof(float) << dec->m_mioih.dwSubbandDegree; + dec->m_ptrWeightTable = malloc(channel_size); + if (!dec->m_ptrWeightTable) + return eslErrGeneral; + } + + // LOT buffers + { + int nBlocksetSamples = dec->m_mioih.dwChannelCount << dec->m_mioih.dwSubbandDegree; + int nLappedSamples = nBlocksetSamples * dec->m_mioih.dwLappedDegree; + if (nLappedSamples > 0) { + dec->m_ptrLastDCT = malloc(sizeof(float) * nLappedSamples); + if (!dec->m_ptrLastDCT) + return eslErrGeneral; + + for (int i = 0; i < nLappedSamples; i++) { + dec->m_ptrLastDCT[i] = 0.0F; + } + } + } + + if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree)) + return eslErrGeneral; + } + else { + return eslErrGeneral; + } + + return eslErrSuccess; +} + +static ESLError MIODecoder_DecodeSoundPCM8(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) { + unsigned int nSampleCount = datahdr->dwSampleCount; + unsigned int nChannelCount = dec->m_mioih.dwChannelCount; + unsigned int nAllSampleCount = nSampleCount * nChannelCount; + ULONG nBytes = nAllSampleCount * sizeof(BYTE); + + if (nSampleCount > dec->m_nBufLength) { + free(dec->m_ptrBuffer1); + dec->m_ptrBuffer1 = malloc(nBytes); + if (!dec->m_ptrBuffer1) + return eslErrGeneral; + + dec->m_nBufLength = nSampleCount; + } + + // prepare huffman codes + if (datahdr->bytFlags & MIO_LEAD_BLOCK) { + ESLError err = MIOContext_PrepareToDecodeERINACode(context, ERINAEncodingFlag_efERINAOrder1); + if (err != eslErrSuccess) return err; + } + + if (MIOContext_DecodeSymbolBytes(context, (SBYTE*)dec->m_ptrBuffer1, nBytes) < nBytes) { + return eslErrGeneral; + } + + // differential processing output + BYTE* ptrSrcBuf = dec->m_ptrBuffer1; + BYTE* ptrDstBuf; + unsigned int nStep = nChannelCount; + unsigned int i, j; + for (i = 0; i < dec->m_mioih.dwChannelCount; i++) { + ptrDstBuf = ptrWaveBuf; + ptrDstBuf += i; + + BYTE bytValue = 0; + for (j = 0; j < nSampleCount; j++) { + bytValue += *(ptrSrcBuf++); + *ptrDstBuf = bytValue; + ptrDstBuf += nStep; + } + } + + return eslErrSuccess; +} + +static ESLError MIODecoder_DecodeSoundPCM16(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) { + unsigned int i, j; + unsigned int nSampleCount = datahdr->dwSampleCount; + unsigned int nChannelCount = dec->m_mioih.dwChannelCount; + unsigned int nAllSampleCount = nSampleCount * nChannelCount; + ULONG nBytes = nAllSampleCount * sizeof(SWORD); + + if (nSampleCount > dec->m_nBufLength) { + free(dec->m_ptrBuffer1); + free(dec->m_ptrBuffer2); + dec->m_ptrBuffer1 = malloc(nBytes); + dec->m_ptrBuffer2 = malloc(nBytes); + if (!dec->m_ptrBuffer1 || !dec->m_ptrBuffer2) + return eslErrGeneral; + + dec->m_nBufLength = nSampleCount; + } + + // prepare huffman codes + if (datahdr->bytFlags & MIO_LEAD_BLOCK) { + ESLError err = MIOContext_PrepareToDecodeERINACode(context, ERINAEncodingFlag_efERINAOrder1); + if (err != eslErrSuccess) return err; + } + + if (MIOContext_DecodeSymbolBytes(context, (SBYTE*)dec->m_ptrBuffer1, nBytes) < nBytes) { + return eslErrGeneral; + } + + // pack hi/lo bytes + BYTE* pbytSrcBuf1; + BYTE* pbytSrcBuf2; + BYTE* pbytDstBuf; + for (i = 0; i < nChannelCount; i++) { + unsigned int nOffset = i * nSampleCount * sizeof(SWORD); + pbytSrcBuf1 = ((BYTE*)dec->m_ptrBuffer1) + nOffset; + pbytSrcBuf2 = pbytSrcBuf1 + nSampleCount; + pbytDstBuf = ((BYTE*)dec->m_ptrBuffer2) + nOffset; + + for (j = 0; j < nSampleCount; j++) { + SBYTE bytLow = pbytSrcBuf2[j]; + SBYTE bytHigh = pbytSrcBuf1[j]; + pbytDstBuf[j * sizeof(SWORD) + 0] = bytLow; + pbytDstBuf[j * sizeof(SWORD) + 1] = bytHigh ^ (bytLow >> 7); + } + } + + // differential processing output + SWORD* ptrSrcBuf = dec->m_ptrBuffer2; + SWORD* ptrDstBuf; + unsigned int nStep = dec->m_mioih.dwChannelCount; + for (i = 0; i < dec->m_mioih.dwChannelCount; i++) { + ptrDstBuf = ptrWaveBuf; + ptrDstBuf += i; + + SWORD wValue = 0; + SWORD wDelta = 0; + for (j = 0; j < nSampleCount; j++) { + wDelta += *(ptrSrcBuf++); + wValue += wDelta; + *ptrDstBuf = wValue; + ptrDstBuf += nStep; + } + } + + return eslErrSuccess; +} + +////////////////////////////////////////////////////////////////////////////// + +static void MIODecoder_IQuantumize(MIODecoder* dec, float* ptrDestination, const INT* ptrQuantumized, int nDegreeNum, SDWORD nWeightCode, int nCoefficient) { + int i, j; + double rMatrixScale = sqrt(2.0 / nDegreeNum); + double rCoefficient = rMatrixScale * nCoefficient; + + // generate weight table + double rAvgRatio[7]; + for (i = 0; i < 6; i++) { + rAvgRatio[i] = 1.0 / pow(2.0, (((nWeightCode >> (i * 5)) & 0x1F) - 15) * 0.5); + } + rAvgRatio[6] = 1.0; + + for (i = 0; i < dec->m_nFrequencyPoint[0]; i++) { + dec->m_ptrWeightTable[i] = (float)rAvgRatio[0]; + } + + for (j = 1; j < 7; j++) { + double a = rAvgRatio[j - 1]; + double k = (rAvgRatio[j] - a) / (dec->m_nFrequencyPoint[j] - dec->m_nFrequencyPoint[j - 1]); + while (i < dec->m_nFrequencyPoint[j]) { + dec->m_ptrWeightTable[i] = (float)(k * (i - dec->m_nFrequencyPoint[j - 1]) + a); + i++; + } + } + + while (i < nDegreeNum) { + dec->m_ptrWeightTable[i] = (float)rAvgRatio[6]; + i++; + } + + float rOddWeight = (float)((((nWeightCode >> 30) & 0x03) + 0x02) / 2.0); + for (i = 15; i < nDegreeNum; i += 16) { + dec->m_ptrWeightTable[i] *= rOddWeight; + } + dec->m_ptrWeightTable[nDegreeNum - 1] = (float)nCoefficient; + + for (i = 0; i < nDegreeNum; i++) { + dec->m_ptrWeightTable[i] = 1.0F / dec->m_ptrWeightTable[i]; + } + + // dequantize + for (i = 0; i < nDegreeNum; i++) { + ptrDestination[i] = (float)(rCoefficient * dec->m_ptrWeightTable[i] * ptrQuantumized[i]); + } +} + +////////////////////////////////////////////////////////////////////////////// + +/* Dequantizes and transforms block frames. Lib divides them into "lead" (keyframes), + * "internal" (standard) and "post" blocks, handled slightly differently. All of them can be MSS + * blocks, which OG code handles in a separate function (presumably as a minor optimization to + * avoid setting extra FORs), but here are handled with a flag since they are very similar. */ + +static ESLError MIODecoder_DecodeLeadBlock_All(MIODecoder* dec, int is_mss) { + unsigned int ch, i; + unsigned int nHalfDegree = dec->m_nDegreeNum / 2; + int internal_channels = is_mss ? 2 : 1; + //int output_channels = is_mss ? 2 : dec->m_mioih.dwChannelCount; + + SDWORD nWeightCode = *(dec->m_ptrNextWeight++); + int nCoefficient = *(dec->m_ptrNextCoefficient++); + + float* ptrLapBuf; + + + // dequantize + ptrLapBuf = dec->m_ptrLastDCTBuf; + for (ch = 0; ch < internal_channels; ch++) { + INT* ptrTempBuf = dec->m_ptrBuffer1; + for (i = 0; i < nHalfDegree; i++) { + ptrTempBuf[i * 2] = 0; + ptrTempBuf[i * 2 + 1] = *(dec->m_ptrNextSource++); + } + MIODecoder_IQuantumize(dec, ptrLapBuf, ptrTempBuf, dec->m_nDegreeNum, nWeightCode, nCoefficient); + + ptrLapBuf += dec->m_nDegreeNum; + } + + // revolve + if (is_mss) { + float rSin, rCos; + int nRevCode = *(dec->m_ptrNextRevCode++); + + float* ptrLapBuf1 = dec->m_ptrLastDCT; + float* ptrLapBuf2 = dec->m_ptrLastDCT + dec->m_nDegreeNum; + + rSin = (float)sin(nRevCode * ERI_PI / 8); + rCos = (float)cos(nRevCode * ERI_PI / 8); + EMT_eriRevolve2x2(ptrLapBuf1, ptrLapBuf2, rSin, rCos, 1, dec->m_nDegreeNum); + } + + // set duplicate parameters + ptrLapBuf = dec->m_ptrLastDCTBuf; + for (ch = 0; ch < internal_channels; ch++) { + EMT_eriOddGivensInverseMatrix(ptrLapBuf, dec->m_pRevolveParam, dec->m_nSubbandDegree); + + for (i = 0; i < dec->m_nDegreeNum; i += 2) { + ptrLapBuf[i] = ptrLapBuf[i + 1]; + } + + EMT_eriFastIPLOT(ptrLapBuf, dec->m_nSubbandDegree); + + ptrLapBuf += dec->m_nDegreeNum; + } + + return eslErrSuccess; +} + +static ESLError MIODecoder_DecodeInternalBlock_All(MIODecoder* dec, SWORD* ptrDst, unsigned int nSamples, int is_mss) { + unsigned int ch, i; + int internal_channels = is_mss ? 2 : 1; + int output_channels = is_mss ? 2 : dec->m_mioih.dwChannelCount; + + SDWORD nWeightCode = *(dec->m_ptrNextWeight++); + int nCoefficient = *(dec->m_ptrNextCoefficient++); + + float* ptrLapBuf; + float* ptrSrcBuf; + + // dequantize + ptrSrcBuf = dec->m_ptrMatrixBuf; + for (ch = 0; ch < internal_channels; ch++) { + MIODecoder_IQuantumize(dec, ptrSrcBuf, dec->m_ptrNextSource, dec->m_nDegreeNum, nWeightCode, nCoefficient); + dec->m_ptrNextSource += dec->m_nDegreeNum; + + ptrSrcBuf += dec->m_nDegreeNum; + } + + // revolve + if (is_mss) { + float rSin, rCos; + int nRevCode = *(dec->m_ptrNextRevCode++); + int nRevCode1 = (nRevCode >> 2) & 0x03; + int nRevCode2 = (nRevCode & 0x03); + + float* ptrSrcBuf1 = dec->m_ptrMatrixBuf; + float* ptrSrcBuf2 = dec->m_ptrMatrixBuf + dec->m_nDegreeNum; + + rSin = (float)sin(nRevCode1 * ERI_PI / 8); + rCos = (float)cos(nRevCode1 * ERI_PI / 8); + EMT_eriRevolve2x2(ptrSrcBuf1, ptrSrcBuf2, rSin, rCos, 2, dec->m_nDegreeNum / 2); + + rSin = (float)sin(nRevCode2 * ERI_PI / 8); + rCos = (float)cos(nRevCode2 * ERI_PI / 8); + EMT_eriRevolve2x2(ptrSrcBuf1 + 1, ptrSrcBuf2 + 1, rSin, rCos, 2, dec->m_nDegreeNum / 2); + } + + // inverse LOT + DCT + ptrLapBuf = dec->m_ptrLastDCTBuf; + ptrSrcBuf = dec->m_ptrMatrixBuf; + for (ch = 0; ch < internal_channels; ch++) { + EMT_eriOddGivensInverseMatrix(ptrSrcBuf, dec->m_pRevolveParam, dec->m_nSubbandDegree); + + EMT_eriFastIPLOT(ptrSrcBuf, dec->m_nSubbandDegree); + EMT_eriFastILOT(dec->m_ptrWorkBuf, ptrLapBuf, ptrSrcBuf, dec->m_nSubbandDegree); + + for (i = 0; i < dec->m_nDegreeNum; i++) { + ptrLapBuf[i] = ptrSrcBuf[i]; + ptrSrcBuf[i] = dec->m_ptrWorkBuf[i]; + } + + EMT_eriFastIDCT(dec->m_ptrInternalBuf, ptrSrcBuf, 1, dec->m_ptrWorkBuf, dec->m_nSubbandDegree); + + EMT_eriRoundR32ToWordArray(ptrDst + ch, output_channels, dec->m_ptrInternalBuf, nSamples); + + ptrLapBuf += dec->m_nDegreeNum; + ptrSrcBuf += dec->m_nDegreeNum; + } + + return eslErrSuccess; +} + +static ESLError MIODecoder_DecodePostBlock_All(MIODecoder* dec, SWORD* ptrDst, unsigned int nSamples, int is_mss) { + unsigned int ch, i; + unsigned int nHalfDegree = dec->m_nDegreeNum / 2; + int internal_channels = is_mss ? 2 : 1; + int output_channels = is_mss ? 2 : dec->m_mioih.dwChannelCount; + + SDWORD nWeightCode = *(dec->m_ptrNextWeight++); + int nCoefficient = *(dec->m_ptrNextCoefficient++); + + float* ptrLapBuf; + float* ptrSrcBuf; + + + // dequantize + ptrSrcBuf = dec->m_ptrMatrixBuf; + for (ch = 0; ch < internal_channels; ch++) { + INT* ptrTempBuf = dec->m_ptrBuffer1; + for (i = 0; i < nHalfDegree; i++) { + ptrTempBuf[i * 2] = 0; + ptrTempBuf[i * 2 + 1] = *(dec->m_ptrNextSource++); + } + MIODecoder_IQuantumize(dec, ptrSrcBuf, ptrTempBuf, dec->m_nDegreeNum, nWeightCode, nCoefficient); + + ptrSrcBuf += dec->m_nDegreeNum; + } + + // revolve + if (is_mss) { + float rSin, rCos; + int nRevCode = *(dec->m_ptrNextRevCode++); + + float* ptrSrcBuf1 = dec->m_ptrMatrixBuf; //L + float* ptrSrcBuf2 = dec->m_ptrMatrixBuf + dec->m_nDegreeNum; //R + + rSin = (float)sin(nRevCode * ERI_PI / 8); + rCos = (float)cos(nRevCode * ERI_PI / 8); + EMT_eriRevolve2x2(ptrSrcBuf1, ptrSrcBuf2, rSin, rCos, 1, dec->m_nDegreeNum); + } + + // inverse LOT + DCT + ptrLapBuf = dec->m_ptrLastDCTBuf; + ptrSrcBuf = dec->m_ptrMatrixBuf; + for (ch = 0; ch < internal_channels; ch++) { + EMT_eriOddGivensInverseMatrix(ptrSrcBuf, dec->m_pRevolveParam, dec->m_nSubbandDegree); + + for (i = 0; i < dec->m_nDegreeNum; i += 2) { + ptrSrcBuf[i] = -ptrSrcBuf[i + 1]; + } + + EMT_eriFastIPLOT(ptrSrcBuf, dec->m_nSubbandDegree); + EMT_eriFastILOT(dec->m_ptrWorkBuf, ptrLapBuf, ptrSrcBuf, dec->m_nSubbandDegree); + + for (i = 0; i < dec->m_nDegreeNum; i++) { + ptrSrcBuf[i] = dec->m_ptrWorkBuf[i]; + } + + EMT_eriFastIDCT(dec->m_ptrInternalBuf, ptrSrcBuf, 1, dec->m_ptrWorkBuf, dec->m_nSubbandDegree); + + EMT_eriRoundR32ToWordArray(ptrDst + ch, output_channels, dec->m_ptrInternalBuf, nSamples); + + ptrLapBuf += dec->m_nDegreeNum; + ptrSrcBuf += dec->m_nDegreeNum; + } + + return eslErrSuccess; +} + +////////////////////////////////////////////////////////////////////////////// + +static ESLError MIODecoder_DecodeSoundDCT_Std(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) { + unsigned int i, j, k; + unsigned int nDegreeWidth = (1 << dec->m_mioih.dwSubbandDegree); + unsigned int nSampleCount = (datahdr->dwSampleCount + nDegreeWidth - 1) & ~(nDegreeWidth - 1); + unsigned int nSubbandCount = (nSampleCount >> dec->m_mioih.dwSubbandDegree); + unsigned int nChannelCount = dec->m_mioih.dwChannelCount; + unsigned int nAllSampleCount = nSampleCount * nChannelCount; + unsigned int nAllSubbandCount = nSubbandCount * nChannelCount; + + if (nSampleCount > dec->m_nBufLength) { + free(dec->m_ptrBuffer2); + free(dec->m_ptrBuffer3); + free(dec->m_ptrDivisionTable); + free(dec->m_ptrWeightCode); + free(dec->m_ptrCoefficient); + + dec->m_ptrBuffer2 = malloc(nAllSampleCount * sizeof(INT)); + dec->m_ptrBuffer3 = malloc(nAllSampleCount * sizeof(SWORD)); + dec->m_ptrDivisionTable = malloc(nAllSubbandCount * sizeof(BYTE)); + dec->m_ptrWeightCode = malloc(nAllSubbandCount * 5 * sizeof(SDWORD)); + dec->m_ptrCoefficient = malloc(nAllSubbandCount * 5 * sizeof(INT)); + if (!dec->m_ptrBuffer2 || !dec->m_ptrBuffer3 || !dec->m_ptrDivisionTable || !dec->m_ptrWeightCode || !dec->m_ptrCoefficient) + return eslErrGeneral; + + dec->m_nBufLength = nSampleCount; + } + + // decode quantization table + if (MIOContext_GetABit(context) != 0) { + return eslErrGeneral; + } + + unsigned int pLastDivision[MIO_MAX_CHANNELS]; + for (i = 0; i < nChannelCount; i++) { + pLastDivision[i] = -1; + } + + dec->m_ptrNextDivision = dec->m_ptrDivisionTable; + dec->m_ptrNextWeight = dec->m_ptrWeightCode; + dec->m_ptrNextCoefficient = dec->m_ptrCoefficient; + + for (i = 0; i < nSubbandCount; i++) { + for (j = 0; j < nChannelCount; j++) { + unsigned int nDivisionCode = MIOContext_GetNBits(context, 2); + *(dec->m_ptrNextDivision++) = (BYTE)nDivisionCode; + + if (nDivisionCode != pLastDivision[j]) { + if (i != 0) { + *(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32); + *(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16); + } + pLastDivision[j] = nDivisionCode; + } + + unsigned int nDivisionCount = (1 << nDivisionCode); + for (k = 0; k < nDivisionCount; k++) { + *(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32); + *(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16); + } + } + } + if (nSubbandCount > 0) { + for (i = 0; i < nChannelCount; i++) { + *(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32); + *(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16); + } + } + + /* sync? */ + if (MIOContext_GetABit(context) != 0) { + return eslErrGeneral; + } + + // init code model if needed + if (datahdr->bytFlags & MIO_LEAD_BLOCK) { + if (dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE) { + ESLError err = MIOContext_PrepareToDecodeERINACode(context, ERINAEncodingFlag_efERINAOrder1); + if (err != eslErrSuccess) return err; + } + else { + ESLError err = MIOContext_PrepareToDecodeERISACode(context); + if (err != eslErrSuccess) return err; + } + } + else if (dec->m_mioih.dwArchitecture == ERISA_NEMESIS_CODE) { + MIOContext_InitializeERISACode(context); + } + + // decode and deinterleave + if (dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE) { + if (MIOContext_DecodeSymbolBytes(context, dec->m_ptrBuffer3, nAllSampleCount * 2) < nAllSampleCount * 2) { + return eslErrGeneral; + } + + SBYTE* ptrHBuf = dec->m_ptrBuffer3; + SBYTE* ptrLBuf = ptrHBuf + nAllSampleCount; + + for (i = 0; i < nDegreeWidth; i++) { + INT* ptrQuantumized = ((INT*)dec->m_ptrBuffer2) + i; + + for (j = 0; j < nAllSubbandCount; j++) { + INT nLow = *(ptrLBuf++); + INT nHigh = *(ptrHBuf++) ^ (nLow >> 8); + *ptrQuantumized = (nLow & 0xFF) | (nHigh << 8); + ptrQuantumized += nDegreeWidth; + } + } + } + else { + if (MIOContext_DecodeERISACodeWords(context, (SWORD*)dec->m_ptrBuffer3, nAllSampleCount) < nAllSampleCount) { + return eslErrGeneral; + } + SWORD* ptrTmp = dec->m_ptrBuffer3; + for (i = 0; i < nAllSampleCount; i++) { + ((INT*)dec->m_ptrBuffer2)[i] = (ptrTmp)[i]; + } + } + + // apply iDCT to subband units + unsigned int nSamples; + unsigned int pRestSamples[MIO_MAX_CHANNELS]; + SWORD* ptrDstBuf[MIO_MAX_CHANNELS]; + + dec->m_ptrNextDivision = dec->m_ptrDivisionTable; + dec->m_ptrNextWeight = dec->m_ptrWeightCode; + dec->m_ptrNextCoefficient = dec->m_ptrCoefficient; + dec->m_ptrNextSource = dec->m_ptrBuffer2; + + for (i = 0; i < nChannelCount; i++) { + pLastDivision[i] = -1; + pRestSamples[i] = datahdr->dwSampleCount; + ptrDstBuf[i] = ((SWORD*)ptrWaveBuf) + i; + } + unsigned int nCurrentDivision = -1; + + for (i = 0; i < nSubbandCount; i++) { + for (j = 0; j < nChannelCount; j++) { + // get division/decomposition code + unsigned int nDivisionCode = *(dec->m_ptrNextDivision++); + unsigned int nDivisionCount = (1 << nDivisionCode); + + // get buffer for duplicate processing + int nChannelStep = nDegreeWidth * dec->m_mioih.dwLappedDegree * j; + dec->m_ptrLastDCTBuf = dec->m_ptrLastDCT + nChannelStep; + + // processing when matrix size changes + int bLeadBlock = 0; + + if (pLastDivision[j] != nDivisionCode) { + // complete until last moment + if (i != 0) { + if (nCurrentDivision != pLastDivision[j]) { + if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree - pLastDivision[j])) + return eslErrGeneral; + nCurrentDivision = pLastDivision[j]; + } + nSamples = pRestSamples[j]; + if (nSamples > dec->m_nDegreeNum) { + nSamples = dec->m_nDegreeNum; + } + if (MIODecoder_DecodePostBlock_All(dec, ptrDstBuf[j], nSamples, 0)) { + return eslErrGeneral; + } + pRestSamples[j] -= nSamples; + ptrDstBuf[j] += nSamples * nChannelCount; + } + + // set params to change matrix size + pLastDivision[j] = nDivisionCode; + bLeadBlock = 1; + } + if (nCurrentDivision != nDivisionCode) { + if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree - nDivisionCode)) + return eslErrGeneral; + nCurrentDivision = nDivisionCode; + } + + // perform sequential iLOT + for (k = 0; k < nDivisionCount; k++) { + if (bLeadBlock) { + // decode lead block + if (MIODecoder_DecodeLeadBlock_All(dec, 0)) { + return eslErrGeneral; + } + + bLeadBlock = 0; + } + else { + // decode regular block + nSamples = pRestSamples[j]; + if (nSamples > dec->m_nDegreeNum) { + nSamples = dec->m_nDegreeNum; + } + if (MIODecoder_DecodeInternalBlock_All(dec, ptrDstBuf[j], nSamples, 0)) { + return eslErrGeneral; + } + pRestSamples[j] -= nSamples; + ptrDstBuf[j] += nSamples * nChannelCount; + } + } + } + } + + // complete the matrix + if (nSubbandCount > 0) { + for (i = 0; i < nChannelCount; i++) { + int nChannelStep = nDegreeWidth * dec->m_mioih.dwLappedDegree * i; + dec->m_ptrLastDCTBuf = dec->m_ptrLastDCT + nChannelStep; + + if (nCurrentDivision != pLastDivision[i]) { + if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree - pLastDivision[i])) + return eslErrGeneral; + nCurrentDivision = pLastDivision[i]; + } + nSamples = pRestSamples[i]; + if (nSamples > dec->m_nDegreeNum) { + nSamples = dec->m_nDegreeNum; + } + if (MIODecoder_DecodePostBlock_All(dec, ptrDstBuf[i], nSamples, 0)) { + return eslErrGeneral; + } + pRestSamples[i] -= nSamples; + ptrDstBuf[i] += nSamples * nChannelCount; + } + } + + return eslErrSuccess; +} + +static ESLError MIODecoder_DecodeSoundDCT_MSS(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) { + unsigned int i, j, k; + unsigned int nDegreeWidth = (1 << dec->m_mioih.dwSubbandDegree); + unsigned int nSampleCount = (datahdr->dwSampleCount + nDegreeWidth - 1) & ~(nDegreeWidth - 1); + unsigned int nSubbandCount = (nSampleCount >> dec->m_mioih.dwSubbandDegree); + unsigned int nChannelCount = dec->m_mioih.dwChannelCount; // usually 2 + unsigned int nAllSampleCount = nSampleCount * nChannelCount; + unsigned int nAllSubbandCount = nSubbandCount; + + if (nSampleCount > dec->m_nBufLength) { + free(dec->m_ptrBuffer2); + free(dec->m_ptrBuffer3); + free(dec->m_ptrDivisionTable); + free(dec->m_ptrRevolveCode); + free(dec->m_ptrWeightCode); + free(dec->m_ptrCoefficient); + + dec->m_ptrBuffer2 = malloc(nAllSampleCount * sizeof(INT)); + dec->m_ptrBuffer3 = malloc(nAllSampleCount * sizeof(SWORD)); + dec->m_ptrDivisionTable = malloc(nAllSubbandCount * sizeof(BYTE)); + dec->m_ptrRevolveCode = malloc(nAllSubbandCount * 10 * sizeof(BYTE)); + dec->m_ptrWeightCode = malloc(nAllSubbandCount * 10 * sizeof(SDWORD)); + dec->m_ptrCoefficient = malloc(nAllSubbandCount * 10 * sizeof(INT)); + if (!dec->m_ptrBuffer2 || !dec->m_ptrBuffer3 || !dec->m_ptrDivisionTable || !dec->m_ptrRevolveCode || !dec->m_ptrWeightCode || !dec->m_ptrCoefficient) + return eslErrGeneral; + + dec->m_nBufLength = nSampleCount; + } + + // decode quantization table + if (MIOContext_GetABit(context) != 0) { + return eslErrGeneral; + } + + unsigned int nLastDivision = -1; + + dec->m_ptrNextDivision = dec->m_ptrDivisionTable; + dec->m_ptrNextRevCode = dec->m_ptrRevolveCode; + dec->m_ptrNextWeight = dec->m_ptrWeightCode; + dec->m_ptrNextCoefficient = dec->m_ptrCoefficient; + + for (i = 0; i < nSubbandCount; i++) { + unsigned int nDivisionCode = MIOContext_GetNBits(context, 2); + *(dec->m_ptrNextDivision++) = (BYTE)nDivisionCode; + + int bLeadBlock = 0; + if (nDivisionCode != nLastDivision) { + if (i != 0) { + *(dec->m_ptrNextRevCode++) = MIOContext_GetNBits(context, 2); + *(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32); + *(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16); + } + bLeadBlock = 1; + nLastDivision = nDivisionCode; + } + + unsigned int nDivisionCount = (1 << nDivisionCode); + for (k = 0; k < nDivisionCount; k++) { + if (bLeadBlock) { + *(dec->m_ptrNextRevCode++) = MIOContext_GetNBits(context, 2); + bLeadBlock = 0; + } + else { + *(dec->m_ptrNextRevCode++) = MIOContext_GetNBits(context, 4); + } + *(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32); + *(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16); + } + } + if (nSubbandCount > 0) { + *(dec->m_ptrNextRevCode++) = MIOContext_GetNBits(context, 2); + *(dec->m_ptrNextWeight++) = MIOContext_GetNBits(context, 32); + *(dec->m_ptrNextCoefficient++) = MIOContext_GetNBits(context, 16); + } + + if (MIOContext_GetABit(context) != 0) { + return eslErrGeneral; + } + + if (datahdr->bytFlags & MIO_LEAD_BLOCK) { + if (dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE) { + ESLError err = MIOContext_PrepareToDecodeERINACode(context, ERINAEncodingFlag_efERINAOrder1); + if (err != eslErrSuccess) return err; + } + else { + ESLError err = MIOContext_PrepareToDecodeERISACode(context); + if (err != eslErrSuccess) return err; + } + } + else if (dec->m_mioih.dwArchitecture == ERISA_NEMESIS_CODE) { + MIOContext_InitializeERISACode(context); + } + + // decode and deinterleave + if (dec->m_mioih.dwArchitecture != ERISA_NEMESIS_CODE) { + if (MIOContext_DecodeSymbolBytes(context, dec->m_ptrBuffer3, nAllSampleCount * 2) < nAllSampleCount * 2) { + return eslErrGeneral; + } + + SBYTE* ptrHBuf = dec->m_ptrBuffer3; + SBYTE* ptrLBuf = ptrHBuf + nAllSampleCount; + + for (i = 0; i < nDegreeWidth * 2; i++) { + INT* ptrQuantumized = ((INT*)dec->m_ptrBuffer2) + i; + + for (j = 0; j < nAllSubbandCount; j++) { + INT nLow = *(ptrLBuf++); + INT nHigh = *(ptrHBuf++) ^ (nLow >> 8); + *ptrQuantumized = (nLow & 0xFF) | (nHigh << 8); + ptrQuantumized += nDegreeWidth * 2; + } + } + } + else { + if (MIOContext_DecodeERISACodeWords(context, (SWORD*)dec->m_ptrBuffer3, nAllSampleCount) < nAllSampleCount) { + return eslErrGeneral; + } + SWORD* ptrTmp = dec->m_ptrBuffer3; + for (i = 0; i < nAllSampleCount; i++) { + ((INT*)dec->m_ptrBuffer2)[i] = (ptrTmp)[i]; + } + } + + // apply iDCT to subband units + unsigned int nSamples; + unsigned int nRestSamples = datahdr->dwSampleCount; + SWORD* ptrDstBuf = ptrWaveBuf; + + nLastDivision = -1; + dec->m_ptrNextDivision = dec->m_ptrDivisionTable; + dec->m_ptrNextRevCode = dec->m_ptrRevolveCode; + dec->m_ptrNextWeight = dec->m_ptrWeightCode; + dec->m_ptrNextCoefficient = dec->m_ptrCoefficient; + dec->m_ptrNextSource = dec->m_ptrBuffer2; + + for (i = 0; i < nSubbandCount; i++) { + // get division/decomposition code + unsigned int nDivisionCode = *(dec->m_ptrNextDivision++); + unsigned int nDivisionCount = (1 << nDivisionCode); + + // processing when matrix size changes + int bLeadBlock = 0; + dec->m_ptrLastDCTBuf = dec->m_ptrLastDCT; + + if (nLastDivision != nDivisionCode) { + // complete until last moment + if (i != 0) { + nSamples = nRestSamples; + if (nSamples > dec->m_nDegreeNum) { + nSamples = dec->m_nDegreeNum; + } + if (MIODecoder_DecodePostBlock_All(dec, ptrDstBuf, nSamples, 1)) { + return eslErrGeneral; + } + nRestSamples -= nSamples; + ptrDstBuf += nSamples * nChannelCount; + } + + // set params to change matrix size + if (MIODecoder_InitializeWithDegree(dec, dec->m_mioih.dwSubbandDegree - nDivisionCode)) + return eslErrGeneral; + nLastDivision = nDivisionCode; + bLeadBlock = 1; + } + + // perform sequential iLOT + for (k = 0; k < nDivisionCount; k++) { + if (bLeadBlock) { + // decode lead block + if (MIODecoder_DecodeLeadBlock_All(dec, 1)) { + return eslErrGeneral; + } + + bLeadBlock = 0; + } + else { + // decode regular block + nSamples = nRestSamples; + if (nSamples > dec->m_nDegreeNum) { + nSamples = dec->m_nDegreeNum; + } + if (MIODecoder_DecodeInternalBlock_All(dec, ptrDstBuf, nSamples, 1)) { + return eslErrGeneral; + } + nRestSamples -= nSamples; + ptrDstBuf += nSamples * nChannelCount; + } + } + } + + // complete the matrix + if (nSubbandCount > 0) { + dec->m_ptrLastDCTBuf = dec->m_ptrLastDCT; + + nSamples = nRestSamples; + if (nSamples > dec->m_nDegreeNum) + nSamples = dec->m_nDegreeNum; + + if (MIODecoder_DecodePostBlock_All(dec, ptrDstBuf, nSamples, 1)) { + return eslErrGeneral; + } + nRestSamples -= nSamples; + ptrDstBuf += nSamples * nChannelCount; + } + + return eslErrSuccess; +} + +ESLError MIODecoder_DecodeSound(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf) { + MIOContext_FlushBuffer(context); + + if (dec->m_mioih.fdwTransformation == CVTYPE_LOSSLESS_ERI) { + if (dec->m_mioih.dwBitsPerSample == 8) { + return MIODecoder_DecodeSoundPCM8(dec, context, datahdr, ptrWaveBuf); + } + else if (dec->m_mioih.dwBitsPerSample == 16) { + return MIODecoder_DecodeSoundPCM16(dec, context, datahdr, ptrWaveBuf); + } + } + else if ((dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI) || (dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI_MSS)) { + if ((dec->m_mioih.dwChannelCount != 2) || (dec->m_mioih.fdwTransformation == CVTYPE_LOT_ERI)) { + return MIODecoder_DecodeSoundDCT_Std(dec, context, datahdr, ptrWaveBuf); + } + else { + return MIODecoder_DecodeSoundDCT_MSS(dec, context, datahdr, ptrWaveBuf); + } + } + + return eslErrGeneral; +} diff --git a/Frameworks/vgmstream/vgmstream/src/coding/mio_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/mio_decoder.c index 6c62f9547..540d81c97 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/mio_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/mio_decoder.c @@ -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 { diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c index d1fecec61..60d257686 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c @@ -1,37 +1,53 @@ #include #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 +#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 diff --git a/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c index 9b7dcccba..9dc7b1c37 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/pcm_decoder.c @@ -1,6 +1,9 @@ #include "coding.h" #include "../util.h" #include +#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; ioffset+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; ioffset+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; ioffset+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; ioffset+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; ioffset + 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; ioffset + 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; ioffset + 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, +}; diff --git a/Frameworks/vgmstream/vgmstream/src/coding/tac_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/tac_decoder.c index 63cdee892..026bbb1b2 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/tac_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/tac_decoder.c @@ -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, diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ualaw_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ualaw_decoder.c new file mode 100644 index 000000000..5419eb943 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/coding/ualaw_decoder.c @@ -0,0 +1,84 @@ +#include "coding.h" +#include "../util.h" +#include + + +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; ioffset+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; ioffset+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; ioffset+i,stream->streamfile); + outbuf[sample_count] = expand_alaw(alawbyte);; + } +} diff --git a/Frameworks/vgmstream/vgmstream/src/formats.c b/Frameworks/vgmstream/vgmstream/src/formats.c index 2a273d0b7..383bdaac4 100644 --- a/Frameworks/vgmstream/vgmstream/src/formats.c +++ b/Frameworks/vgmstream/vgmstream/src/formats.c @@ -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"}, diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked.c index acea36ae7..fed162ea9 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked.c @@ -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); diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_filp.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_filp.c index 6baea3627..b2d4c10a3 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_filp.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_filp.c @@ -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;ichannels;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); } } diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_gsb.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_gsb.c deleted file mode 100644 index 29a417711..000000000 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_gsb.c +++ /dev/null @@ -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;ichannels;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); - } -} diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_gsnd.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_gsnd.c new file mode 100644 index 000000000..db251778a --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_gsnd.c @@ -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); + } +} diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_vas_kceo.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_vas_kceo.c new file mode 100644 index 000000000..a8e1ad0ff --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_vas_kceo.c @@ -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 + } +} diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_xvas.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_xvas.c deleted file mode 100644 index a26ed0da3..000000000 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_xvas.c +++ /dev/null @@ -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;ichannels;i++) { - vgmstream->ch[i].offset = vgmstream->current_block_offset; - } - vgmstream->current_block_size /=2; - -} diff --git a/Frameworks/vgmstream/vgmstream/src/layout/layout.h b/Frameworks/vgmstream/vgmstream/src/layout/layout.h index 3c35ec6db..aae900f64 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/layout.h +++ b/Frameworks/vgmstream/vgmstream/src/layout/layout.h @@ -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); diff --git a/Frameworks/vgmstream/vgmstream/src/libvgmstream.h b/Frameworks/vgmstream/vgmstream/src/libvgmstream.h index 89dc3c850..f29a46075 100644 --- a/Frameworks/vgmstream/vgmstream/src/libvgmstream.h +++ b/Frameworks/vgmstream/vgmstream/src/libvgmstream.h @@ -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; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/2dx.c b/Frameworks/vgmstream/vgmstream/src/meta/2dx.c index 26e15a490..643ab7f8d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/2dx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/2dx.c @@ -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); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/astb.c b/Frameworks/vgmstream/vgmstream/src/meta/astb.c index e987e1c47..7af57ad3e 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/astb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/astb.c @@ -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) */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/astl.c b/Frameworks/vgmstream/vgmstream/src/meta/astl.c new file mode 100644 index 000000000..6f8098200 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/astl.c @@ -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; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/axhd.c b/Frameworks/vgmstream/vgmstream/src/meta/axhd.c index 1f15868f6..469cb0280 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/axhd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/axhd.c @@ -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); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/cbx.c b/Frameworks/vgmstream/vgmstream/src/meta/chatterbox.c similarity index 74% rename from Frameworks/vgmstream/vgmstream/src/meta/cbx.c rename to Frameworks/vgmstream/vgmstream/src/meta/chatterbox.c index 09a919ceb..ee8f35e31 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/cbx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/chatterbox.c @@ -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" diff --git a/Frameworks/vgmstream/vgmstream/src/meta/excitebots.c b/Frameworks/vgmstream/vgmstream/src/meta/excitebots.c deleted file mode 100644 index 2f5de05bb..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/excitebots.c +++ /dev/null @@ -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;ich[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - - if (!vgmstream->ch[i].streamfile) goto fail; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset = 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 */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ezw.c b/Frameworks/vgmstream/vgmstream/src/meta/ezw.c index cd7d7924c..1f3aadab1 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ezw.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ezw.c @@ -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); } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb.c index 8239aa8eb..29c813f2b 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb.c @@ -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: diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ghs.c b/Frameworks/vgmstream/vgmstream/src/meta/ghs.c index 24e13b688..baf2873a8 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ghs.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ghs.c @@ -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); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/gsnd.c b/Frameworks/vgmstream/vgmstream/src/meta/gsnd.c index 9ea897f3f..83ee1f9cf 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/gsnd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/gsnd.c @@ -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; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca_bf.h b/Frameworks/vgmstream/vgmstream/src/meta/hca_bf.h index f12e267da..00717031f 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca_bf.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca_bf.h @@ -1,6 +1,7 @@ #ifndef _HCA_BF_ #define _HCA_BF_ +#include #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 -//#include - /* 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 diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h index 491883a2f..4485fdd23 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h @@ -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 diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_iab.c b/Frameworks/vgmstream/vgmstream/src/meta/iab.c similarity index 51% rename from Frameworks/vgmstream/vgmstream/src/meta/ps2_iab.c rename to Frameworks/vgmstream/vgmstream/src/meta/iab.c index edae3d814..1a46c1382 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_iab.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/iab.c @@ -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; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ktac.c b/Frameworks/vgmstream/vgmstream/src/meta/ktac.c index c075dd90a..fe691152c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ktac.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ktac.c @@ -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; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/lps.c b/Frameworks/vgmstream/vgmstream/src/meta/lps.c new file mode 100644 index 000000000..bc3dc6bb2 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/lps.c @@ -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); +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/madp.c b/Frameworks/vgmstream/vgmstream/src/meta/madp.c new file mode 100644 index 000000000..62b8d600f --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/madp.c @@ -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); +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mca.c b/Frameworks/vgmstream/vgmstream/src/meta/mca.c deleted file mode 100644 index bdb6ddc23..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/mca.c +++ /dev/null @@ -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; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mcss.c b/Frameworks/vgmstream/vgmstream/src/meta/mcss.c new file mode 100644 index 000000000..1ff10de8e --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/mcss.c @@ -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; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h index 1c916e7b7..909ea17b7 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -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 diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mss.c b/Frameworks/vgmstream/vgmstream/src/meta/mss.c deleted file mode 100644 index d04a30d2f..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/mss.c +++ /dev/null @@ -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; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ngc_ffcc_str.c b/Frameworks/vgmstream/vgmstream/src/meta/ngc_ffcc_str.c deleted file mode 100644 index ac875b1e1..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/ngc_ffcc_str.c +++ /dev/null @@ -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;cch[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;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ngc_lps.c b/Frameworks/vgmstream/vgmstream/src/meta/ngc_lps.c deleted file mode 100644 index bafa5f904..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/ngc_lps.c +++ /dev/null @@ -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;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ngc_nst_dsp.c b/Frameworks/vgmstream/vgmstream/src/meta/ngc_nst_dsp.c deleted file mode 100644 index 98f8deb45..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/ngc_nst_dsp.c +++ /dev/null @@ -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;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/nst_monster.c b/Frameworks/vgmstream/vgmstream/src/meta/nst_monster.c new file mode 100644 index 000000000..88a5c6b9f --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/nst_monster.c @@ -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); +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/oor.c b/Frameworks/vgmstream/vgmstream/src/meta/oor.c index 483075422..2d3eee28c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/oor.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/oor.c @@ -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). diff --git a/Frameworks/vgmstream/vgmstream/src/meta/opus.c b/Frameworks/vgmstream/vgmstream/src/meta/opus.c index 174389774..a6877e701 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/opus.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/opus.c @@ -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; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/pc_ast.c b/Frameworks/vgmstream/vgmstream/src/meta/pc_ast.c deleted file mode 100644 index e678f2632..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/pc_ast.c +++ /dev/null @@ -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; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_rnd.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_rnd.c deleted file mode 100644 index 0042359a8..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_rnd.c +++ /dev/null @@ -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;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_vgv.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_vgv.c deleted file mode 100644 index 7ffb45069..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_vgv.c +++ /dev/null @@ -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;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset; //+vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/riff.c b/Frameworks/vgmstream/vgmstream/src/meta/riff.c index 4191dc984..0ddabbd6f 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/riff.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/riff.c @@ -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; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sd9.c b/Frameworks/vgmstream/vgmstream/src/meta/sd9.c index 8fa47d35f..9baede45f 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sd9.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sd9.c @@ -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; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sfx0_monster.c b/Frameworks/vgmstream/vgmstream/src/meta/sfx0_monster.c new file mode 100644 index 000000000..d8371cb18 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/sfx0_monster.c @@ -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); +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sfxb.c b/Frameworks/vgmstream/vgmstream/src/meta/sfxb.c new file mode 100644 index 000000000..b8dbce4b0 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/sfxb.c @@ -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; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/song_monster.c b/Frameworks/vgmstream/vgmstream/src/meta/song_monster.c new file mode 100644 index 000000000..e687b5cdd --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/song_monster.c @@ -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; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/spsd.c b/Frameworks/vgmstream/vgmstream/src/meta/spsd.c index 14d78c079..d9fb5ee2d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/spsd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/spsd.c @@ -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; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ssp.c b/Frameworks/vgmstream/vgmstream/src/meta/ssp.c new file mode 100644 index 000000000..43069af73 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/ssp.c @@ -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; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/str_sqex.c b/Frameworks/vgmstream/vgmstream/src/meta/str_sqex.c new file mode 100644 index 000000000..c87b66f3e --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/str_sqex.c @@ -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); +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/txth.c b/Frameworks/vgmstream/vgmstream/src/meta/txth.c index 9c07d2696..6ff2818fd 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/txth.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/txth.c @@ -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; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/txtp_process.c b/Frameworks/vgmstream/vgmstream/src/meta/txtp_process.c index a46fd491a..efbb43002 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/txtp_process.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/txtp_process.c @@ -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; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/vai.c b/Frameworks/vgmstream/vgmstream/src/meta/vai.c index 7539d7f3a..3644b3d89 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/vai.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/vai.c @@ -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; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/vas_kceo.c b/Frameworks/vgmstream/vgmstream/src/meta/vas_kceo.c index 79a64e68e..8cd07144a 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/vas_kceo.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/vas_kceo.c @@ -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; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/vgs.c b/Frameworks/vgmstream/vgmstream/src/meta/vgs.c index c4f9940a5..0aedb3bda 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/vgs.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/vgs.c @@ -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); } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/vgv.c b/Frameworks/vgmstream/vgmstream/src/meta/vgv.c new file mode 100644 index 000000000..04686f104 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/vgv.c @@ -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); +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wii_sng.c b/Frameworks/vgmstream/vgmstream/src/meta/wii_sng.c deleted file mode 100644 index 6eb14267b..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/wii_sng.c +++ /dev/null @@ -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;ich[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; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xau_konami.c b/Frameworks/vgmstream/vgmstream/src/meta/xau_konami.c deleted file mode 100644 index b8c6eb67d..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/xau_konami.c +++ /dev/null @@ -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; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xmd.c b/Frameworks/vgmstream/vgmstream/src/meta/xmd.c index 88012a4f3..aab5765f3 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xmd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xmd.c @@ -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; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xps.c b/Frameworks/vgmstream/vgmstream/src/meta/xps.c index da84fbb55..bbf7bb0da 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xps.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xps.c @@ -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; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xwav.c b/Frameworks/vgmstream/vgmstream/src/meta/xwav.c index 2af1fea75..e7342930d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xwav.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xwav.c @@ -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 diff --git a/Frameworks/vgmstream/vgmstream/src/util/miniz.c b/Frameworks/vgmstream/vgmstream/src/util/miniz.c index 8d0032f9e..bf350e69b 100644 --- a/Frameworks/vgmstream/vgmstream/src/util/miniz.c +++ b/Frameworks/vgmstream/vgmstream/src/util/miniz.c @@ -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; diff --git a/Frameworks/vgmstream/vgmstream/src/util/miniz.h b/Frameworks/vgmstream/vgmstream/src/util/miniz.h index 9fcfffcc8..77fe6593f 100644 --- a/Frameworks/vgmstream/vgmstream/src/util/miniz.h +++ b/Frameworks/vgmstream/vgmstream/src/util/miniz.h @@ -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 diff --git a/Frameworks/vgmstream/vgmstream/src/util/vorbis_codebooks.c b/Frameworks/vgmstream/vgmstream/src/util/vorbis_codebooks.c index 1d648f481..b2e6c02f9 100644 --- a/Frameworks/vgmstream/vgmstream/src/util/vorbis_codebooks.c +++ b/Frameworks/vgmstream/vgmstream/src/util/vorbis_codebooks.c @@ -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; +} diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream_init.c b/Frameworks/vgmstream/vgmstream/src/vgmstream_init.c index ce9c48de1..f19b1427b 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream_init.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream_init.c @@ -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, diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream_types.h b/Frameworks/vgmstream/vgmstream/src/vgmstream_types.h index f7c3876f4..9a983e10a 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream_types.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream_types.h @@ -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,