VGMStream: Updated libvgmstream code base

Updated VGMStream to r1980-181-g10093db5

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2025-03-23 15:45:54 -07:00
parent 9b683a9c56
commit cbaacd35b1
102 changed files with 11949 additions and 4489 deletions

View file

@ -139,7 +139,7 @@
832BF81C21E0514B006F50F1 /* xpcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80A21E05148006F50F1 /* xpcm.c */; }; 832BF81C21E0514B006F50F1 /* xpcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80A21E05148006F50F1 /* xpcm.c */; };
832BF81D21E0514B006F50F1 /* msf_tamasoft.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80B21E05148006F50F1 /* msf_tamasoft.c */; }; 832BF81D21E0514B006F50F1 /* msf_tamasoft.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80B21E05148006F50F1 /* msf_tamasoft.c */; };
832BF81E21E0514B006F50F1 /* xps.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80C21E05148006F50F1 /* xps.c */; }; 832BF81E21E0514B006F50F1 /* xps.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80C21E05148006F50F1 /* xps.c */; };
832BF81F21E0514B006F50F1 /* ps2_va3.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80D21E05148006F50F1 /* ps2_va3.c */; }; 832BF81F21E0514B006F50F1 /* va3.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80D21E05148006F50F1 /* va3.c */; };
832BF82021E0514B006F50F1 /* zsnd_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BF80E21E05149006F50F1 /* zsnd_streamfile.h */; }; 832BF82021E0514B006F50F1 /* zsnd_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BF80E21E05149006F50F1 /* zsnd_streamfile.h */; };
832BF82121E0514B006F50F1 /* zsnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80F21E05149006F50F1 /* zsnd.c */; }; 832BF82121E0514B006F50F1 /* zsnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80F21E05149006F50F1 /* zsnd.c */; };
832BF82221E0514B006F50F1 /* vs_str.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF81021E05149006F50F1 /* vs_str.c */; }; 832BF82221E0514B006F50F1 /* vs_str.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF81021E05149006F50F1 /* vs_str.c */; };
@ -251,7 +251,6 @@
834F7DB02C7093EA003AC386 /* circus_vq_lib.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D422C7093EA003AC386 /* circus_vq_lib.h */; }; 834F7DB02C7093EA003AC386 /* circus_vq_lib.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D422C7093EA003AC386 /* circus_vq_lib.h */; };
834F7DB12C7093EA003AC386 /* circus_vq_lzxpcm.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D432C7093EA003AC386 /* circus_vq_lzxpcm.h */; }; 834F7DB12C7093EA003AC386 /* circus_vq_lzxpcm.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D432C7093EA003AC386 /* circus_vq_lzxpcm.h */; };
834F7DB22C7093EA003AC386 /* circus_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D442C7093EA003AC386 /* circus_decoder.c */; }; 834F7DB22C7093EA003AC386 /* circus_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D442C7093EA003AC386 /* circus_decoder.c */; };
834F7DB32C7093EA003AC386 /* coding_utils_samples.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D452C7093EA003AC386 /* coding_utils_samples.h */; };
834F7DB42C7093EA003AC386 /* coding_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D462C7093EA003AC386 /* coding_utils.c */; }; 834F7DB42C7093EA003AC386 /* coding_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D462C7093EA003AC386 /* coding_utils.c */; };
834F7DB52C7093EA003AC386 /* coding.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D472C7093EA003AC386 /* coding.h */; }; 834F7DB52C7093EA003AC386 /* coding.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D472C7093EA003AC386 /* coding.h */; };
834F7DB62C7093EA003AC386 /* compresswave_lib.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D482C7093EA003AC386 /* compresswave_lib.c */; }; 834F7DB62C7093EA003AC386 /* compresswave_lib.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D482C7093EA003AC386 /* compresswave_lib.c */; };
@ -326,8 +325,6 @@
834F7DFD2C7093EA003AC386 /* tgcadpcm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D8F2C7093EA003AC386 /* tgcadpcm_decoder.c */; }; 834F7DFD2C7093EA003AC386 /* tgcadpcm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D8F2C7093EA003AC386 /* tgcadpcm_decoder.c */; };
834F7DFE2C7093EA003AC386 /* ubi_adpcm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D902C7093EA003AC386 /* ubi_adpcm_decoder.c */; }; 834F7DFE2C7093EA003AC386 /* ubi_adpcm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D902C7093EA003AC386 /* ubi_adpcm_decoder.c */; };
834F7DFF2C7093EA003AC386 /* vadpcm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D912C7093EA003AC386 /* vadpcm_decoder.c */; }; 834F7DFF2C7093EA003AC386 /* vadpcm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D912C7093EA003AC386 /* vadpcm_decoder.c */; };
834F7E002C7093EA003AC386 /* vorbis_custom_data_fsb.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D922C7093EA003AC386 /* vorbis_custom_data_fsb.h */; };
834F7E012C7093EA003AC386 /* vorbis_custom_data_wwise.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D932C7093EA003AC386 /* vorbis_custom_data_wwise.h */; };
834F7E022C7093EA003AC386 /* vorbis_custom_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D942C7093EA003AC386 /* vorbis_custom_decoder.c */; }; 834F7E022C7093EA003AC386 /* vorbis_custom_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D942C7093EA003AC386 /* vorbis_custom_decoder.c */; };
834F7E032C7093EA003AC386 /* vorbis_custom_decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D952C7093EA003AC386 /* vorbis_custom_decoder.h */; }; 834F7E032C7093EA003AC386 /* vorbis_custom_decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 834F7D952C7093EA003AC386 /* vorbis_custom_decoder.h */; };
834F7E042C7093EA003AC386 /* vorbis_custom_utils_awc.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D962C7093EA003AC386 /* vorbis_custom_utils_awc.c */; }; 834F7E042C7093EA003AC386 /* vorbis_custom_utils_awc.c in Sources */ = {isa = PBXBuildFile; fileRef = 834F7D962C7093EA003AC386 /* vorbis_custom_utils_awc.c */; };
@ -443,8 +440,8 @@
834FE10F215C79ED000A5D3D /* sdf.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0E6215C79EC000A5D3D /* sdf.c */; }; 834FE10F215C79ED000A5D3D /* sdf.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0E6215C79EC000A5D3D /* sdf.c */; };
834FE110215C79ED000A5D3D /* msv.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0E7215C79EC000A5D3D /* msv.c */; }; 834FE110215C79ED000A5D3D /* msv.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0E7215C79EC000A5D3D /* msv.c */; };
834FE111215C79ED000A5D3D /* ck.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0E8215C79EC000A5D3D /* ck.c */; }; 834FE111215C79ED000A5D3D /* ck.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0E8215C79EC000A5D3D /* ck.c */; };
835096F22C9979DD00163D93 /* libvgmstream.h in Headers */ = {isa = PBXBuildFile; fileRef = 835096F02C9979DD00163D93 /* libvgmstream.h */; }; 835096F22C9979DD00163D93 /* libvgmstream.h in Headers */ = {isa = PBXBuildFile; fileRef = 835096F02C9979DD00163D93 /* libvgmstream.h */; settings = {ATTRIBUTES = (Public, ); }; };
835096F32C9979DD00163D93 /* libvgmstream_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 835096F12C9979DD00163D93 /* libvgmstream_streamfile.h */; }; 835096F32C9979DD00163D93 /* libvgmstream_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 835096F12C9979DD00163D93 /* libvgmstream_streamfile.h */; settings = {ATTRIBUTES = (Public, ); }; };
8350C0551E071881009E0A93 /* xma.c in Sources */ = {isa = PBXBuildFile; fileRef = 8350C0541E071881009E0A93 /* xma.c */; }; 8350C0551E071881009E0A93 /* xma.c in Sources */ = {isa = PBXBuildFile; fileRef = 8350C0541E071881009E0A93 /* xma.c */; };
8351F32D2212B57000A606E4 /* 208.c in Sources */ = {isa = PBXBuildFile; fileRef = 8351F32A2212B57000A606E4 /* 208.c */; }; 8351F32D2212B57000A606E4 /* 208.c in Sources */ = {isa = PBXBuildFile; fileRef = 8351F32A2212B57000A606E4 /* 208.c */; };
8351F32E2212B57000A606E4 /* ubi_bao_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8351F32B2212B57000A606E4 /* ubi_bao_streamfile.h */; }; 8351F32E2212B57000A606E4 /* ubi_bao_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8351F32B2212B57000A606E4 /* ubi_bao_streamfile.h */; };
@ -557,14 +554,13 @@
836F6FD518BDC2190095E648 /* lp_ap_lep.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9918BDC2180095E648 /* lp_ap_lep.c */; }; 836F6FD518BDC2190095E648 /* lp_ap_lep.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9918BDC2180095E648 /* lp_ap_lep.c */; };
836F6FD718BDC2190095E648 /* filp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9B18BDC2180095E648 /* filp.c */; }; 836F6FD718BDC2190095E648 /* filp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9B18BDC2180095E648 /* filp.c */; };
836F6FD818BDC2190095E648 /* gbts.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9C18BDC2180095E648 /* gbts.c */; }; 836F6FD818BDC2190095E648 /* gbts.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9C18BDC2180095E648 /* gbts.c */; };
836F6FD918BDC2190095E648 /* ps2_gcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9D18BDC2180095E648 /* ps2_gcm.c */; }; 836F6FD918BDC2190095E648 /* mcg.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9D18BDC2180095E648 /* mcg.c */; };
836F6FDA18BDC2190095E648 /* hgc1.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9E18BDC2180095E648 /* hgc1.c */; }; 836F6FDA18BDC2190095E648 /* hgc1.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9E18BDC2180095E648 /* hgc1.c */; };
836F6FDB18BDC2190095E648 /* ps2_hsf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9F18BDC2180095E648 /* ps2_hsf.c */; }; 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 /* ps2_iab.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA018BDC2180095E648 /* ps2_iab.c */; };
836F6FDE18BDC2190095E648 /* ild.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA218BDC2180095E648 /* ild.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 */; }; 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 */; }; 836F6FE218BDC2190095E648 /* vig_kces.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA618BDC2180095E648 /* vig_kces.c */; };
836F6FE618BDC2190095E648 /* ps2_mcg.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EAA18BDC2180095E648 /* ps2_mcg.c */; };
836F6FE818BDC2190095E648 /* mic_koei.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EAC18BDC2180095E648 /* mic_koei.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 */; }; 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 */; }; 836F6FF218BDC2190095E648 /* ps2_rnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB618BDC2180095E648 /* ps2_rnd.c */; };
@ -584,7 +580,6 @@
836F700918BDC2190095E648 /* voi.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ECD18BDC2190095E648 /* voi.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 */; }; 836F700B18BDC2190095E648 /* ps2_wad.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ECF18BDC2190095E648 /* ps2_wad.c */; };
836F700C18BDC2190095E648 /* wb.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED018BDC2190095E648 /* wb.c */; }; 836F700C18BDC2190095E648 /* wb.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED018BDC2190095E648 /* wb.c */; };
836F700D18BDC2190095E648 /* ps2_wmus.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED118BDC2190095E648 /* ps2_wmus.c */; };
836F701518BDC2190095E648 /* sndp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED918BDC2190095E648 /* sndp.c */; }; 836F701518BDC2190095E648 /* sndp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED918BDC2190095E648 /* sndp.c */; };
836F701E18BDC2190095E648 /* redspark.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EE218BDC2190095E648 /* redspark.c */; }; 836F701E18BDC2190095E648 /* redspark.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EE218BDC2190095E648 /* redspark.c */; };
836F701F18BDC2190095E648 /* riff.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EE318BDC2190095E648 /* riff.c */; }; 836F701F18BDC2190095E648 /* riff.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EE318BDC2190095E648 /* riff.c */; };
@ -744,6 +739,37 @@
83B46FD52707FB9A00847FC9 /* endianness.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B46FD42707FB9A00847FC9 /* endianness.h */; }; 83B46FD52707FB9A00847FC9 /* endianness.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B46FD42707FB9A00847FC9 /* endianness.h */; };
83B69B222845A26600D2435A /* bw_mp3_riff.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B69B212845A26600D2435A /* bw_mp3_riff.c */; }; 83B69B222845A26600D2435A /* bw_mp3_riff.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B69B212845A26600D2435A /* bw_mp3_riff.c */; };
83B72E3A27904589006007A3 /* libfdk-aac.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 83B72E342790452C006007A3 /* libfdk-aac.2.dylib */; }; 83B72E3A27904589006007A3 /* libfdk-aac.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 83B72E342790452C006007A3 /* libfdk-aac.2.dylib */; };
83B73C232D8FEC3A00A57F08 /* vorbis_codebooks_oor.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C222D8FEC3A00A57F08 /* vorbis_codebooks_oor.h */; };
83B73C242D8FEC3A00A57F08 /* oor_helpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C202D8FEC3A00A57F08 /* oor_helpers.h */; };
83B73C252D8FEC3A00A57F08 /* oor_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C212D8FEC3A00A57F08 /* oor_helpers.c */; };
83B73C272D8FEC5500A57F08 /* vorbis_custom_utils_oor.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C262D8FEC5500A57F08 /* vorbis_custom_utils_oor.c */; };
83B73C292D8FEC7B00A57F08 /* oor.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C282D8FEC7B00A57F08 /* oor.c */; };
83B73C2C2D8FED0500A57F08 /* vorbis_codebooks_wwise.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C2B2D8FED0500A57F08 /* vorbis_codebooks_wwise.h */; };
83B73C2D2D8FED0500A57F08 /* vorbis_codebooks_fsb.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C2A2D8FED0500A57F08 /* vorbis_codebooks_fsb.h */; };
83B73C312D8FEF7A00A57F08 /* ubi_mpeg_helpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C2F2D8FEF7A00A57F08 /* ubi_mpeg_helpers.h */; };
83B73C322D8FEF7A00A57F08 /* minimp3.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C2E2D8FEF7A00A57F08 /* minimp3.h */; };
83B73C332D8FEF7A00A57F08 /* ubi_mpeg_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C302D8FEF7A00A57F08 /* ubi_mpeg_helpers.c */; };
83B73C352D8FEFFD00A57F08 /* ubi_mpeg_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C342D8FEFFD00A57F08 /* ubi_mpeg_decoder.c */; };
83B73C3F2D8FF15700A57F08 /* mio_xerisa.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C3E2D8FF15700A57F08 /* mio_xerisa.h */; };
83B73C402D8FF15700A57F08 /* mio_erisasound.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C3C2D8FF15700A57F08 /* mio_erisasound.h */; };
83B73C412D8FF15700A57F08 /* mio_erisacontext.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C362D8FF15700A57F08 /* mio_erisacontext.h */; };
83B73C422D8FF15700A57F08 /* mio_erisafile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C382D8FF15700A57F08 /* mio_erisafile.h */; };
83B73C432D8FF15700A57F08 /* mio_erisamatrix.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C3A2D8FF15700A57F08 /* mio_erisamatrix.h */; };
83B73C442D8FF15700A57F08 /* mio_erisacontext.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C372D8FF15700A57F08 /* mio_erisacontext.c */; };
83B73C452D8FF15700A57F08 /* mio_erisafile.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C392D8FF15700A57F08 /* mio_erisafile.c */; };
83B73C462D8FF15700A57F08 /* mio_erisamatrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C3B2D8FF15700A57F08 /* mio_erisamatrix.c */; };
83B73C472D8FF15700A57F08 /* mio_erisasound.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C3D2D8FF15700A57F08 /* mio_erisasound.c */; };
83B73C492D8FF17900A57F08 /* mio_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C482D8FF17900A57F08 /* mio_decoder.c */; };
83B73C4B2D8FF19800A57F08 /* mio.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C4A2D8FF19800A57F08 /* mio.c */; };
83B73C4F2D8FF1CB00A57F08 /* io_callback_sf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C4D2D8FF1CB00A57F08 /* io_callback_sf.h */; };
83B73C502D8FF1CB00A57F08 /* io_callback.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C4C2D8FF1CB00A57F08 /* io_callback.h */; };
83B73C512D8FF1CB00A57F08 /* io_callback_sf.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C4E2D8FF1CB00A57F08 /* io_callback_sf.c */; };
83B73C542D8FF1E300A57F08 /* vorbis_codebooks.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C522D8FF1E300A57F08 /* vorbis_codebooks.h */; };
83B73C552D8FF1E300A57F08 /* vorbis_codebooks.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C532D8FF1E300A57F08 /* vorbis_codebooks.c */; };
83B73C572D8FF27000A57F08 /* 2dx.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C562D8FF27000A57F08 /* 2dx.c */; };
83B73C5B2D8FF37700A57F08 /* codec_info.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B73C592D8FF37700A57F08 /* codec_info.h */; };
83B73C5C2D8FF37700A57F08 /* codec_info.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C5A2D8FF37700A57F08 /* codec_info.c */; };
83B73C5D2D8FF37700A57F08 /* api_libsf_cache.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B73C582D8FF37700A57F08 /* api_libsf_cache.c */; };
83B8FE2B2D5AB1F5005854C1 /* axhd.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B8FE2A2D5AB1F5005854C1 /* axhd.c */; }; 83B8FE2B2D5AB1F5005854C1 /* axhd.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B8FE2A2D5AB1F5005854C1 /* axhd.c */; };
83B8FE2D2D5AB2A5005854C1 /* shaa.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B8FE2C2D5AB2A5005854C1 /* shaa.c */; }; 83B8FE2D2D5AB2A5005854C1 /* shaa.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B8FE2C2D5AB2A5005854C1 /* shaa.c */; };
83B8FE2F2D5AB2F4005854C1 /* xwb_konami.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B8FE2E2D5AB2F4005854C1 /* xwb_konami.c */; }; 83B8FE2F2D5AB2F4005854C1 /* xwb_konami.c in Sources */ = {isa = PBXBuildFile; fileRef = 83B8FE2E2D5AB2F4005854C1 /* xwb_konami.c */; };
@ -1066,7 +1092,7 @@
832BF80A21E05148006F50F1 /* xpcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpcm.c; sourceTree = "<group>"; }; 832BF80A21E05148006F50F1 /* xpcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpcm.c; sourceTree = "<group>"; };
832BF80B21E05148006F50F1 /* msf_tamasoft.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = msf_tamasoft.c; sourceTree = "<group>"; }; 832BF80B21E05148006F50F1 /* msf_tamasoft.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = msf_tamasoft.c; sourceTree = "<group>"; };
832BF80C21E05148006F50F1 /* xps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xps.c; sourceTree = "<group>"; }; 832BF80C21E05148006F50F1 /* xps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xps.c; sourceTree = "<group>"; };
832BF80D21E05148006F50F1 /* ps2_va3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_va3.c; sourceTree = "<group>"; }; 832BF80D21E05148006F50F1 /* va3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = va3.c; sourceTree = "<group>"; };
832BF80E21E05149006F50F1 /* zsnd_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zsnd_streamfile.h; sourceTree = "<group>"; }; 832BF80E21E05149006F50F1 /* zsnd_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zsnd_streamfile.h; sourceTree = "<group>"; };
832BF80F21E05149006F50F1 /* zsnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zsnd.c; sourceTree = "<group>"; }; 832BF80F21E05149006F50F1 /* zsnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zsnd.c; sourceTree = "<group>"; };
832BF81021E05149006F50F1 /* vs_str.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vs_str.c; sourceTree = "<group>"; }; 832BF81021E05149006F50F1 /* vs_str.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vs_str.c; sourceTree = "<group>"; };
@ -1178,7 +1204,6 @@
834F7D422C7093EA003AC386 /* circus_vq_lib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = circus_vq_lib.h; sourceTree = "<group>"; }; 834F7D422C7093EA003AC386 /* circus_vq_lib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = circus_vq_lib.h; sourceTree = "<group>"; };
834F7D432C7093EA003AC386 /* circus_vq_lzxpcm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = circus_vq_lzxpcm.h; sourceTree = "<group>"; }; 834F7D432C7093EA003AC386 /* circus_vq_lzxpcm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = circus_vq_lzxpcm.h; sourceTree = "<group>"; };
834F7D442C7093EA003AC386 /* circus_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = circus_decoder.c; sourceTree = "<group>"; }; 834F7D442C7093EA003AC386 /* circus_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = circus_decoder.c; sourceTree = "<group>"; };
834F7D452C7093EA003AC386 /* coding_utils_samples.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coding_utils_samples.h; sourceTree = "<group>"; };
834F7D462C7093EA003AC386 /* coding_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = coding_utils.c; sourceTree = "<group>"; }; 834F7D462C7093EA003AC386 /* coding_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = coding_utils.c; sourceTree = "<group>"; };
834F7D472C7093EA003AC386 /* coding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coding.h; sourceTree = "<group>"; }; 834F7D472C7093EA003AC386 /* coding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coding.h; sourceTree = "<group>"; };
834F7D482C7093EA003AC386 /* compresswave_lib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compresswave_lib.c; sourceTree = "<group>"; }; 834F7D482C7093EA003AC386 /* compresswave_lib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compresswave_lib.c; sourceTree = "<group>"; };
@ -1253,8 +1278,6 @@
834F7D8F2C7093EA003AC386 /* tgcadpcm_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tgcadpcm_decoder.c; sourceTree = "<group>"; }; 834F7D8F2C7093EA003AC386 /* tgcadpcm_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tgcadpcm_decoder.c; sourceTree = "<group>"; };
834F7D902C7093EA003AC386 /* ubi_adpcm_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ubi_adpcm_decoder.c; sourceTree = "<group>"; }; 834F7D902C7093EA003AC386 /* ubi_adpcm_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ubi_adpcm_decoder.c; sourceTree = "<group>"; };
834F7D912C7093EA003AC386 /* vadpcm_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vadpcm_decoder.c; sourceTree = "<group>"; }; 834F7D912C7093EA003AC386 /* vadpcm_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vadpcm_decoder.c; sourceTree = "<group>"; };
834F7D922C7093EA003AC386 /* vorbis_custom_data_fsb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vorbis_custom_data_fsb.h; sourceTree = "<group>"; };
834F7D932C7093EA003AC386 /* vorbis_custom_data_wwise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vorbis_custom_data_wwise.h; sourceTree = "<group>"; };
834F7D942C7093EA003AC386 /* vorbis_custom_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_decoder.c; sourceTree = "<group>"; }; 834F7D942C7093EA003AC386 /* vorbis_custom_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_decoder.c; sourceTree = "<group>"; };
834F7D952C7093EA003AC386 /* vorbis_custom_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vorbis_custom_decoder.h; sourceTree = "<group>"; }; 834F7D952C7093EA003AC386 /* vorbis_custom_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vorbis_custom_decoder.h; sourceTree = "<group>"; };
834F7D962C7093EA003AC386 /* vorbis_custom_utils_awc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_utils_awc.c; sourceTree = "<group>"; }; 834F7D962C7093EA003AC386 /* vorbis_custom_utils_awc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_utils_awc.c; sourceTree = "<group>"; };
@ -1484,14 +1507,13 @@
836F6E9918BDC2180095E648 /* lp_ap_lep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lp_ap_lep.c; sourceTree = "<group>"; }; 836F6E9918BDC2180095E648 /* lp_ap_lep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lp_ap_lep.c; sourceTree = "<group>"; };
836F6E9B18BDC2180095E648 /* filp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filp.c; sourceTree = "<group>"; }; 836F6E9B18BDC2180095E648 /* filp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filp.c; sourceTree = "<group>"; };
836F6E9C18BDC2180095E648 /* gbts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gbts.c; sourceTree = "<group>"; }; 836F6E9C18BDC2180095E648 /* gbts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gbts.c; sourceTree = "<group>"; };
836F6E9D18BDC2180095E648 /* ps2_gcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_gcm.c; sourceTree = "<group>"; }; 836F6E9D18BDC2180095E648 /* mcg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mcg.c; sourceTree = "<group>"; };
836F6E9E18BDC2180095E648 /* hgc1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hgc1.c; sourceTree = "<group>"; }; 836F6E9E18BDC2180095E648 /* hgc1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hgc1.c; sourceTree = "<group>"; };
836F6E9F18BDC2180095E648 /* ps2_hsf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_hsf.c; sourceTree = "<group>"; }; 836F6E9F18BDC2180095E648 /* ps2_hsf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_hsf.c; sourceTree = "<group>"; };
836F6EA018BDC2180095E648 /* ps2_iab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_iab.c; sourceTree = "<group>"; }; 836F6EA018BDC2180095E648 /* ps2_iab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_iab.c; sourceTree = "<group>"; };
836F6EA218BDC2180095E648 /* ild.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ild.c; sourceTree = "<group>"; }; 836F6EA218BDC2180095E648 /* ild.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ild.c; sourceTree = "<group>"; };
836F6EA418BDC2180095E648 /* ps2_joe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_joe.c; sourceTree = "<group>"; }; 836F6EA418BDC2180095E648 /* ps2_joe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_joe.c; sourceTree = "<group>"; };
836F6EA618BDC2180095E648 /* vig_kces.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vig_kces.c; sourceTree = "<group>"; }; 836F6EA618BDC2180095E648 /* vig_kces.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vig_kces.c; sourceTree = "<group>"; };
836F6EAA18BDC2180095E648 /* ps2_mcg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_mcg.c; sourceTree = "<group>"; };
836F6EAC18BDC2180095E648 /* mic_koei.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mic_koei.c; sourceTree = "<group>"; }; 836F6EAC18BDC2180095E648 /* mic_koei.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mic_koei.c; sourceTree = "<group>"; };
836F6EB218BDC2180095E648 /* p2bt_move_visa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = p2bt_move_visa.c; sourceTree = "<group>"; }; 836F6EB218BDC2180095E648 /* p2bt_move_visa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = p2bt_move_visa.c; sourceTree = "<group>"; };
836F6EB618BDC2180095E648 /* ps2_rnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rnd.c; sourceTree = "<group>"; }; 836F6EB618BDC2180095E648 /* ps2_rnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rnd.c; sourceTree = "<group>"; };
@ -1511,7 +1533,6 @@
836F6ECD18BDC2190095E648 /* voi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = voi.c; sourceTree = "<group>"; }; 836F6ECD18BDC2190095E648 /* voi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = voi.c; sourceTree = "<group>"; };
836F6ECF18BDC2190095E648 /* ps2_wad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_wad.c; sourceTree = "<group>"; }; 836F6ECF18BDC2190095E648 /* ps2_wad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_wad.c; sourceTree = "<group>"; };
836F6ED018BDC2190095E648 /* wb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wb.c; sourceTree = "<group>"; }; 836F6ED018BDC2190095E648 /* wb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wb.c; sourceTree = "<group>"; };
836F6ED118BDC2190095E648 /* ps2_wmus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_wmus.c; sourceTree = "<group>"; };
836F6ED918BDC2190095E648 /* sndp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sndp.c; sourceTree = "<group>"; }; 836F6ED918BDC2190095E648 /* sndp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sndp.c; sourceTree = "<group>"; };
836F6EE218BDC2190095E648 /* redspark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = redspark.c; sourceTree = "<group>"; }; 836F6EE218BDC2190095E648 /* redspark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = redspark.c; sourceTree = "<group>"; };
836F6EE318BDC2190095E648 /* riff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = riff.c; sourceTree = "<group>"; }; 836F6EE318BDC2190095E648 /* riff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = riff.c; sourceTree = "<group>"; };
@ -1673,6 +1694,37 @@
83B46FD42707FB9A00847FC9 /* endianness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endianness.h; sourceTree = "<group>"; }; 83B46FD42707FB9A00847FC9 /* endianness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endianness.h; sourceTree = "<group>"; };
83B69B212845A26600D2435A /* bw_mp3_riff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bw_mp3_riff.c; sourceTree = "<group>"; }; 83B69B212845A26600D2435A /* bw_mp3_riff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bw_mp3_riff.c; sourceTree = "<group>"; };
83B72E342790452C006007A3 /* libfdk-aac.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libfdk-aac.2.dylib"; path = "../../ThirdParty/fdk-aac/lib/libfdk-aac.2.dylib"; sourceTree = "<group>"; }; 83B72E342790452C006007A3 /* libfdk-aac.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libfdk-aac.2.dylib"; path = "../../ThirdParty/fdk-aac/lib/libfdk-aac.2.dylib"; sourceTree = "<group>"; };
83B73C202D8FEC3A00A57F08 /* oor_helpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = oor_helpers.h; sourceTree = "<group>"; };
83B73C212D8FEC3A00A57F08 /* oor_helpers.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = oor_helpers.c; sourceTree = "<group>"; };
83B73C222D8FEC3A00A57F08 /* vorbis_codebooks_oor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vorbis_codebooks_oor.h; sourceTree = "<group>"; };
83B73C262D8FEC5500A57F08 /* vorbis_custom_utils_oor.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_utils_oor.c; sourceTree = "<group>"; };
83B73C282D8FEC7B00A57F08 /* oor.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = oor.c; sourceTree = "<group>"; };
83B73C2A2D8FED0500A57F08 /* vorbis_codebooks_fsb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vorbis_codebooks_fsb.h; sourceTree = "<group>"; };
83B73C2B2D8FED0500A57F08 /* vorbis_codebooks_wwise.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vorbis_codebooks_wwise.h; sourceTree = "<group>"; };
83B73C2E2D8FEF7A00A57F08 /* minimp3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = minimp3.h; sourceTree = "<group>"; };
83B73C2F2D8FEF7A00A57F08 /* ubi_mpeg_helpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ubi_mpeg_helpers.h; sourceTree = "<group>"; };
83B73C302D8FEF7A00A57F08 /* ubi_mpeg_helpers.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ubi_mpeg_helpers.c; sourceTree = "<group>"; };
83B73C342D8FEFFD00A57F08 /* ubi_mpeg_decoder.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ubi_mpeg_decoder.c; sourceTree = "<group>"; };
83B73C362D8FF15700A57F08 /* mio_erisacontext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mio_erisacontext.h; sourceTree = "<group>"; };
83B73C372D8FF15700A57F08 /* mio_erisacontext.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mio_erisacontext.c; sourceTree = "<group>"; };
83B73C382D8FF15700A57F08 /* mio_erisafile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mio_erisafile.h; sourceTree = "<group>"; };
83B73C392D8FF15700A57F08 /* mio_erisafile.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mio_erisafile.c; sourceTree = "<group>"; };
83B73C3A2D8FF15700A57F08 /* mio_erisamatrix.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mio_erisamatrix.h; sourceTree = "<group>"; };
83B73C3B2D8FF15700A57F08 /* mio_erisamatrix.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mio_erisamatrix.c; sourceTree = "<group>"; };
83B73C3C2D8FF15700A57F08 /* mio_erisasound.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mio_erisasound.h; sourceTree = "<group>"; };
83B73C3D2D8FF15700A57F08 /* mio_erisasound.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mio_erisasound.c; sourceTree = "<group>"; };
83B73C3E2D8FF15700A57F08 /* mio_xerisa.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mio_xerisa.h; sourceTree = "<group>"; };
83B73C482D8FF17900A57F08 /* mio_decoder.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mio_decoder.c; sourceTree = "<group>"; };
83B73C4A2D8FF19800A57F08 /* mio.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mio.c; sourceTree = "<group>"; };
83B73C4C2D8FF1CB00A57F08 /* io_callback.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = io_callback.h; sourceTree = "<group>"; };
83B73C4D2D8FF1CB00A57F08 /* io_callback_sf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = io_callback_sf.h; sourceTree = "<group>"; };
83B73C4E2D8FF1CB00A57F08 /* io_callback_sf.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = io_callback_sf.c; sourceTree = "<group>"; };
83B73C522D8FF1E300A57F08 /* vorbis_codebooks.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vorbis_codebooks.h; sourceTree = "<group>"; };
83B73C532D8FF1E300A57F08 /* vorbis_codebooks.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vorbis_codebooks.c; sourceTree = "<group>"; };
83B73C562D8FF27000A57F08 /* 2dx.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = 2dx.c; sourceTree = "<group>"; };
83B73C582D8FF37700A57F08 /* api_libsf_cache.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = api_libsf_cache.c; sourceTree = "<group>"; };
83B73C592D8FF37700A57F08 /* codec_info.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = codec_info.h; sourceTree = "<group>"; };
83B73C5A2D8FF37700A57F08 /* codec_info.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = codec_info.c; sourceTree = "<group>"; };
83B8FE2A2D5AB1F5005854C1 /* axhd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = axhd.c; sourceTree = "<group>"; }; 83B8FE2A2D5AB1F5005854C1 /* axhd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = axhd.c; sourceTree = "<group>"; };
83B8FE2C2D5AB2A5005854C1 /* shaa.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = shaa.c; sourceTree = "<group>"; }; 83B8FE2C2D5AB2A5005854C1 /* shaa.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = shaa.c; sourceTree = "<group>"; };
83B8FE2E2D5AB2F4005854C1 /* xwb_konami.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = xwb_konami.c; sourceTree = "<group>"; }; 83B8FE2E2D5AB2F4005854C1 /* xwb_konami.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = xwb_konami.c; sourceTree = "<group>"; };
@ -1896,10 +1948,22 @@
834F7D392C7093EA003AC386 /* libacm.h */, 834F7D392C7093EA003AC386 /* libacm.h */,
834F7D382C7093EA003AC386 /* libacm_decode.c */, 834F7D382C7093EA003AC386 /* libacm_decode.c */,
834F7D3A2C7093EA003AC386 /* libacm_util.c */, 834F7D3A2C7093EA003AC386 /* libacm_util.c */,
83B73C2E2D8FEF7A00A57F08 /* minimp3.h */,
83B73C362D8FF15700A57F08 /* mio_erisacontext.h */,
83B73C372D8FF15700A57F08 /* mio_erisacontext.c */,
83B73C382D8FF15700A57F08 /* mio_erisafile.h */,
83B73C392D8FF15700A57F08 /* mio_erisafile.c */,
83B73C3A2D8FF15700A57F08 /* mio_erisamatrix.h */,
83B73C3B2D8FF15700A57F08 /* mio_erisamatrix.c */,
83B73C3C2D8FF15700A57F08 /* mio_erisasound.h */,
83B73C3D2D8FF15700A57F08 /* mio_erisasound.c */,
83B73C3E2D8FF15700A57F08 /* mio_xerisa.h */,
834F7D792C7093EA003AC386 /* nwa_lib.h */, 834F7D792C7093EA003AC386 /* nwa_lib.h */,
834F7D342C7093EA003AC386 /* nwa_lib.c */, 834F7D342C7093EA003AC386 /* nwa_lib.c */,
834F7E7A2C709E66003AC386 /* ongakukan_adp_lib.h */, 834F7E7A2C709E66003AC386 /* ongakukan_adp_lib.h */,
834F7E792C709E66003AC386 /* ongakukan_adp_lib.c */, 834F7E792C709E66003AC386 /* ongakukan_adp_lib.c */,
83B73C202D8FEC3A00A57F08 /* oor_helpers.h */,
83B73C212D8FEC3A00A57F08 /* oor_helpers.c */,
834F7D832C7093EA003AC386 /* relic_lib.h */, 834F7D832C7093EA003AC386 /* relic_lib.h */,
834F7D822C7093EA003AC386 /* relic_lib.c */, 834F7D822C7093EA003AC386 /* relic_lib.c */,
834F7D842C7093EA003AC386 /* relic_mixfft.c */, 834F7D842C7093EA003AC386 /* relic_mixfft.c */,
@ -1907,8 +1971,13 @@
834F7D8C2C7093EA003AC386 /* tac_lib.h */, 834F7D8C2C7093EA003AC386 /* tac_lib.h */,
834F7D8B2C7093EA003AC386 /* tac_lib.c */, 834F7D8B2C7093EA003AC386 /* tac_lib.c */,
834F7D8A2C7093EA003AC386 /* tac_ops.h */, 834F7D8A2C7093EA003AC386 /* tac_ops.h */,
83B73C2F2D8FEF7A00A57F08 /* ubi_mpeg_helpers.h */,
83B73C302D8FEF7A00A57F08 /* ubi_mpeg_helpers.c */,
834F7D362C7093EA003AC386 /* utkdec.h */, 834F7D362C7093EA003AC386 /* utkdec.h */,
834F7D352C7093EA003AC386 /* utkdec.c */, 834F7D352C7093EA003AC386 /* utkdec.c */,
83B73C2A2D8FED0500A57F08 /* vorbis_codebooks_fsb.h */,
83B73C222D8FEC3A00A57F08 /* vorbis_codebooks_oor.h */,
83B73C2B2D8FED0500A57F08 /* vorbis_codebooks_wwise.h */,
); );
path = libs; path = libs;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1924,7 +1993,6 @@
834F7D442C7093EA003AC386 /* circus_decoder.c */, 834F7D442C7093EA003AC386 /* circus_decoder.c */,
834F7D472C7093EA003AC386 /* coding.h */, 834F7D472C7093EA003AC386 /* coding.h */,
834F7D462C7093EA003AC386 /* coding_utils.c */, 834F7D462C7093EA003AC386 /* coding_utils.c */,
834F7D452C7093EA003AC386 /* coding_utils_samples.h */,
834F7D4A2C7093EA003AC386 /* compresswave_decoder.c */, 834F7D4A2C7093EA003AC386 /* compresswave_decoder.c */,
834F7D4B2C7093EA003AC386 /* derf_decoder.c */, 834F7D4B2C7093EA003AC386 /* derf_decoder.c */,
834F7D4C2C7093EA003AC386 /* dpcm_kcej_decoder.c */, 834F7D4C2C7093EA003AC386 /* dpcm_kcej_decoder.c */,
@ -1949,6 +2017,7 @@
834F7D672C7093EA003AC386 /* l5_555_decoder.c */, 834F7D672C7093EA003AC386 /* l5_555_decoder.c */,
834F7D372C7093EA003AC386 /* libs */, 834F7D372C7093EA003AC386 /* libs */,
834F7D682C7093EA003AC386 /* lsf_decoder.c */, 834F7D682C7093EA003AC386 /* lsf_decoder.c */,
83B73C482D8FF17900A57F08 /* mio_decoder.c */,
834F7D6A2C7093EA003AC386 /* mp4_aac_decoder.c */, 834F7D6A2C7093EA003AC386 /* mp4_aac_decoder.c */,
834F7D692C7093EA003AC386 /* mpc3_decoder.c */, 834F7D692C7093EA003AC386 /* mpc3_decoder.c */,
834F7D6E2C7093EA003AC386 /* mpeg_custom_utils.c */, 834F7D6E2C7093EA003AC386 /* mpeg_custom_utils.c */,
@ -1980,15 +2049,15 @@
834F7D8E2C7093EA003AC386 /* tantalus_decoder.c */, 834F7D8E2C7093EA003AC386 /* tantalus_decoder.c */,
834F7D8F2C7093EA003AC386 /* tgcadpcm_decoder.c */, 834F7D8F2C7093EA003AC386 /* tgcadpcm_decoder.c */,
834F7D902C7093EA003AC386 /* ubi_adpcm_decoder.c */, 834F7D902C7093EA003AC386 /* ubi_adpcm_decoder.c */,
83B73C342D8FEFFD00A57F08 /* ubi_mpeg_decoder.c */,
834F7D912C7093EA003AC386 /* vadpcm_decoder.c */, 834F7D912C7093EA003AC386 /* vadpcm_decoder.c */,
834F7D922C7093EA003AC386 /* vorbis_custom_data_fsb.h */,
834F7D932C7093EA003AC386 /* vorbis_custom_data_wwise.h */,
834F7D952C7093EA003AC386 /* vorbis_custom_decoder.h */, 834F7D952C7093EA003AC386 /* vorbis_custom_decoder.h */,
834F7D942C7093EA003AC386 /* vorbis_custom_decoder.c */, 834F7D942C7093EA003AC386 /* vorbis_custom_decoder.c */,
834F7D9C2C7093EA003AC386 /* vorbis_custom_utils.c */, 834F7D9C2C7093EA003AC386 /* vorbis_custom_utils.c */,
834F7D962C7093EA003AC386 /* vorbis_custom_utils_awc.c */, 834F7D962C7093EA003AC386 /* vorbis_custom_utils_awc.c */,
834F7D972C7093EA003AC386 /* vorbis_custom_utils_fsb.c */, 834F7D972C7093EA003AC386 /* vorbis_custom_utils_fsb.c */,
834F7D982C7093EA003AC386 /* vorbis_custom_utils_ogl.c */, 834F7D982C7093EA003AC386 /* vorbis_custom_utils_ogl.c */,
83B73C262D8FEC5500A57F08 /* vorbis_custom_utils_oor.c */,
834F7D992C7093EA003AC386 /* vorbis_custom_utils_sk.c */, 834F7D992C7093EA003AC386 /* vorbis_custom_utils_sk.c */,
834F7D9A2C7093EA003AC386 /* vorbis_custom_utils_vid1.c */, 834F7D9A2C7093EA003AC386 /* vorbis_custom_utils_vid1.c */,
834F7D9B2C7093EA003AC386 /* vorbis_custom_utils_wwise.c */, 834F7D9B2C7093EA003AC386 /* vorbis_custom_utils_wwise.c */,
@ -2010,7 +2079,10 @@
834F7EA02C70A786003AC386 /* api_helpers.c */, 834F7EA02C70A786003AC386 /* api_helpers.c */,
834F7EA12C70A786003AC386 /* api_internal.h */, 834F7EA12C70A786003AC386 /* api_internal.h */,
834F7EA22C70A786003AC386 /* api_libsf.c */, 834F7EA22C70A786003AC386 /* api_libsf.c */,
83B73C582D8FF37700A57F08 /* api_libsf_cache.c */,
834F7EA32C70A786003AC386 /* api_tags.c */, 834F7EA32C70A786003AC386 /* api_tags.c */,
83B73C592D8FF37700A57F08 /* codec_info.h */,
83B73C5A2D8FF37700A57F08 /* codec_info.c */,
834F7EA62C70A786003AC386 /* decode.h */, 834F7EA62C70A786003AC386 /* decode.h */,
834F7EA52C70A786003AC386 /* decode.c */, 834F7EA52C70A786003AC386 /* decode.c */,
834845772D27F2E9000E4928 /* decode_state.h */, 834845772D27F2E9000E4928 /* decode_state.h */,
@ -2217,6 +2289,7 @@
836F6E2718BDC2180095E648 /* meta */ = { 836F6E2718BDC2180095E648 /* meta */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
83B73C562D8FF27000A57F08 /* 2dx.c */,
836F6E2918BDC2180095E648 /* 2dx9.c */, 836F6E2918BDC2180095E648 /* 2dx9.c */,
836F6E8D18BDC2180095E648 /* 2pfs.c */, 836F6E8D18BDC2180095E648 /* 2pfs.c */,
83C727FE22BC893900678B4A /* 9tav.c */, 83C727FE22BC893900678B4A /* 9tav.c */,
@ -2420,9 +2493,11 @@
836F6E5C18BDC2180095E648 /* mattel_hyperscan.c */, 836F6E5C18BDC2180095E648 /* mattel_hyperscan.c */,
836F6E5D18BDC2180095E648 /* maxis_xa.c */, 836F6E5D18BDC2180095E648 /* maxis_xa.c */,
83EDE5D61A70951A005F5D84 /* mca.c */, 83EDE5D61A70951A005F5D84 /* mca.c */,
836F6E9D18BDC2180095E648 /* mcg.c */,
836F6E5E18BDC2180095E648 /* meta.h */, 836F6E5E18BDC2180095E648 /* meta.h */,
834FE0DE215C79EB000A5D3D /* mib_mih.c */, 834FE0DE215C79EB000A5D3D /* mib_mih.c */,
836F6EAC18BDC2180095E648 /* mic_koei.c */, 836F6EAC18BDC2180095E648 /* mic_koei.c */,
83B73C4A2D8FF19800A57F08 /* mio.c */,
8346D97725BF838C00D1A8B0 /* mjb_mjh.c */, 8346D97725BF838C00D1A8B0 /* mjb_mjh.c */,
836F6E5F18BDC2180095E648 /* mn_str.c */, 836F6E5F18BDC2180095E648 /* mn_str.c */,
8349A9031FE6258100E26435 /* mogg.c */, 8349A9031FE6258100E26435 /* mogg.c */,
@ -2483,6 +2558,7 @@
831BA60F1EAC61A500CF89B0 /* ogl.c */, 831BA60F1EAC61A500CF89B0 /* ogl.c */,
83AF2CC726226BA400538240 /* ogv_3rdeye.c */, 83AF2CC726226BA400538240 /* ogv_3rdeye.c */,
8349A8FB1FE6257F00E26435 /* omu.c */, 8349A8FB1FE6257F00E26435 /* omu.c */,
83B73C282D8FEC7B00A57F08 /* oor.c */,
8306B0CE2098458E000302D4 /* opus.c */, 8306B0CE2098458E000302D4 /* opus.c */,
8306B0CD2098458E000302D4 /* opus_interleave_streamfile.h */, 8306B0CD2098458E000302D4 /* opus_interleave_streamfile.h */,
836F6EB218BDC2180095E648 /* p2bt_move_visa.c */, 836F6EB218BDC2180095E648 /* p2bt_move_visa.c */,
@ -2505,21 +2581,17 @@
836F6E9118BDC2180095E648 /* ps2_ass.c */, 836F6E9118BDC2180095E648 /* ps2_ass.c */,
836F6E9418BDC2180095E648 /* ps2_b1s.c */, 836F6E9418BDC2180095E648 /* ps2_b1s.c */,
836F6E9618BDC2180095E648 /* ps2_bmdx.c */, 836F6E9618BDC2180095E648 /* ps2_bmdx.c */,
836F6E9D18BDC2180095E648 /* ps2_gcm.c */,
836F6E9F18BDC2180095E648 /* ps2_hsf.c */, 836F6E9F18BDC2180095E648 /* ps2_hsf.c */,
836F6EA018BDC2180095E648 /* ps2_iab.c */, 836F6EA018BDC2180095E648 /* ps2_iab.c */,
836F6EA418BDC2180095E648 /* ps2_joe.c */, 836F6EA418BDC2180095E648 /* ps2_joe.c */,
836F6EAA18BDC2180095E648 /* ps2_mcg.c */,
836F6EB618BDC2180095E648 /* ps2_rnd.c */, 836F6EB618BDC2180095E648 /* ps2_rnd.c */,
836F6EBD18BDC2180095E648 /* ps2_snd.c */, 836F6EBD18BDC2180095E648 /* ps2_snd.c */,
836F6EBF18BDC2190095E648 /* ps2_sps.c */, 836F6EBF18BDC2190095E648 /* ps2_sps.c */,
836F6EC518BDC2190095E648 /* ps2_tec.c */, 836F6EC518BDC2190095E648 /* ps2_tec.c */,
832BF80D21E05148006F50F1 /* ps2_va3.c */,
836F6EC918BDC2190095E648 /* ps2_vbk.c */, 836F6EC918BDC2190095E648 /* ps2_vbk.c */,
836F6ECB18BDC2190095E648 /* ps2_vgv.c */, 836F6ECB18BDC2190095E648 /* ps2_vgv.c */,
836F6ECC18BDC2190095E648 /* ps2_vms.c */, 836F6ECC18BDC2190095E648 /* ps2_vms.c */,
836F6ECF18BDC2190095E648 /* ps2_wad.c */, 836F6ECF18BDC2190095E648 /* ps2_wad.c */,
836F6ED118BDC2190095E648 /* ps2_wmus.c */,
8315868326F586E200803A3A /* psb.c */, 8315868326F586E200803A3A /* psb.c */,
837CEAE823487F2B00E62A4A /* psf.c */, 837CEAE823487F2B00E62A4A /* psf.c */,
836F6E5518BDC2180095E648 /* psnd.c */, 836F6E5518BDC2180095E648 /* psnd.c */,
@ -2639,6 +2711,7 @@
834FE0C5215C79E6000A5D3D /* ue4opus.c */, 834FE0C5215C79E6000A5D3D /* ue4opus.c */,
83B8FE302D5AB421005854C1 /* undefind.c */, 83B8FE302D5AB421005854C1 /* undefind.c */,
834FE0DD215C79EB000A5D3D /* utk.c */, 834FE0DD215C79EB000A5D3D /* utk.c */,
832BF80D21E05148006F50F1 /* va3.c */,
83D1189228B2F33400AF3370 /* vab.c */, 83D1189228B2F33400AF3370 /* vab.c */,
834FE0E4215C79EC000A5D3D /* vag.c */, 834FE0E4215C79EC000A5D3D /* vag.c */,
834FE0D3215C79E9000A5D3D /* vai.c */, 834FE0D3215C79E9000A5D3D /* vai.c */,
@ -2735,42 +2808,47 @@
833E82F92A28595A00CD0580 /* bitstream_lsb.h */, 833E82F92A28595A00CD0580 /* bitstream_lsb.h */,
836DF620298F83F400CD0580 /* bitstream_msb.h */, 836DF620298F83F400CD0580 /* bitstream_msb.h */,
833E82C72A28566700CD0580 /* channel_mappings.h */, 833E82C72A28566700CD0580 /* channel_mappings.h */,
83D26A8026E66DC2001A9475 /* chunks.c */,
83D26A7E26E66DC2001A9475 /* chunks.h */, 83D26A7E26E66DC2001A9475 /* chunks.h */,
834F7D132C70861D003AC386 /* cipher_blowfish.c */, 83D26A8026E66DC2001A9475 /* chunks.c */,
834F7D122C70861D003AC386 /* cipher_blowfish.h */, 834F7D122C70861D003AC386 /* cipher_blowfish.h */,
834F7D1A2C708719003AC386 /* cipher_xxtea.c */, 834F7D132C70861D003AC386 /* cipher_blowfish.c */,
834F7D1B2C708719003AC386 /* cipher_xxtea.h */, 834F7D1B2C708719003AC386 /* cipher_xxtea.h */,
833E82EB2A28587D00CD0580 /* companion_files.c */, 834F7D1A2C708719003AC386 /* cipher_xxtea.c */,
833E82EF2A28587D00CD0580 /* companion_files.h */, 833E82EF2A28587D00CD0580 /* companion_files.h */,
836DF621298F83F400CD0580 /* cri_keys.c */, 833E82EB2A28587D00CD0580 /* companion_files.c */,
836DF61F298F83F400CD0580 /* cri_keys.h */, 836DF61F298F83F400CD0580 /* cri_keys.h */,
836F46B5282087A6005B9B87 /* cri_utf.c */, 836DF621298F83F400CD0580 /* cri_keys.c */,
836F46B6282087A6005B9B87 /* cri_utf.h */, 836F46B6282087A6005B9B87 /* cri_utf.h */,
836F46B5282087A6005B9B87 /* cri_utf.c */,
83B46FD42707FB9A00847FC9 /* endianness.h */, 83B46FD42707FB9A00847FC9 /* endianness.h */,
83C0C75E2AA436370056AFD8 /* layout_utils.c */, 83B73C4C2D8FF1CB00A57F08 /* io_callback.h */,
83B73C4D2D8FF1CB00A57F08 /* io_callback_sf.h */,
83B73C4E2D8FF1CB00A57F08 /* io_callback_sf.c */,
83C0C75F2AA436370056AFD8 /* layout_utils.h */, 83C0C75F2AA436370056AFD8 /* layout_utils.h */,
83D26A7D26E66DC2001A9475 /* log.c */, 83C0C75E2AA436370056AFD8 /* layout_utils.c */,
83D26A7F26E66DC2001A9475 /* log.h */, 83D26A7F26E66DC2001A9475 /* log.h */,
8315868826F586F900803A3A /* m2_psb.c */, 83D26A7D26E66DC2001A9475 /* log.c */,
8315868926F586F900803A3A /* m2_psb.h */, 8315868926F586F900803A3A /* m2_psb.h */,
834F7E9A2C70A6E1003AC386 /* meta_utils.c */, 8315868826F586F900803A3A /* m2_psb.c */,
834F7E992C70A6E1003AC386 /* meta_utils.h */, 834F7E992C70A6E1003AC386 /* meta_utils.h */,
8319017A28F67EE100B70711 /* miniz.c */, 834F7E9A2C70A6E1003AC386 /* meta_utils.c */,
8319017928F67EE000B70711 /* miniz.h */, 8319017928F67EE000B70711 /* miniz.h */,
833E82EC2A28587D00CD0580 /* paths.c */, 8319017A28F67EE100B70711 /* miniz.c */,
833E82ED2A28587D00CD0580 /* paths.h */, 833E82ED2A28587D00CD0580 /* paths.h */,
833E82C92A2856B200CD0580 /* reader_get_nibbles.h */, 833E82EC2A28587D00CD0580 /* paths.c */,
833E82F52A2858EF00CD0580 /* reader.c */,
833E82CA2A2856B200CD0580 /* reader_get.h */, 833E82CA2A2856B200CD0580 /* reader_get.h */,
833E82C92A2856B200CD0580 /* reader_get_nibbles.h */,
833E82CB2A2856B200CD0580 /* reader_put.h */, 833E82CB2A2856B200CD0580 /* reader_put.h */,
833E82EE2A28587D00CD0580 /* reader_sf.h */, 833E82EE2A28587D00CD0580 /* reader_sf.h */,
833E82F62A2858EF00CD0580 /* reader_text.h */, 833E82F62A2858EF00CD0580 /* reader_text.h */,
833E82F52A2858EF00CD0580 /* reader.c */,
83FBB17B2A4FF87200CD0580 /* sf_utils.c */,
83FBB17A2A4FF87200CD0580 /* sf_utils.h */, 83FBB17A2A4FF87200CD0580 /* sf_utils.h */,
8339B324280FDF4B0076F74B /* text_reader.c */, 83FBB17B2A4FF87200CD0580 /* sf_utils.c */,
8339B325280FDF4B0076F74B /* text_reader.h */, 8339B325280FDF4B0076F74B /* text_reader.h */,
8339B324280FDF4B0076F74B /* text_reader.c */,
834F7E772C709D0E003AC386 /* vgmstream_limits.h */, 834F7E772C709D0E003AC386 /* vgmstream_limits.h */,
83B73C522D8FF1E300A57F08 /* vorbis_codebooks.h */,
83B73C532D8FF1E300A57F08 /* vorbis_codebooks.c */,
834F7E102C709933003AC386 /* zlib_vgmstream.h */, 834F7E102C709933003AC386 /* zlib_vgmstream.h */,
); );
path = util; path = util;
@ -2811,9 +2889,12 @@
834F7DC42C7093EA003AC386 /* g72x_state.h in Headers */, 834F7DC42C7093EA003AC386 /* g72x_state.h in Headers */,
834F7ED62C70A786003AC386 /* plugins.h in Headers */, 834F7ED62C70A786003AC386 /* plugins.h in Headers */,
834F7E782C709D0E003AC386 /* vgmstream_limits.h in Headers */, 834F7E782C709D0E003AC386 /* vgmstream_limits.h in Headers */,
83B73C5B2D8FF37700A57F08 /* codec_info.h in Headers */,
83D26A8226E66DC2001A9475 /* chunks.h in Headers */, 83D26A8226E66DC2001A9475 /* chunks.h in Headers */,
835096F32C9979DD00163D93 /* libvgmstream_streamfile.h in Headers */,
836F705518BDC2190095E648 /* streamtypes.h in Headers */, 836F705518BDC2190095E648 /* streamtypes.h in Headers */,
83CBF5362D46309100AA2D75 /* ka1a_dec.h in Headers */, 83CBF5362D46309100AA2D75 /* ka1a_dec.h in Headers */,
835096F22C9979DD00163D93 /* libvgmstream.h in Headers */,
83CBF5372D46309100AA2D75 /* ka1a_dec_data.h in Headers */, 83CBF5372D46309100AA2D75 /* ka1a_dec_data.h in Headers */,
833E82CF2A2856B200CD0580 /* reader_get_nibbles.h in Headers */, 833E82CF2A2856B200CD0580 /* reader_get_nibbles.h in Headers */,
833E82D12A2856B200CD0580 /* reader_put.h in Headers */, 833E82D12A2856B200CD0580 /* reader_put.h in Headers */,
@ -2848,6 +2929,8 @@
83B46FD52707FB9A00847FC9 /* endianness.h in Headers */, 83B46FD52707FB9A00847FC9 /* endianness.h in Headers */,
834F7D092C7085EB003AC386 /* str_wav_streamfile.h in Headers */, 834F7D092C7085EB003AC386 /* str_wav_streamfile.h in Headers */,
836F705718BDC2190095E648 /* util.h in Headers */, 836F705718BDC2190095E648 /* util.h in Headers */,
83B73C4F2D8FF1CB00A57F08 /* io_callback_sf.h in Headers */,
83B73C502D8FF1CB00A57F08 /* io_callback.h in Headers */,
834F7DF82C7093EA003AC386 /* tac_ops.h in Headers */, 834F7DF82C7093EA003AC386 /* tac_ops.h in Headers */,
83256CC128666C620036D9C0 /* index.h in Headers */, 83256CC128666C620036D9C0 /* index.h in Headers */,
834FE0ED215C79ED000A5D3D /* fsb_interleave_streamfile.h in Headers */, 834FE0ED215C79ED000A5D3D /* fsb_interleave_streamfile.h in Headers */,
@ -2871,8 +2954,6 @@
83256CD628666C620036D9C0 /* newhuffman.h in Headers */, 83256CD628666C620036D9C0 /* newhuffman.h in Headers */,
835C883722CC17BE001B4B3F /* ogg_vorbis_streamfile.h in Headers */, 835C883722CC17BE001B4B3F /* ogg_vorbis_streamfile.h in Headers */,
837CEAFE23487F2C00E62A4A /* jstm_streamfile.h in Headers */, 837CEAFE23487F2C00E62A4A /* jstm_streamfile.h in Headers */,
835096F22C9979DD00163D93 /* libvgmstream.h in Headers */,
835096F32C9979DD00163D93 /* libvgmstream_streamfile.h in Headers */,
834F7DB02C7093EA003AC386 /* circus_vq_lib.h in Headers */, 834F7DB02C7093EA003AC386 /* circus_vq_lib.h in Headers */,
832BF82021E0514B006F50F1 /* zsnd_streamfile.h in Headers */, 832BF82021E0514B006F50F1 /* zsnd_streamfile.h in Headers */,
834F7E862C709FED003AC386 /* api_version.h in Headers */, 834F7E862C709FED003AC386 /* api_version.h in Headers */,
@ -2901,6 +2982,8 @@
83256CD128666C620036D9C0 /* mpg123lib_intern.h in Headers */, 83256CD128666C620036D9C0 /* mpg123lib_intern.h in Headers */,
83C7281622BC893D00678B4A /* xwma_konami_streamfile.h in Headers */, 83C7281622BC893D00678B4A /* xwma_konami_streamfile.h in Headers */,
834F7D1D2C708719003AC386 /* cipher_xxtea.h in Headers */, 834F7D1D2C708719003AC386 /* cipher_xxtea.h in Headers */,
83B73C312D8FEF7A00A57F08 /* ubi_mpeg_helpers.h in Headers */,
83B73C322D8FEF7A00A57F08 /* minimp3.h in Headers */,
833E82C82A28566700CD0580 /* channel_mappings.h in Headers */, 833E82C82A28566700CD0580 /* channel_mappings.h in Headers */,
83256CC028666C620036D9C0 /* synth_8bit.h in Headers */, 83256CC028666C620036D9C0 /* synth_8bit.h in Headers */,
834F7DCB2C7093EA003AC386 /* g7221_lib.h in Headers */, 834F7DCB2C7093EA003AC386 /* g7221_lib.h in Headers */,
@ -2925,15 +3008,20 @@
834F7E202C709AE0003AC386 /* api_tags.h in Headers */, 834F7E202C709AE0003AC386 /* api_tags.h in Headers */,
8396BE7B2935FC2F00CD0580 /* sscf_encrypted.h in Headers */, 8396BE7B2935FC2F00CD0580 /* sscf_encrypted.h in Headers */,
83FBD506235D31F800D35BCD /* riff_ogg_streamfile.h in Headers */, 83FBD506235D31F800D35BCD /* riff_ogg_streamfile.h in Headers */,
83B73C3F2D8FF15700A57F08 /* mio_xerisa.h in Headers */,
83B73C402D8FF15700A57F08 /* mio_erisasound.h in Headers */,
83B73C412D8FF15700A57F08 /* mio_erisacontext.h in Headers */,
83B73C422D8FF15700A57F08 /* mio_erisafile.h in Headers */,
83B73C432D8FF15700A57F08 /* mio_erisamatrix.h in Headers */,
8339B327280FDF4B0076F74B /* text_reader.h in Headers */, 8339B327280FDF4B0076F74B /* text_reader.h in Headers */,
834F7E002C7093EA003AC386 /* vorbis_custom_data_fsb.h in Headers */,
834F7DD12C7093EA003AC386 /* icelib.h in Headers */, 834F7DD12C7093EA003AC386 /* icelib.h in Headers */,
836F6F9A18BDC2190095E648 /* meta.h in Headers */, 836F6F9A18BDC2190095E648 /* meta.h in Headers */,
8319017B28F67EE100B70711 /* miniz.h in Headers */, 8319017B28F67EE100B70711 /* miniz.h in Headers */,
834F7DA52C7093EA003AC386 /* utkdec.h in Headers */, 834F7DA52C7093EA003AC386 /* utkdec.h in Headers */,
834F7ECE2C70A786003AC386 /* mixer_priv.h in Headers */, 834F7ECE2C70A786003AC386 /* mixer_priv.h in Headers */,
83B73C232D8FEC3A00A57F08 /* vorbis_codebooks_oor.h in Headers */,
83B73C242D8FEC3A00A57F08 /* oor_helpers.h in Headers */,
833E82FA2A28595A00CD0580 /* bitstream_lsb.h in Headers */, 833E82FA2A28595A00CD0580 /* bitstream_lsb.h in Headers */,
834F7DB32C7093EA003AC386 /* coding_utils_samples.h in Headers */,
834F7DF72C7093EA003AC386 /* tac_data.h in Headers */, 834F7DF72C7093EA003AC386 /* tac_data.h in Headers */,
834F7DFA2C7093EA003AC386 /* tac_lib.h in Headers */, 834F7DFA2C7093EA003AC386 /* tac_lib.h in Headers */,
83A8BAE625667AA8000F5F3F /* lp_ap_lep_streamfile.h in Headers */, 83A8BAE625667AA8000F5F3F /* lp_ap_lep_streamfile.h in Headers */,
@ -2972,16 +3060,18 @@
83256CD728666C620036D9C0 /* synth_mono.h in Headers */, 83256CD728666C620036D9C0 /* synth_mono.h in Headers */,
834F7DCE2C7093EA003AC386 /* clhca.h in Headers */, 834F7DCE2C7093EA003AC386 /* clhca.h in Headers */,
8349A91B1FE6258200E26435 /* adx_keys.h in Headers */, 8349A91B1FE6258200E26435 /* adx_keys.h in Headers */,
834F7E012C7093EA003AC386 /* vorbis_custom_data_wwise.h in Headers */,
836F6F4D18BDC2190095E648 /* layout.h in Headers */, 836F6F4D18BDC2190095E648 /* layout.h in Headers */,
83269DD22399F5DE00F49FE3 /* nus3bank_streamfile.h in Headers */, 83269DD22399F5DE00F49FE3 /* nus3bank_streamfile.h in Headers */,
83AA5D251F6E2F9C0020821C /* hca_keys.h in Headers */, 83AA5D251F6E2F9C0020821C /* hca_keys.h in Headers */,
834F7E832C709F5B003AC386 /* apa3_streamfile.h in Headers */, 834F7E832C709F5B003AC386 /* apa3_streamfile.h in Headers */,
83256CDA28666C620036D9C0 /* l2tables.h in Headers */, 83256CDA28666C620036D9C0 /* l2tables.h in Headers */,
83256CC828666C620036D9C0 /* getbits.h in Headers */, 83256CC828666C620036D9C0 /* getbits.h in Headers */,
83B73C2C2D8FED0500A57F08 /* vorbis_codebooks_wwise.h in Headers */,
83B73C2D2D8FED0500A57F08 /* vorbis_codebooks_fsb.h in Headers */,
83256CC728666C620036D9C0 /* optimize.h in Headers */, 83256CC728666C620036D9C0 /* optimize.h in Headers */,
83031ED3243C50DF00C3F3E0 /* fsb5_streamfile.h in Headers */, 83031ED3243C50DF00C3F3E0 /* fsb5_streamfile.h in Headers */,
83256CE328666C620036D9C0 /* decode.h in Headers */, 83256CE328666C620036D9C0 /* decode.h in Headers */,
83B73C542D8FF1E300A57F08 /* vorbis_codebooks.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -3179,6 +3269,8 @@
832BF82821E0514B006F50F1 /* xwma.c in Sources */, 832BF82821E0514B006F50F1 /* xwma.c in Sources */,
83FC176E23AC58D100E1025F /* csb.c in Sources */, 83FC176E23AC58D100E1025F /* csb.c in Sources */,
836F46B32820874D005B9B87 /* esf.c in Sources */, 836F46B32820874D005B9B87 /* esf.c in Sources */,
83B73C512D8FF1CB00A57F08 /* io_callback_sf.c in Sources */,
83B73C352D8FEFFD00A57F08 /* ubi_mpeg_decoder.c in Sources */,
8306B0EB20984590000302D4 /* wave_segmented.c in Sources */, 8306B0EB20984590000302D4 /* wave_segmented.c in Sources */,
836F6F9F18BDC2190095E648 /* musc.c in Sources */, 836F6F9F18BDC2190095E648 /* musc.c in Sources */,
8349A9121FE6258200E26435 /* smss.c in Sources */, 8349A9121FE6258200E26435 /* smss.c in Sources */,
@ -3229,6 +3321,7 @@
836F6F9418BDC2190095E648 /* iivb.c in Sources */, 836F6F9418BDC2190095E648 /* iivb.c in Sources */,
836F6F8D18BDC2190095E648 /* gsnd.c in Sources */, 836F6F8D18BDC2190095E648 /* gsnd.c in Sources */,
836F704518BDC2190095E648 /* wvs.c in Sources */, 836F704518BDC2190095E648 /* wvs.c in Sources */,
83B73C292D8FEC7B00A57F08 /* oor.c in Sources */,
839FBFFB26C354E70016A78A /* wxd_wxh.c in Sources */, 839FBFFB26C354E70016A78A /* wxd_wxh.c in Sources */,
83EDE5D91A70951A005F5D84 /* btsnd.c in Sources */, 83EDE5D91A70951A005F5D84 /* btsnd.c in Sources */,
834F7DD72C7093EA003AC386 /* mpc3_decoder.c in Sources */, 834F7DD72C7093EA003AC386 /* mpc3_decoder.c in Sources */,
@ -3336,6 +3429,7 @@
835DF7032C79ABB50008814A /* sbuf.c in Sources */, 835DF7032C79ABB50008814A /* sbuf.c in Sources */,
830EBE142004656E0023AA10 /* ktss.c in Sources */, 830EBE142004656E0023AA10 /* ktss.c in Sources */,
836F6F6618BDC2190095E648 /* aax.c in Sources */, 836F6F6618BDC2190095E648 /* aax.c in Sources */,
83B73C272D8FEC5500A57F08 /* vorbis_custom_utils_oor.c in Sources */,
8306B0BC20984552000302D4 /* blocked_vs.c in Sources */, 8306B0BC20984552000302D4 /* blocked_vs.c in Sources */,
83AA7F812519C042004C5298 /* silence.c in Sources */, 83AA7F812519C042004C5298 /* silence.c in Sources */,
837CEAF823487F2C00E62A4A /* xwv_valve.c in Sources */, 837CEAF823487F2C00E62A4A /* xwv_valve.c in Sources */,
@ -3430,6 +3524,7 @@
837CEAD823487E8300E62A4A /* bmp_konami.c in Sources */, 837CEAD823487E8300E62A4A /* bmp_konami.c in Sources */,
834F7DDC2C7093EA003AC386 /* mpeg_custom_utils.c in Sources */, 834F7DDC2C7093EA003AC386 /* mpeg_custom_utils.c in Sources */,
834F7E922C70A1AB003AC386 /* vgmstream_init.c in Sources */, 834F7E922C70A1AB003AC386 /* vgmstream_init.c in Sources */,
83B73C332D8FEF7A00A57F08 /* ubi_mpeg_helpers.c in Sources */,
836F700118BDC2190095E648 /* ps2_tec.c in Sources */, 836F700118BDC2190095E648 /* ps2_tec.c in Sources */,
832BF82121E0514B006F50F1 /* zsnd.c in Sources */, 832BF82121E0514B006F50F1 /* zsnd.c in Sources */,
836F703018BDC2190095E648 /* sqex_scd.c in Sources */, 836F703018BDC2190095E648 /* sqex_scd.c in Sources */,
@ -3486,8 +3581,9 @@
834F7CFD2C70834D003AC386 /* nxof.c in Sources */, 834F7CFD2C70834D003AC386 /* nxof.c in Sources */,
836F6FC718BDC2190095E648 /* pona.c in Sources */, 836F6FC718BDC2190095E648 /* pona.c in Sources */,
8306B0B820984552000302D4 /* blocked_ws_aud.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 /* cbx.c in Sources */,
836F6FE618BDC2190095E648 /* ps2_mcg.c in Sources */,
83AA5D241F6E2F9C0020821C /* awc.c in Sources */, 83AA5D241F6E2F9C0020821C /* awc.c in Sources */,
8349A8E91FE6253900E26435 /* blocked_ea_1snh.c in Sources */, 8349A8E91FE6253900E26435 /* blocked_ea_1snh.c in Sources */,
8306B0E620984590000302D4 /* msb_msh.c in Sources */, 8306B0E620984590000302D4 /* msb_msh.c in Sources */,
@ -3520,6 +3616,7 @@
83CBF5432D46339200AA2D75 /* skex.c in Sources */, 83CBF5432D46339200AA2D75 /* skex.c in Sources */,
834F7E182C709A1D003AC386 /* ea_schl_standard.c in Sources */, 834F7E182C709A1D003AC386 /* ea_schl_standard.c in Sources */,
836F6FCD18BDC2190095E648 /* ps2_ass.c in Sources */, 836F6FCD18BDC2190095E648 /* ps2_ass.c in Sources */,
83B73C252D8FEC3A00A57F08 /* oor_helpers.c in Sources */,
83CBF5412D4631F300AA2D75 /* i3ds.c in Sources */, 83CBF5412D4631F300AA2D75 /* i3ds.c in Sources */,
8349A90B1FE6258200E26435 /* pcm_kceje.c in Sources */, 8349A90B1FE6258200E26435 /* pcm_kceje.c in Sources */,
836F6F4A18BDC2190095E648 /* interleave.c in Sources */, 836F6F4A18BDC2190095E648 /* interleave.c in Sources */,
@ -3541,12 +3638,15 @@
834D3A6E19F47C98001C54F6 /* g1l.c in Sources */, 834D3A6E19F47C98001C54F6 /* g1l.c in Sources */,
832BF82A21E0514B006F50F1 /* vs_square.c in Sources */, 832BF82A21E0514B006F50F1 /* vs_square.c in Sources */,
8349A9091FE6258200E26435 /* pc_ast.c in Sources */, 8349A9091FE6258200E26435 /* pc_ast.c in Sources */,
83B73C442D8FF15700A57F08 /* mio_erisacontext.c in Sources */,
83B73C452D8FF15700A57F08 /* mio_erisafile.c in Sources */,
83B73C462D8FF15700A57F08 /* mio_erisamatrix.c in Sources */,
83B73C472D8FF15700A57F08 /* mio_erisasound.c in Sources */,
834F7DEF2C7093EA003AC386 /* ptadpcm_decoder.c in Sources */, 834F7DEF2C7093EA003AC386 /* ptadpcm_decoder.c in Sources */,
832BF81F21E0514B006F50F1 /* ps2_va3.c in Sources */, 832BF81F21E0514B006F50F1 /* va3.c in Sources */,
8349A91C1FE6258200E26435 /* mogg.c in Sources */, 8349A91C1FE6258200E26435 /* mogg.c in Sources */,
834FE0F5215C79ED000A5D3D /* wav2.c in Sources */, 834FE0F5215C79ED000A5D3D /* wav2.c in Sources */,
836F703D18BDC2190095E648 /* mus_krome.c in Sources */, 836F703D18BDC2190095E648 /* mus_krome.c in Sources */,
836F700D18BDC2190095E648 /* ps2_wmus.c in Sources */,
831BA61C1EAC61A500CF89B0 /* sndx.c in Sources */, 831BA61C1EAC61A500CF89B0 /* sndx.c in Sources */,
836F6F9618BDC2190095E648 /* lsf.c in Sources */, 836F6F9618BDC2190095E648 /* lsf.c in Sources */,
834F7E7E2C709E76003AC386 /* ongakukan_adp_decoder.c in Sources */, 834F7E7E2C709E76003AC386 /* ongakukan_adp_decoder.c in Sources */,
@ -3585,6 +3685,7 @@
836F702A18BDC2190095E648 /* sd9.c in Sources */, 836F702A18BDC2190095E648 /* sd9.c in Sources */,
836F6FB418BDC2190095E648 /* ngc_nst_dsp.c in Sources */, 836F6FB418BDC2190095E648 /* ngc_nst_dsp.c in Sources */,
834F7DB92C7093EA003AC386 /* derf_decoder.c in Sources */, 834F7DB92C7093EA003AC386 /* derf_decoder.c in Sources */,
83B73C4B2D8FF19800A57F08 /* mio.c in Sources */,
836F6FDB18BDC2190095E648 /* ps2_hsf.c in Sources */, 836F6FDB18BDC2190095E648 /* ps2_hsf.c in Sources */,
836F6FF618BDC2190095E648 /* ster.c in Sources */, 836F6FF618BDC2190095E648 /* ster.c in Sources */,
834F7E0D2C7093EA003AC386 /* xa_decoder.c in Sources */, 834F7E0D2C7093EA003AC386 /* xa_decoder.c in Sources */,
@ -3610,6 +3711,7 @@
834F7D0B2C7085EB003AC386 /* ea_eaac_standard.c in Sources */, 834F7D0B2C7085EB003AC386 /* ea_eaac_standard.c in Sources */,
834FE0FA215C79ED000A5D3D /* nus3bank.c in Sources */, 834FE0FA215C79ED000A5D3D /* nus3bank.c in Sources */,
8306B0B220984552000302D4 /* blocked_mxch.c in Sources */, 8306B0B220984552000302D4 /* blocked_mxch.c in Sources */,
83B73C492D8FF17900A57F08 /* mio_decoder.c in Sources */,
834F7DBC2C7093EA003AC386 /* ea_mt_decoder.c in Sources */, 834F7DBC2C7093EA003AC386 /* ea_mt_decoder.c in Sources */,
837CEAFA23487F2C00E62A4A /* xa_04sw.c in Sources */, 837CEAFA23487F2C00E62A4A /* xa_04sw.c in Sources */,
836F6F8618BDC2190095E648 /* excitebots.c in Sources */, 836F6F8618BDC2190095E648 /* excitebots.c in Sources */,
@ -3633,6 +3735,7 @@
831BA6211EAC61A500CF89B0 /* pasx.c in Sources */, 831BA6211EAC61A500CF89B0 /* pasx.c in Sources */,
832BF82621E0514B006F50F1 /* nwav.c in Sources */, 832BF82621E0514B006F50F1 /* nwav.c in Sources */,
8349A8E81FE6253900E26435 /* blocked_dec.c in Sources */, 8349A8E81FE6253900E26435 /* blocked_dec.c in Sources */,
83B73C552D8FF1E300A57F08 /* vorbis_codebooks.c in Sources */,
834F7EDA2C70A786003AC386 /* seek.c in Sources */, 834F7EDA2C70A786003AC386 /* seek.c in Sources */,
834F7DBF2C7093EA003AC386 /* fadpcm_decoder.c in Sources */, 834F7DBF2C7093EA003AC386 /* fadpcm_decoder.c in Sources */,
834F7DCC2C7093EA003AC386 /* g7221_decoder.c in Sources */, 834F7DCC2C7093EA003AC386 /* g7221_decoder.c in Sources */,
@ -3644,6 +3747,7 @@
8306B0B620984552000302D4 /* blocked_hwas.c in Sources */, 8306B0B620984552000302D4 /* blocked_hwas.c in Sources */,
836F6FC218BDC2190095E648 /* pc_mxst.c in Sources */, 836F6FC218BDC2190095E648 /* pc_mxst.c in Sources */,
8375737621F950ED00F01AF5 /* gin.c in Sources */, 8375737621F950ED00F01AF5 /* gin.c in Sources */,
83B73C572D8FF27000A57F08 /* 2dx.c in Sources */,
836F6FC918BDC2190095E648 /* 2pfs.c in Sources */, 836F6FC918BDC2190095E648 /* 2pfs.c in Sources */,
83AFABBC23795202002F3947 /* xssb.c in Sources */, 83AFABBC23795202002F3947 /* xssb.c in Sources */,
836F704818BDC2190095E648 /* xbox_ims.c in Sources */, 836F704818BDC2190095E648 /* xbox_ims.c in Sources */,
@ -3651,7 +3755,7 @@
836F6F7518BDC2190095E648 /* bnsf.c in Sources */, 836F6F7518BDC2190095E648 /* bnsf.c in Sources */,
836F704318BDC2190095E648 /* wpd.c in Sources */, 836F704318BDC2190095E648 /* wpd.c in Sources */,
8349A9081FE6258200E26435 /* ezw.c in Sources */, 8349A9081FE6258200E26435 /* ezw.c in Sources */,
836F6FD918BDC2190095E648 /* ps2_gcm.c in Sources */, 836F6FD918BDC2190095E648 /* mcg.c in Sources */,
83A21F88201D8981000F04B9 /* ogg_vorbis.c in Sources */, 83A21F88201D8981000F04B9 /* ogg_vorbis.c in Sources */,
837CEAF923487F2C00E62A4A /* xavs.c in Sources */, 837CEAF923487F2C00E62A4A /* xavs.c in Sources */,
836F6F8E18BDC2190095E648 /* halpst.c in Sources */, 836F6F8E18BDC2190095E648 /* halpst.c in Sources */,

View file

@ -1,13 +1,23 @@
#include "api_internal.h" #include "api_internal.h"
#include "mixing.h" #include "mixing.h"
#define INTERNAL_BUF_SAMPLES 1024
LIBVGMSTREAM_API uint32_t libvgmstream_get_version(void) { LIBVGMSTREAM_API uint32_t libvgmstream_get_version(void) {
return (LIBVGMSTREAM_API_VERSION_MAJOR << 24) | (LIBVGMSTREAM_API_VERSION_MINOR << 16) | (LIBVGMSTREAM_API_VERSION_PATCH << 0); return (LIBVGMSTREAM_API_VERSION_MAJOR << 24) | (LIBVGMSTREAM_API_VERSION_MINOR << 16) | (LIBVGMSTREAM_API_VERSION_PATCH << 0);
} }
LIBVGMSTREAM_API libvgmstream_t* libvgmstream_create(libstreamfile_t* libsf, int subsong, libvgmstream_config_t* vcfg) {
libvgmstream_t* vgmstream = libvgmstream_init();
libvgmstream_setup(vgmstream, vcfg);
int err = libvgmstream_open_stream(vgmstream, libsf, subsong);
if (err < 0) {
libvgmstream_free(vgmstream);
return NULL;
}
return vgmstream;
}
LIBVGMSTREAM_API libvgmstream_t* libvgmstream_init(void) { LIBVGMSTREAM_API libvgmstream_t* libvgmstream_init(void) {
libvgmstream_t* lib = NULL; libvgmstream_t* lib = NULL;
@ -48,57 +58,79 @@ LIBVGMSTREAM_API void libvgmstream_free(libvgmstream_t* lib) {
free(lib); free(lib);
} }
// TODO: allow calling after load
LIBVGMSTREAM_API void libvgmstream_setup(libvgmstream_t* lib, libvgmstream_config_t* cfg) { LIBVGMSTREAM_API void libvgmstream_setup(libvgmstream_t* lib, libvgmstream_config_t* cfg) {
if (!lib || !lib->priv) if (!lib || !lib->priv)
return; return;
libvgmstream_priv_t* priv = lib->priv; libvgmstream_priv_t* priv = lib->priv;
// Can only apply once b/c some options modify the internal mixing chain and there is no clean way to
// reset the stream when txtp also manipulates it (maybe could add some flag per mixing item)
if (priv->setup_done)
return;
// allow overwritting current config, though will only apply to next load
//if (priv->config_loaded)
// return;
if (!cfg) { if (!cfg) {
memset(&priv->cfg , 0, sizeof(libvgmstream_config_t)); memset(&priv->cfg , 0, sizeof(libvgmstream_config_t));
priv->cfg.loop_count = 1; //TODO: loop 0 means no loop (improve detection) priv->config_loaded = false;
} }
else { else {
priv->cfg = *cfg; priv->cfg = *cfg;
priv->config_loaded = true;
} }
//TODO validate, etc //TODO validate, etc (for now most incorrect values are ignored)
// apply now if possible to update format info
if (priv->vgmstream) {
api_apply_config(priv);
}
} }
void libvgmstream_priv_reset(libvgmstream_priv_t* priv, bool reset_buf) { void libvgmstream_priv_reset(libvgmstream_priv_t* priv, bool full) {
//memset(&priv->cfg, 0, sizeof(libvgmstream_config_t)); //config is always valid //memset(&priv->cfg, 0, sizeof(libvgmstream_config_t)); //config is always valid
memset(&priv->fmt, 0, sizeof(libvgmstream_format_t));
memset(&priv->dec, 0, sizeof(libvgmstream_decoder_t));
//memset(&priv->pos, 0, sizeof(libvgmstream_priv_position_t)); //position info is updated on open //memset(&priv->pos, 0, sizeof(libvgmstream_priv_position_t)); //position info is updated on open
memset(&priv->dec, 0, sizeof(libvgmstream_decoder_t));
if (reset_buf) { if (full) {
free(priv->buf.data); free(priv->buf.data); //TODO
memset(&priv->buf, 0, sizeof(libvgmstream_priv_buf_t)); memset(&priv->buf, 0, sizeof(libvgmstream_priv_buf_t));
memset(&priv->fmt, 0, sizeof(libvgmstream_format_t));
}
else {
priv->buf.consumed = priv->buf.samples;
} }
priv->pos.current = 0; priv->pos.current = 0;
priv->decode_done = false; priv->decode_done = false;
} }
libvgmstream_sample_t api_get_output_sample_type(libvgmstream_priv_t* priv) { libvgmstream_sfmt_t api_get_output_sample_type(libvgmstream_priv_t* priv) {
VGMSTREAM* v = priv->vgmstream; VGMSTREAM* v = priv->vgmstream;
sfmt_t format = mixing_get_output_sample_type(v); sfmt_t format = mixing_get_output_sample_type(v);
switch(format) { switch(format) {
case SFMT_S16: return LIBVGMSTREAM_SAMPLE_PCM16; case SFMT_S16: return LIBVGMSTREAM_SFMT_PCM16;
case SFMT_FLT: return LIBVGMSTREAM_SAMPLE_FLOAT; case SFMT_FLT: return LIBVGMSTREAM_SFMT_FLOAT;
case SFMT_F32: return LIBVGMSTREAM_SFMT_FLOAT; //shouldn't happen?
default: default:
return 0x00; //??? return 0x00; //???
} }
} }
int api_get_sample_size(libvgmstream_sample_t sample_type) { int api_get_sample_size(libvgmstream_sfmt_t sample_format) {
switch(sample_type) { switch(sample_format) {
case LIBVGMSTREAM_SAMPLE_PCM24: //case LIBVGMSTREAM_SFMT_PCM24:
case LIBVGMSTREAM_SAMPLE_PCM32: //case LIBVGMSTREAM_SFMT_PCM32:
case LIBVGMSTREAM_SAMPLE_FLOAT: case LIBVGMSTREAM_SFMT_FLOAT:
return 0x04; return 0x04;
case LIBVGMSTREAM_SAMPLE_PCM16: case LIBVGMSTREAM_SFMT_PCM16:
default: default:
return 0x02; return 0x02;
} }

View file

@ -3,18 +3,6 @@
#include "mixing.h" #include "mixing.h"
static void load_vgmstream(libvgmstream_priv_t* priv, libvgmstream_options_t* opt) {
STREAMFILE* sf_api = open_api_streamfile(opt->libsf);
if (!sf_api)
return;
//TODO: handle internal format_id
sf_api->stream_index = opt->subsong_index;
priv->vgmstream = init_vgmstream_from_STREAMFILE(sf_api);
close_streamfile(sf_api);
}
static void apply_config(libvgmstream_priv_t* priv) { static void apply_config(libvgmstream_priv_t* priv) {
libvgmstream_config_t* cfg = &priv->cfg; libvgmstream_config_t* cfg = &priv->cfg;
@ -36,23 +24,50 @@ static void apply_config(libvgmstream_priv_t* priv) {
if (!vcfg.allow_play_forever) if (!vcfg.allow_play_forever)
vcfg.play_forever = 0; vcfg.play_forever = 0;
// Traditionally in CLI loop_count = 0 removes loops but this is pretty odd for a lib
// (calling _setup with nothing set would remove most audio).
// For now loop_count 0 is set to 1, and loop_count <0 is assumed to be same 0
if (vcfg.loop_count == 0) {
vcfg.loop_count = 1;
} else if (vcfg.loop_count < 0)
vcfg.loop_count = 0;
vgmstream_apply_config(priv->vgmstream, &vcfg); vgmstream_apply_config(priv->vgmstream, &vcfg);
} }
static void prepare_mixing(libvgmstream_priv_t* priv, libvgmstream_options_t* opt) { static void prepare_mixing(libvgmstream_priv_t* priv) {
libvgmstream_config_t* cfg = &priv->cfg;
/* enable after config but before outbuf */ /* enable after config but before outbuf */
if (priv->cfg.auto_downmix_channels) { if (cfg->auto_downmix_channels) {
vgmstream_mixing_autodownmix(priv->vgmstream, priv->cfg.auto_downmix_channels); vgmstream_mixing_autodownmix(priv->vgmstream, cfg->auto_downmix_channels);
} }
else if (opt && opt->stereo_track >= 1) { else if (cfg->stereo_track >= 1) {
vgmstream_mixing_stereo_only(priv->vgmstream, opt->stereo_track - 1); vgmstream_mixing_stereo_only(priv->vgmstream, cfg->stereo_track - 1);
} }
if (priv->cfg.force_pcm16) { if (cfg->force_sfmt) {
mixing_macro_output_sample_format(priv->vgmstream, SFMT_S16); // external force
sfmt_t force_sfmt = SFMT_NONE;
switch(cfg->force_sfmt) {
case LIBVGMSTREAM_SFMT_PCM16: force_sfmt = SFMT_S16; break;
case LIBVGMSTREAM_SFMT_FLOAT: force_sfmt = SFMT_FLT; break;
default: break;
} }
else if (priv->cfg.force_float) {
mixing_macro_output_sample_format(priv->vgmstream, SFMT_FLT); mixing_macro_output_sample_format(priv->vgmstream, force_sfmt);
}
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;
default: break;
}
mixing_macro_output_sample_format(priv->vgmstream, force_sfmt);
} }
vgmstream_mixing_enable(priv->vgmstream, INTERNAL_BUF_SAMPLES, NULL /*&input_channels*/, NULL /*&output_channels*/); vgmstream_mixing_enable(priv->vgmstream, INTERNAL_BUF_SAMPLES, NULL /*&input_channels*/, NULL /*&output_channels*/);
@ -76,11 +91,11 @@ static void update_format_info(libvgmstream_priv_t* priv) {
fmt->channels = v->channels; fmt->channels = v->channels;
fmt->input_channels = 0; fmt->input_channels = 0;
vgmstream_mixing_enable(v, 0, &fmt->input_channels, &fmt->channels); vgmstream_mixing_enable(v, 0, &fmt->input_channels, &fmt->channels); //query
fmt->channel_layout = v->channel_layout; fmt->channel_layout = v->channel_layout;
fmt->sample_type = api_get_output_sample_type(priv); fmt->sample_format = api_get_output_sample_type(priv);
fmt->sample_size = api_get_sample_size(fmt->sample_type); fmt->sample_size = api_get_sample_size(fmt->sample_format);
fmt->sample_rate = v->sample_rate; fmt->sample_rate = v->sample_rate;
@ -105,26 +120,58 @@ static void update_format_info(libvgmstream_priv_t* priv) {
} }
} }
LIBVGMSTREAM_API int libvgmstream_open_stream(libvgmstream_t* lib, libvgmstream_options_t* opt) { // apply config if data + config is loaded and not already loaded
if (!lib ||!lib->priv) void api_apply_config(libvgmstream_priv_t* priv) {
return LIBVGMSTREAM_ERROR_GENERIC; if (priv->setup_done)
if (!opt || !opt->libsf || opt->subsong_index < 0) return;
if (!priv->vgmstream)
return;
apply_config(priv);
prepare_mixing(priv);
update_position(priv);
update_format_info(priv);
priv->setup_done = true;
}
static void load_vgmstream(libvgmstream_priv_t* priv, libstreamfile_t* libsf, int subsong_index) {
STREAMFILE* sf_api = open_api_streamfile(libsf);
if (!sf_api)
return;
//TODO: handle format_id
sf_api->stream_index = subsong_index;
priv->vgmstream = init_vgmstream_from_STREAMFILE(sf_api);
close_streamfile(sf_api);
}
LIBVGMSTREAM_API int libvgmstream_open_stream(libvgmstream_t* lib, libstreamfile_t* libsf, int subsong_index) {
if (!lib ||!lib->priv || !libsf)
return LIBVGMSTREAM_ERROR_GENERIC; return LIBVGMSTREAM_ERROR_GENERIC;
// close loaded song if any + reset // close loaded song if any + reset
libvgmstream_close_stream(lib); libvgmstream_close_stream(lib);
libvgmstream_priv_t* priv = lib->priv; libvgmstream_priv_t* priv = lib->priv;
if (subsong_index < 0)
return LIBVGMSTREAM_ERROR_GENERIC;
load_vgmstream(priv, opt); load_vgmstream(priv, libsf, subsong_index);
if (!priv->vgmstream) if (!priv->vgmstream)
return LIBVGMSTREAM_ERROR_GENERIC; return LIBVGMSTREAM_ERROR_GENERIC;
apply_config(priv);
prepare_mixing(priv, opt); // apply now if possible to update format info
if (priv->config_loaded) {
api_apply_config(priv);
}
else {
// no config: just update info (apply_config will be called later)
update_position(priv); update_position(priv);
update_format_info(priv); update_format_info(priv);
}
return LIBVGMSTREAM_OK; return LIBVGMSTREAM_OK;
} }
@ -138,6 +185,8 @@ LIBVGMSTREAM_API void libvgmstream_close_stream(libvgmstream_t* lib) {
close_vgmstream(priv->vgmstream); close_vgmstream(priv->vgmstream);
priv->vgmstream = NULL; priv->vgmstream = NULL;
priv->setup_done = false;
//priv->config_loaded = false; // loaded config still applies (_close is also called on _open)
libvgmstream_priv_reset(priv, true); libvgmstream_priv_reset(priv, true);
} }

View file

@ -1,6 +1,7 @@
#include "api_internal.h" #include "api_internal.h"
#include "mixing.h" #include "mixing.h"
#include "render.h" #include "render.h"
#include "../util/log.h"
static bool reset_buf(libvgmstream_priv_t* priv) { static bool reset_buf(libvgmstream_priv_t* priv) {
@ -46,15 +47,16 @@ static void update_buf(libvgmstream_priv_t* priv, int samples_done) {
priv->buf.bytes = samples_done * priv->buf.sample_size * priv->buf.channels; priv->buf.bytes = samples_done * priv->buf.sample_size * priv->buf.channels;
//priv->buf.consumed = 0; //external //priv->buf.consumed = 0; //external
// mark done if this buf reached EOF
if (!priv->pos.play_forever) { if (!priv->pos.play_forever) {
priv->decode_done = (priv->pos.current >= priv->pos.play_samples);
priv->pos.current += samples_done; priv->pos.current += samples_done;
priv->decode_done = (priv->pos.current >= priv->pos.play_samples);
} }
} }
// update decoder info based on last render, though at the moment it's all fixed // update decoder info based on last render, though at the moment it's all fixed
static void update_decoder_info(libvgmstream_priv_t* priv, int samples_done) { static void update_decoder_info(libvgmstream_priv_t* priv) {
// output copy // output copy
priv->dec.buf = priv->buf.data; priv->dec.buf = priv->buf.data;
@ -68,6 +70,13 @@ LIBVGMSTREAM_API int libvgmstream_render(libvgmstream_t* lib) {
return LIBVGMSTREAM_ERROR_GENERIC; return LIBVGMSTREAM_ERROR_GENERIC;
libvgmstream_priv_t* priv = lib->priv; libvgmstream_priv_t* priv = lib->priv;
// setup if not called (mainly to make sure mixing is enabled) //TODO: handle internally
// (for cases where _open_stream is called but not _setup)
if (!priv->setup_done) {
api_apply_config(priv);
}
if (priv->decode_done) if (priv->decode_done)
return LIBVGMSTREAM_ERROR_GENERIC; return LIBVGMSTREAM_ERROR_GENERIC;
@ -84,7 +93,7 @@ LIBVGMSTREAM_API int libvgmstream_render(libvgmstream_t* lib) {
int decoded = render_main(&ssrc, priv->vgmstream); int decoded = render_main(&ssrc, priv->vgmstream);
update_buf(priv, decoded); update_buf(priv, decoded);
update_decoder_info(priv, decoded); update_decoder_info(priv);
return LIBVGMSTREAM_OK; return LIBVGMSTREAM_OK;
} }
@ -161,6 +170,10 @@ LIBVGMSTREAM_API void libvgmstream_seek(libvgmstream_t* lib, int64_t sample) {
seek_vgmstream(priv->vgmstream, sample); seek_vgmstream(priv->vgmstream, sample);
priv->pos.current = priv->vgmstream->pstate.play_position; priv->pos.current = priv->vgmstream->pstate.play_position;
// update flags just in case
update_buf(priv, 0);
update_decoder_info(priv);
} }

View file

@ -12,28 +12,33 @@ static int get_internal_log_level(libvgmstream_loglevel_t level) {
} }
} }
LIBVGMSTREAM_API void libvgmstream_set_log(libvgmstream_log_t* cfg) { LIBVGMSTREAM_API void libvgmstream_set_log(libvgmstream_loglevel_t level, void (*callback)(int level, const char* str)) {
if (!cfg) int ilevel = get_internal_log_level(level);
return; if (callback) {
vgm_log_set_callback(NULL, ilevel, 0, callback);
int ilevel = get_internal_log_level(cfg->level);
if (cfg->stdout_callback) {
//vgmstream_set_log_stdout(ilevel);
vgm_log_set_callback(NULL, ilevel, 1, NULL);
} }
else { else {
//vgmstream_set_log_callback(ilevel, cfg->callback); vgm_log_set_callback(NULL, ilevel, 1, NULL);
vgm_log_set_callback(NULL, ilevel, 0, cfg->callback);
} }
} }
LIBVGMSTREAM_API const char** libvgmstream_get_extensions(size_t* size) { LIBVGMSTREAM_API const char** libvgmstream_get_extensions(int* size) {
return vgmstream_get_formats(size); if (!size)
return NULL;
size_t tmp = 0;
const char** list = vgmstream_get_formats(&tmp);
*size = tmp;
return list;
} }
LIBVGMSTREAM_API const char** libvgmstream_get_common_extensions(size_t* size) { LIBVGMSTREAM_API const char** libvgmstream_get_common_extensions(int* size) {
return vgmstream_get_common_formats(size); if (!size)
return NULL;
size_t tmp = 0;
const char** list = vgmstream_get_common_formats(&tmp);
*size = tmp;
return list;
} }

View file

@ -33,31 +33,36 @@ typedef struct {
} libvgmstream_priv_buf_t; } libvgmstream_priv_buf_t;
// used to calculate and stop stream (to be removed once VGMSTREAM can stop on its own)
typedef struct { typedef struct {
int64_t play_forever; int64_t play_forever;
int64_t play_samples; int64_t play_samples;
int64_t current; int64_t current;
} libvgmstream_priv_position_t; } libvgmstream_priv_position_t;
/* vgmstream context/handle */ // vgmstream context/handle
typedef struct { typedef struct {
libvgmstream_format_t fmt; // externally exposed // externally exposed to API
libvgmstream_decoder_t dec; // externally exposed libvgmstream_format_t fmt;
libvgmstream_decoder_t dec;
libvgmstream_config_t cfg; // internal copy // internals
libvgmstream_config_t cfg;
VGMSTREAM* vgmstream; VGMSTREAM* vgmstream;
libvgmstream_priv_buf_t buf; libvgmstream_priv_buf_t buf;
libvgmstream_priv_position_t pos; libvgmstream_priv_position_t pos;
bool config_loaded;
bool setup_done;
bool decode_done; bool decode_done;
} libvgmstream_priv_t; } libvgmstream_priv_t;
void libvgmstream_priv_reset(libvgmstream_priv_t* priv, bool reset_buf); void libvgmstream_priv_reset(libvgmstream_priv_t* priv, bool full);
libvgmstream_sample_t api_get_output_sample_type(libvgmstream_priv_t* priv); libvgmstream_sfmt_t api_get_output_sample_type(libvgmstream_priv_t* priv);
int api_get_sample_size(libvgmstream_sample_t sample_type); int api_get_sample_size(libvgmstream_sfmt_t sample_format);
void api_apply_config(libvgmstream_priv_t* priv);
STREAMFILE* open_api_streamfile(libstreamfile_t* libsf); STREAMFILE* open_api_streamfile(libstreamfile_t* libsf);

View file

@ -5,63 +5,23 @@ static libstreamfile_t* libstreamfile_from_streamfile(STREAMFILE* sf);
/* libstreamfile_t for external use, as a default implementation calling some internal SF */ /* libstreamfile_t for external use, as a default implementation calling some internal SF */
typedef struct { typedef struct {
int64_t offset;
int64_t size; int64_t size;
STREAMFILE* sf; STREAMFILE* sf;
char name[PATH_LIMIT]; char name[PATH_LIMIT];
} libsf_priv_t; } libsf_priv_t;
static int libsf_read(void* user_data, uint8_t* dst, int dst_size) { static int libsf_read(void* user_data, uint8_t* dst, int64_t offset, int length) {
libsf_priv_t* priv = user_data; libsf_priv_t* priv = user_data;
if (!priv || !dst) return priv->sf->read(priv->sf, dst, offset, length);
return 0;
int bytes = priv->sf->read(priv->sf, dst, priv->offset, dst_size);
priv->offset += bytes;
return bytes;
}
static int64_t libsf_seek(void* user_data, int64_t offset, int whence) {
libsf_priv_t* priv = user_data;
if (!priv)
return -1;
switch (whence) {
case LIBSTREAMFILE_SEEK_SET: /* absolute */
break;
case LIBSTREAMFILE_SEEK_CUR: /* relative to current */
offset += priv->offset;
break;
case LIBSTREAMFILE_SEEK_END: /* relative to file end (should be negative) */
offset += priv->size;
break;
default:
break;
}
/* clamp offset like fseek */
if (offset > priv->size)
offset = priv->size;
else if (offset < 0)
offset = 0;
/* main seek */
priv->offset = offset;
return 0;
} }
static int64_t libsf_get_size(void* user_data) { static int64_t libsf_get_size(void* user_data) {
libsf_priv_t* priv = user_data; libsf_priv_t* priv = user_data;
if (!priv) return priv->sf->get_size(priv->sf);
return 0;
return priv->size;
} }
static const char* libsf_get_name(void* user_data) { static const char* libsf_get_name(void* user_data) {
libsf_priv_t* priv = user_data; libsf_priv_t* priv = user_data;
if (!priv)
return NULL;
if (priv->name[0] == '\0') { if (priv->name[0] == '\0') {
priv->sf->get_name(priv->sf, priv->name, sizeof(priv->name)); priv->sf->get_name(priv->sf, priv->name, sizeof(priv->name));
@ -72,7 +32,8 @@ static const char* libsf_get_name(void* user_data) {
static libstreamfile_t* libsf_open(void* user_data, const char* filename) { static libstreamfile_t* libsf_open(void* user_data, const char* filename) {
libsf_priv_t* priv = user_data; libsf_priv_t* priv = user_data;
if (!priv || !priv->sf || !filename)
if (!filename)
return NULL; return NULL;
STREAMFILE* sf = priv->sf->open(priv->sf, filename, 0); STREAMFILE* sf = priv->sf->open(priv->sf, filename, 0);
@ -104,14 +65,11 @@ static libstreamfile_t* libstreamfile_from_streamfile(STREAMFILE* sf) {
if (!sf) if (!sf)
return NULL; return NULL;
libstreamfile_t* libsf = NULL;
libsf_priv_t* priv = NULL; libsf_priv_t* priv = NULL;
libstreamfile_t* libsf = calloc(1, sizeof(libstreamfile_t));
libsf = calloc(1, sizeof(libstreamfile_t));
if (!libsf) goto fail; if (!libsf) goto fail;
libsf->read = libsf_read; libsf->read = libsf_read;
libsf->seek = libsf_seek;
libsf->get_size = libsf_get_size; libsf->get_size = libsf_get_size;
libsf->get_name = libsf_get_name; libsf->get_name = libsf_get_name;
libsf->open = libsf_open; libsf->open = libsf_open;

View file

@ -18,10 +18,10 @@ typedef struct {
char name[PATH_LIMIT]; char name[PATH_LIMIT];
} cache_priv_t; } cache_priv_t;
static int cache_read(void* user_data, uint8_t* dst, int dst_size) { static int cache_read(void* user_data, uint8_t* dst, int64_t offset, int length) {
cache_priv_t* priv = user_data; cache_priv_t* priv = user_data;
size_t read_total = 0; size_t read_total = 0;
if (!dst || dst_size <= 0) if (!dst || length <= 0 || offset < 0)
return 0; return 0;
/* is the part of the requested length in the buffer? */ /* is the part of the requested length in the buffer? */
@ -30,19 +30,22 @@ static int cache_read(void* user_data, uint8_t* dst, int dst_size) {
int buf_into = (int)(priv->offset - priv->buf_offset); int buf_into = (int)(priv->offset - priv->buf_offset);
buf_limit = priv->valid_size - buf_into; buf_limit = priv->valid_size - buf_into;
if (buf_limit > dst_size) if (buf_limit > length)
buf_limit = dst_size; buf_limit = length;
memcpy(dst, priv->buf + buf_into, buf_limit); memcpy(dst, priv->buf + buf_into, buf_limit);
read_total += buf_limit; read_total += buf_limit;
dst_size -= buf_limit; length -= buf_limit;
priv->offset += buf_limit; priv->offset += buf_limit;
dst += buf_limit; dst += buf_limit;
} }
/* possible if all data was copied to buf and FD closed */
if (!priv->libsf)
return read_total;
/* read the rest of the requested length */ /* read the rest of the requested length */
while (dst_size > 0) { while (length > 0) {
size_t buf_limit; size_t buf_limit;
/* ignore requests at EOF */ /* ignore requests at EOF */
@ -52,18 +55,15 @@ static int cache_read(void* user_data, uint8_t* dst, int dst_size) {
break; break;
} }
/* position to new offset */
priv->libsf->seek(priv, priv->offset, 0);
/* fill the buffer (offset now is beyond buf_offset) */ /* fill the buffer (offset now is beyond buf_offset) */
priv->buf_offset = priv->offset; priv->buf_offset = priv->offset;
priv->valid_size = priv->libsf->read(priv, priv->buf, priv->buf_size); priv->valid_size = priv->libsf->read(priv, priv->buf, priv->buf_offset, priv->buf_size);
/* decide how much must be read this time */ /* decide how much must be read this time */
if (dst_size > priv->buf_size) if (length > priv->buf_size)
buf_limit = priv->buf_size; buf_limit = priv->buf_size;
else else
buf_limit = dst_size; buf_limit = length;
/* give up on partial reads (EOF) */ /* give up on partial reads (EOF) */
if (priv->valid_size < buf_limit) { if (priv->valid_size < buf_limit) {
@ -77,40 +77,14 @@ static int cache_read(void* user_data, uint8_t* dst, int dst_size) {
memcpy(dst, priv->buf, buf_limit); memcpy(dst, priv->buf, buf_limit);
priv->offset += buf_limit; priv->offset += buf_limit;
read_total += buf_limit; read_total += buf_limit;
dst_size -= buf_limit; length -= buf_limit;
dst += buf_limit; dst += buf_limit;
} }
priv->offset = offset; /* last fread offset */
return read_total; return read_total;
} }
static int64_t cache_seek(void* user_data, int64_t offset, int whence) {
cache_priv_t* priv = user_data;
switch (whence) {
case LIBSTREAMFILE_SEEK_SET: /* absolute */
break;
case LIBSTREAMFILE_SEEK_CUR: /* relative to current */
offset += priv->offset;
break;
case LIBSTREAMFILE_SEEK_END: /* relative to file end (should be negative) */
offset += priv->file_size;
break;
default:
break;
}
/* clamp offset like fseek */
if (offset > priv->file_size)
offset = priv->file_size;
else if (offset < 0)
offset = 0;
/* main seek */
priv->offset = offset;
return 0;
}
static int64_t cache_get_size(void* user_data) { static int64_t cache_get_size(void* user_data) {
cache_priv_t* priv = user_data; cache_priv_t* priv = user_data;
return priv->file_size; return priv->file_size;
@ -168,7 +142,6 @@ LIBVGMSTREAM_API libstreamfile_t* libstreamfile_open_buffered(libstreamfile_t* e
if (!libsf) goto fail; if (!libsf) goto fail;
libsf->read = cache_read; libsf->read = cache_read;
libsf->seek = cache_seek;
libsf->get_size = cache_get_size; libsf->get_size = cache_get_size;
libsf->get_name = cache_get_name; libsf->get_name = cache_get_name;
libsf->open = cache_open; libsf->open = cache_open;

View file

@ -0,0 +1,43 @@
#include "codec_info.h"
//TODO: move to root folder?
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 vorbis_custom_decoder;
#endif
extern const codec_info_t tac_decoder;
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;
const codec_info_t* codec_get_info(VGMSTREAM* v) {
switch(v->coding_type) {
case coding_CRI_HCA:
return &hca_decoder;
case coding_KA1A:
return &ka1a_decoder;
case coding_UBI_MPEG:
return &ubimpeg_decoder;
#ifdef VGM_USE_VORBIS
case coding_VORBIS_custom:
return &vorbis_custom_decoder;
#endif
case coding_TAC:
return &tac_decoder;
case coding_COMPRESSWAVE:
return &compresswave_decoder;
#ifdef VGM_USE_SPEEX
case coding_SPEEX:
return &speex_decoder;
#endif
case coding_IMUSE:
return &imuse_decoder;
case coding_MIO:
return &mio_decoder;
default:
return NULL;
}
}

View file

@ -0,0 +1,33 @@
#ifndef _CODEC_INFO_H
#define _CODEC_INFO_H
#include <stdint.h>
#include <stdbool.h>
#include "../vgmstream.h"
#include "../base/sbuf.h"
/* Class-like definition for codecs.
*/
typedef struct {
//int (*init)();
sfmt_t sample_type; // fixed for most cases; if not set will be assumed to be PCM16
sfmt_t (*get_sample_type)(VGMSTREAM* v); //variable for codecs with variations depending on data
bool (*decode_frame)(VGMSTREAM* v);
void (*free)(void* codec_data);
void (*reset)(void* codec_data);
void (*seek)(VGMSTREAM* v, int32_t num_sample);
// info for vgmstream
//uint32_t flags;
// alloc size of effect's private data (don't set to manage manually in init/free)
//int priv_size;
//int sample_type;
//int get_sample_type();
} codec_info_t;
const codec_info_t* codec_get_info(VGMSTREAM* v);
#endif

View file

@ -5,6 +5,7 @@
#include "mixing.h" #include "mixing.h"
#include "plugins.h" #include "plugins.h"
#include "sbuf.h" #include "sbuf.h"
#include "codec_info.h"
#include "../util/log.h" #include "../util/log.h"
#include "decode_state.h" #include "decode_state.h"
@ -39,14 +40,16 @@ void decode_free(VGMSTREAM* vgmstream) {
if (!vgmstream->codec_data) if (!vgmstream->codec_data)
return; return;
const codec_info_t* codec_info = codec_get_info(vgmstream);
if (codec_info) {
codec_info->free(vgmstream->codec_data);
return;
}
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
if (vgmstream->coding_type == coding_OGG_VORBIS) { if (vgmstream->coding_type == coding_OGG_VORBIS) {
free_ogg_vorbis(vgmstream->codec_data); free_ogg_vorbis(vgmstream->codec_data);
} }
if (vgmstream->coding_type == coding_VORBIS_custom) {
free_vorbis_custom(vgmstream->codec_data);
}
#endif #endif
if (vgmstream->coding_type == coding_CIRCUS_VQ) { if (vgmstream->coding_type == coding_CIRCUS_VQ) {
@ -57,14 +60,6 @@ void decode_free(VGMSTREAM* vgmstream) {
free_relic(vgmstream->codec_data); free_relic(vgmstream->codec_data);
} }
if (vgmstream->coding_type == coding_CRI_HCA) {
free_hca(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_TAC) {
free_tac(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_ICE_RANGE || if (vgmstream->coding_type == coding_ICE_RANGE ||
vgmstream->coding_type == coding_ICE_DCT) { vgmstream->coding_type == coding_ICE_DCT) {
free_ice(vgmstream->codec_data); free_ice(vgmstream->codec_data);
@ -74,26 +69,14 @@ void decode_free(VGMSTREAM* vgmstream) {
free_ubi_adpcm(vgmstream->codec_data); free_ubi_adpcm(vgmstream->codec_data);
} }
if (vgmstream->coding_type == coding_IMUSE) {
free_imuse(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_ONGAKUKAN_ADPCM) { if (vgmstream->coding_type == coding_ONGAKUKAN_ADPCM) {
free_ongakukan_adp(vgmstream->codec_data); free_ongakukan_adp(vgmstream->codec_data);
} }
if (vgmstream->coding_type == coding_COMPRESSWAVE) {
free_compresswave(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_EA_MT) { if (vgmstream->coding_type == coding_EA_MT) {
free_ea_mt(vgmstream->codec_data, vgmstream->channels); free_ea_mt(vgmstream->codec_data, vgmstream->channels);
} }
if (vgmstream->coding_type == coding_KA1A) {
free_ka1a(vgmstream->codec_data);
}
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
if (vgmstream->coding_type == coding_FFmpeg) { if (vgmstream->coding_type == coding_FFmpeg) {
free_ffmpeg(vgmstream->codec_data); free_ffmpeg(vgmstream->codec_data);
@ -140,12 +123,6 @@ void decode_free(VGMSTREAM* vgmstream) {
} }
#endif #endif
#ifdef VGM_USE_SPEEX
if (vgmstream->coding_type == coding_SPEEX) {
free_speex(vgmstream->codec_data);
}
#endif
if (vgmstream->coding_type == coding_ACM) { if (vgmstream->coding_type == coding_ACM) {
free_acm(vgmstream->codec_data); free_acm(vgmstream->codec_data);
} }
@ -162,6 +139,12 @@ void decode_seek(VGMSTREAM* vgmstream) {
if (!vgmstream->codec_data) if (!vgmstream->codec_data)
return; return;
const codec_info_t* codec_info = codec_get_info(vgmstream);
if (codec_info) {
codec_info->seek(vgmstream, vgmstream->loop_current_sample);
return;
}
if (vgmstream->coding_type == coding_CIRCUS_VQ) { if (vgmstream->coding_type == coding_CIRCUS_VQ) {
seek_circus_vq(vgmstream->codec_data, vgmstream->loop_current_sample); seek_circus_vq(vgmstream->codec_data, vgmstream->loop_current_sample);
} }
@ -170,14 +153,6 @@ void decode_seek(VGMSTREAM* vgmstream) {
seek_relic(vgmstream->codec_data, vgmstream->loop_current_sample); seek_relic(vgmstream->codec_data, vgmstream->loop_current_sample);
} }
if (vgmstream->coding_type == coding_CRI_HCA) {
loop_hca(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_TAC) {
seek_tac(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_ICE_RANGE || if (vgmstream->coding_type == coding_ICE_RANGE ||
vgmstream->coding_type == coding_ICE_DCT) { vgmstream->coding_type == coding_ICE_DCT) {
seek_ice(vgmstream->codec_data, vgmstream->loop_current_sample); seek_ice(vgmstream->codec_data, vgmstream->loop_current_sample);
@ -187,34 +162,18 @@ void decode_seek(VGMSTREAM* vgmstream) {
seek_ubi_adpcm(vgmstream->codec_data, vgmstream->loop_current_sample); seek_ubi_adpcm(vgmstream->codec_data, vgmstream->loop_current_sample);
} }
if (vgmstream->coding_type == coding_IMUSE) {
seek_imuse(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_ONGAKUKAN_ADPCM) { if (vgmstream->coding_type == coding_ONGAKUKAN_ADPCM) {
seek_ongakukan_adp(vgmstream->codec_data, vgmstream->loop_current_sample); seek_ongakukan_adp(vgmstream->codec_data, vgmstream->loop_current_sample);
} }
if (vgmstream->coding_type == coding_COMPRESSWAVE) {
seek_compresswave(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_EA_MT) { if (vgmstream->coding_type == coding_EA_MT) {
seek_ea_mt(vgmstream, vgmstream->loop_current_sample); seek_ea_mt(vgmstream, vgmstream->loop_current_sample);
} }
if (vgmstream->coding_type == coding_KA1A) {
seek_ka1a(vgmstream, vgmstream->loop_current_sample);
}
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
if (vgmstream->coding_type == coding_OGG_VORBIS) { if (vgmstream->coding_type == coding_OGG_VORBIS) {
seek_ogg_vorbis(vgmstream->codec_data, vgmstream->loop_current_sample); seek_ogg_vorbis(vgmstream->codec_data, vgmstream->loop_current_sample);
} }
if (vgmstream->coding_type == coding_VORBIS_custom) {
seek_vorbis_custom(vgmstream, vgmstream->loop_current_sample);
}
#endif #endif
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
@ -241,12 +200,6 @@ void decode_seek(VGMSTREAM* vgmstream) {
} }
#endif #endif
#ifdef VGM_USE_SPEEX
if (vgmstream->coding_type == coding_SPEEX) {
seek_speex(vgmstream, vgmstream->loop_current_sample);
}
#endif
#ifdef VGM_USE_MPEG #ifdef VGM_USE_MPEG
if (vgmstream->coding_type == coding_MPEG_custom || if (vgmstream->coding_type == coding_MPEG_custom ||
vgmstream->coding_type == coding_MPEG_ealayer3 || vgmstream->coding_type == coding_MPEG_ealayer3 ||
@ -269,14 +222,16 @@ void decode_reset(VGMSTREAM* vgmstream) {
if (!vgmstream->codec_data) if (!vgmstream->codec_data)
return; return;
const codec_info_t* codec_info = codec_get_info(vgmstream);
if (codec_info) {
codec_info->reset(vgmstream->codec_data);
return;
}
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
if (vgmstream->coding_type == coding_OGG_VORBIS) { if (vgmstream->coding_type == coding_OGG_VORBIS) {
reset_ogg_vorbis(vgmstream->codec_data); reset_ogg_vorbis(vgmstream->codec_data);
} }
if (vgmstream->coding_type == coding_VORBIS_custom) {
reset_vorbis_custom(vgmstream);
}
#endif #endif
if (vgmstream->coding_type == coding_CIRCUS_VQ) { if (vgmstream->coding_type == coding_CIRCUS_VQ) {
@ -287,14 +242,6 @@ void decode_reset(VGMSTREAM* vgmstream) {
reset_relic(vgmstream->codec_data); reset_relic(vgmstream->codec_data);
} }
if (vgmstream->coding_type == coding_CRI_HCA) {
reset_hca(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_TAC) {
reset_tac(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_ICE_RANGE || if (vgmstream->coding_type == coding_ICE_RANGE ||
vgmstream->coding_type == coding_ICE_DCT) { vgmstream->coding_type == coding_ICE_DCT) {
reset_ice(vgmstream->codec_data); reset_ice(vgmstream->codec_data);
@ -304,26 +251,14 @@ void decode_reset(VGMSTREAM* vgmstream) {
reset_ubi_adpcm(vgmstream->codec_data); reset_ubi_adpcm(vgmstream->codec_data);
} }
if (vgmstream->coding_type == coding_IMUSE) {
reset_imuse(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_ONGAKUKAN_ADPCM) { if (vgmstream->coding_type == coding_ONGAKUKAN_ADPCM) {
reset_ongakukan_adp(vgmstream->codec_data); reset_ongakukan_adp(vgmstream->codec_data);
} }
if (vgmstream->coding_type == coding_COMPRESSWAVE) {
reset_compresswave(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_EA_MT) { if (vgmstream->coding_type == coding_EA_MT) {
reset_ea_mt(vgmstream); reset_ea_mt(vgmstream);
} }
if (vgmstream->coding_type == coding_KA1A) {
reset_ka1a(vgmstream->codec_data);
}
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
if (vgmstream->coding_type == coding_MP4_AAC) { if (vgmstream->coding_type == coding_MP4_AAC) {
reset_mp4_aac(vgmstream); reset_mp4_aac(vgmstream);
@ -364,12 +299,6 @@ void decode_reset(VGMSTREAM* vgmstream) {
} }
#endif #endif
#ifdef VGM_USE_SPEEX
if (vgmstream->coding_type == coding_SPEEX) {
reset_speex(vgmstream->codec_data);
}
#endif
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
if (vgmstream->coding_type == coding_FFmpeg) { if (vgmstream->coding_type == coding_FFmpeg) {
reset_ffmpeg(vgmstream->codec_data); reset_ffmpeg(vgmstream->codec_data);
@ -433,7 +362,6 @@ int decode_get_samples_per_frame(VGMSTREAM* vgmstream) {
return 1; return 1;
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
case coding_OGG_VORBIS: case coding_OGG_VORBIS:
case coding_VORBIS_custom:
#endif #endif
#ifdef VGM_USE_MPEG #ifdef VGM_USE_MPEG
case coding_MPEG_custom: case coding_MPEG_custom:
@ -586,18 +514,12 @@ int decode_get_samples_per_frame(VGMSTREAM* vgmstream) {
return 0; /* varies per frame */ return 0; /* varies per frame */
case coding_ONGAKUKAN_ADPCM: case coding_ONGAKUKAN_ADPCM:
return 0; /* actually 1. */ return 0; /* actually 1. */
case coding_COMPRESSWAVE:
return 0; /* multiple of 2 */
case coding_EA_MT: case coding_EA_MT:
return 0; /* 432, but variable in looped files */ return 0; /* 432, but variable in looped files */
case coding_CIRCUS_VQ: case coding_CIRCUS_VQ:
return 0; return 0;
case coding_RELIC: case coding_RELIC:
return 0; /* 512 */ return 0; /* 512 */
case coding_CRI_HCA:
return 0; /* 1024 - delay/padding (which can be bigger than 1024) */
case coding_TAC:
return 0; /* 1024 - delay/padding */
case coding_ICE_RANGE: case coding_ICE_RANGE:
case coding_ICE_DCT: case coding_ICE_DCT:
return 0; /* ~100 (range), ~16 (DCT) */ return 0; /* ~100 (range), ~16 (DCT) */
@ -612,10 +534,6 @@ int decode_get_samples_per_frame(VGMSTREAM* vgmstream) {
#ifdef VGM_USE_CELT #ifdef VGM_USE_CELT
case coding_CELT_FSB: case coding_CELT_FSB:
return 0; /* 512? */ return 0; /* 512? */
#endif
#ifdef VGM_USE_SPEEX
case coding_SPEEX:
return 0;
#endif #endif
default: default:
return 0; return 0;
@ -807,12 +725,9 @@ int decode_get_frame_size(VGMSTREAM* vgmstream) {
/* UBI_ADPCM: varies per mode? */ /* UBI_ADPCM: varies per mode? */
/* IMUSE: VBR */ /* IMUSE: VBR */
/* EA_MT: VBR, frames of bit counts or PCM frames */ /* EA_MT: VBR, frames of bit counts or PCM frames */
/* COMPRESSWAVE: VBR/huffman bits */
/* ATRAC9: CBR around 0x100-200 */ /* ATRAC9: CBR around 0x100-200 */
/* CELT FSB: varies, usually 0x80-100 */ /* CELT FSB: varies, usually 0x80-100 */
/* SPEEX: varies, usually 0x40-60 */
/* TAC: VBR around ~0x200-300 */ /* TAC: VBR around ~0x200-300 */
/* Vorbis, MPEG, ACM, etc: varies */
default: /* (VBR or managed by decoder) */ default: /* (VBR or managed by decoder) */
return 0; return 0;
} }
@ -875,6 +790,7 @@ static void decode_frames(sbuf_t* sdst, VGMSTREAM* vgmstream) {
decode_state_t* ds = vgmstream->decode_state; decode_state_t* ds = vgmstream->decode_state;
sbuf_t* ssrc = &ds->sbuf; sbuf_t* ssrc = &ds->sbuf;
const codec_info_t* codec_info = codec_get_info(vgmstream);
// fill the external buf by decoding N times; may read partially that buf // fill the external buf by decoding N times; may read partially that buf
while (sdst->filled < sdst->samples) { while (sdst->filled < sdst->samples) {
@ -882,11 +798,11 @@ static void decode_frames(sbuf_t* sdst, VGMSTREAM* vgmstream) {
// decode new frame if prev one was consumed // decode new frame if prev one was consumed
if (ssrc->filled == 0) { if (ssrc->filled == 0) {
bool ok = false; bool ok = false;
switch (vgmstream->coding_type) {
case coding_KA1A: if (codec_info) {
ok = decode_ka1a_frame(vgmstream); ok = codec_info->decode_frame(vgmstream);
break; }
default: else {
goto decode_fail; goto decode_fail;
} }
@ -902,6 +818,9 @@ static void decode_frames(sbuf_t* sdst, VGMSTREAM* vgmstream) {
goto decode_fail; goto decode_fail;
} }
} }
else {
num_empty = 0; //reset for discard loops
}
if (ds->discard) { if (ds->discard) {
// decoder may signal that samples need to be discarded (ex. encoder delay or during loops) // decoder may signal that samples need to be discarded (ex. encoder delay or during loops)
@ -1233,10 +1152,6 @@ void decode_vgmstream(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do) {
case coding_OGG_VORBIS: case coding_OGG_VORBIS:
decode_ogg_vorbis(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels); decode_ogg_vorbis(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels);
break; break;
case coding_VORBIS_custom:
decode_vorbis_custom(vgmstream, buffer, samples_to_do, vgmstream->channels);
break;
#endif #endif
case coding_CIRCUS_VQ: case coding_CIRCUS_VQ:
decode_circus_vq(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels); decode_circus_vq(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels);
@ -1244,12 +1159,6 @@ void decode_vgmstream(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do) {
case coding_RELIC: case coding_RELIC:
decode_relic(&vgmstream->ch[0], vgmstream->codec_data, buffer, samples_to_do); decode_relic(&vgmstream->ch[0], vgmstream->codec_data, buffer, samples_to_do);
break; break;
case coding_CRI_HCA:
decode_hca(vgmstream->codec_data, buffer, samples_to_do);
break;
case coding_TAC:
decode_tac(vgmstream, buffer, samples_to_do);
break;
case coding_ICE_RANGE: case coding_ICE_RANGE:
case coding_ICE_DCT: case coding_ICE_DCT:
decode_ice(vgmstream->codec_data, buffer, samples_to_do); decode_ice(vgmstream->codec_data, buffer, samples_to_do);
@ -1482,11 +1391,6 @@ void decode_vgmstream(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do) {
case coding_CELT_FSB: case coding_CELT_FSB:
decode_celt_fsb(vgmstream, buffer, samples_to_do, vgmstream->channels); decode_celt_fsb(vgmstream, buffer, samples_to_do, vgmstream->channels);
break; break;
#endif
#ifdef VGM_USE_SPEEX
case coding_SPEEX:
decode_speex(vgmstream, buffer, samples_to_do);
break;
#endif #endif
case coding_ACM: case coding_ACM:
decode_acm(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels); decode_acm(vgmstream->codec_data, buffer, samples_to_do, vgmstream->channels);
@ -1656,18 +1560,10 @@ void decode_vgmstream(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do) {
decode_ubi_adpcm(vgmstream, buffer, samples_to_do); decode_ubi_adpcm(vgmstream, buffer, samples_to_do);
break; break;
case coding_IMUSE:
decode_imuse(vgmstream, buffer, samples_to_do);
break;
case coding_ONGAKUKAN_ADPCM: case coding_ONGAKUKAN_ADPCM:
decode_ongakukan_adp(vgmstream, buffer, samples_to_do); decode_ongakukan_adp(vgmstream, buffer, samples_to_do);
break; break;
case coding_COMPRESSWAVE:
decode_compresswave(vgmstream->codec_data, buffer, samples_to_do);
break;
case coding_EA_MT: case coding_EA_MT:
for (ch = 0; ch < vgmstream->channels; ch++) { for (ch = 0; ch < vgmstream->channels; ch++) {
decode_ea_mt(vgmstream, buffer+ch, vgmstream->channels, samples_to_do, ch); decode_ea_mt(vgmstream, buffer+ch, vgmstream->channels, samples_to_do, ch);

View file

@ -330,7 +330,7 @@ static STREAMFILE* get_vgmstream_average_bitrate_channel_streamfile(VGMSTREAM* v
} }
if (vgmstream->coding_type == coding_COMPRESSWAVE) { if (vgmstream->coding_type == coding_COMPRESSWAVE) {
return compresswave_get_streamfile(vgmstream->codec_data); return compresswave_get_streamfile(vgmstream);
} }
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS

View file

@ -116,7 +116,7 @@ void mixer_process(mixer_t* mixer, sbuf_t* sbuf, int32_t current_pos) {
setup_mixbuf(mixer, sbuf); setup_mixbuf(mixer, sbuf);
// apply mixing ops in order. channesl in mixersmix may increase or decrease per op // apply mixing ops in order. channels in mixers may increase or decrease per op (set in sbuf)
// - 2ch w/ "1+2,1u" = ch1+ch2, ch1(add and push rest) = 3ch: ch1' ch1+ch2 ch2 // - 2ch w/ "1+2,1u" = ch1+ch2, ch1(add and push rest) = 3ch: ch1' ch1+ch2 ch2
// - 2ch w/ "1u" = downmix to 1ch (current_channels decreases once) // - 2ch w/ "1u" = downmix to 1ch (current_channels decreases once)
for (int m = 0; m < mixer->chain_count; m++) { for (int m = 0; m < mixer->chain_count; m++) {

View file

@ -125,8 +125,11 @@ void mixer_op_fade(mixer_t* mixer, mix_op_t* mix) {
//TODO optimize for case 0? //TODO optimize for case 0?
for (int s = 0; s < smix->filled; s++) { for (int s = 0; s < smix->filled; s++) {
bool fade_applies = get_fade_gain(mix, &new_gain, current_subpos); bool fade_applies = get_fade_gain(mix, &new_gain, current_subpos);
if (!fade_applies) //TODO optimize? if (!fade_applies) { //TODO optimize?
dst += channels;
current_subpos++;
continue; continue;
}
if (mix->ch_dst < 0) { if (mix->ch_dst < 0) {
for (int ch = 0; ch < channels; ch++) { for (int ch = 0; ch < channels; ch++) {

View file

@ -7,6 +7,7 @@
#include "mixer.h" #include "mixer.h"
#include "mixer_priv.h" #include "mixer_priv.h"
#include "sbuf.h" #include "sbuf.h"
#include "codec_info.h"
/* Wrapper/helpers for vgmstream's "mixer", which does main sample buffer transformations */ /* Wrapper/helpers for vgmstream's "mixer", which does main sample buffer transformations */
@ -143,9 +144,20 @@ void mixing_info(VGMSTREAM* vgmstream, int* p_input_channels, int* p_output_chan
} }
sfmt_t mixing_get_input_sample_type(VGMSTREAM* vgmstream) { sfmt_t mixing_get_input_sample_type(VGMSTREAM* vgmstream) {
const codec_info_t* codec_info = codec_get_info(vgmstream);
if (codec_info) {
if (codec_info->sample_type)
return codec_info->sample_type;
if (codec_info->get_sample_type)
return codec_info->get_sample_type(vgmstream);
}
// TODO: on layered/segments, detect biggest value and use that (ex. if one of the layers uses flt > flt) // TODO: on layered/segments, detect biggest value and use that (ex. if one of the layers uses flt > flt)
switch(vgmstream->coding_type) { switch(vgmstream->coding_type) {
case coding_KA1A: #ifdef VGM_USE_VORBIS
case coding_VORBIS_custom:
#endif
return SFMT_FLT; return SFMT_FLT;
default: default:
return SFMT_S16; return SFMT_S16;

View file

@ -569,7 +569,7 @@ void mixing_macro_downmix(VGMSTREAM* vgmstream, int max /*, mapping_t output_map
void mixing_macro_output_sample_format(VGMSTREAM* vgmstream, sfmt_t type) { void mixing_macro_output_sample_format(VGMSTREAM* vgmstream, sfmt_t type) {
mixer_t* mixer = vgmstream->mixer; mixer_t* mixer = vgmstream->mixer;
if (!mixer) if (!mixer || !type)
return; return;
// optimization (may skip initializing mixer) // optimization (may skip initializing mixer)
@ -577,4 +577,5 @@ void mixing_macro_output_sample_format(VGMSTREAM* vgmstream, sfmt_t type) {
if (input_fmt == type) if (input_fmt == type)
return; return;
mixer->force_type = type; mixer->force_type = type;
mixer->has_non_fade = true;
} }

View file

@ -1,10 +1,16 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
//#include <math.h>
#include "../util.h" #include "../util.h"
#include "sbuf.h" #include "sbuf.h"
#include "../util/log.h" #include "../util/log.h"
// float-to-int modes
//#define PCM16_ROUNDING_LRINT // potentially faster in some systems/compilers and much slower in others
//#define PCM16_ROUNDING_HALF // rounding half + down (vorbis-style), more 'accurate' but slower
#ifdef PCM16_ROUNDING_HALF
#include <math.h>
#endif
void sbuf_init(sbuf_t* sbuf, sfmt_t format, void* buf, int samples, int channels) { void sbuf_init(sbuf_t* sbuf, sfmt_t format, void* buf, int samples, int channels) {
memset(sbuf, 0, sizeof(sbuf_t)); memset(sbuf, 0, sizeof(sbuf_t));
@ -48,6 +54,8 @@ void* sbuf_get_filled_buf(sbuf_t* sbuf) {
} }
void sbuf_consume(sbuf_t* sbuf, int samples) { void sbuf_consume(sbuf_t* sbuf, int samples) {
if (samples == 0) //some discards
return;
int sample_size = sfmt_get_sample_size(sbuf->fmt); int sample_size = sfmt_get_sample_size(sbuf->fmt);
if (sample_size <= 0) //??? if (sample_size <= 0) //???
return; return;
@ -67,7 +75,7 @@ void sbuf_consume(sbuf_t* sbuf, int samples) {
* alts for more accurate rounding could be: * alts for more accurate rounding could be:
* - (int)floor(f) * - (int)floor(f)
* - (int)(f < 0 ? f - 0.5f : f + 0.5f) * - (int)(f < 0 ? f - 0.5f : f + 0.5f)
* - (((int) (f1 + 32768.5)) - 32768) * - (((int) (f1 + 32767.5)) - 32767)
* - etc * - etc
* but since +-1 isn't really audible we'll just cast, as it's the fastest * but since +-1 isn't really audible we'll just cast, as it's the fastest
* *
@ -77,22 +85,22 @@ void sbuf_consume(sbuf_t* sbuf, int samples) {
* It's slightly faster (~5%) but causes fuzzy PCM<>float<>PCM conversions. * It's slightly faster (~5%) but causes fuzzy PCM<>float<>PCM conversions.
*/ */
static inline int float_to_int(float val) { static inline int float_to_int(float val) {
#if 1 #if PCM16_ROUNDING_LRINT
return (int)val; return lrintf(val);
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
return (int)val; return (int)val;
#else #else
return lrintf(val); return (int)val;
#endif #endif
} }
static inline int double_to_int(double val) { static inline int double_to_int(double val) {
#if 1 #if PCM16_ROUNDING_LRINT
return (int)val; return lrint(val);
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
return (int)val; return (int)val;
#else #else
return lrint(val); return (int)val;
#endif #endif
} }
@ -122,7 +130,7 @@ void sbuf_copy_to_f32(float* dst, sbuf_t* sbuf) {
case SFMT_FLT: { case SFMT_FLT: {
float* src = sbuf->buf; float* src = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) { for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = src[s] * 32768.0f; dst[s] = src[s] * 32767.0f;
} }
break; break;
} }
@ -150,7 +158,7 @@ void sbuf_copy_from_f32(sbuf_t* sbuf, float* src) {
case SFMT_FLT: { case SFMT_FLT: {
float* dst = sbuf->buf; float* dst = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) { for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = src[s] / 32768.0f; dst[s] = src[s] / 32767.0f;
} }
break; break;
} }
@ -175,14 +183,26 @@ int sbuf_get_copy_max(sbuf_t* sdst, sbuf_t* ssrc) {
dst[dst_pos++] = src[src_pos++]; \ 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) \ #define sbuf_copy_segments_internal_s16(dst, src, src_pos, dst_pos, src_max, value) \
while (src_pos < src_max) { \ while (src_pos < src_max) { \
dst[dst_pos++] = clamp16(float_to_int(src[src_pos++] * value)); \ 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) \ #define sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, value) \
while (src_pos < src_max) { \ while (src_pos < src_max) { \
dst[dst_pos++] = float_to_int(src[src_pos++] * value); \ dst[dst_pos++] = (src[src_pos++] * value); \
} }
// copy N samples from ssrc into dst (should be clamped externally) // copy N samples from ssrc into dst (should be clamped externally)
@ -191,7 +211,7 @@ void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int samples_copy) {
if (ssrc->channels != sdst->channels) { if (ssrc->channels != sdst->channels) {
// 0'd other channels first (uncommon so probably fine albeit slower-ish) // 0'd other channels first (uncommon so probably fine albeit slower-ish)
sbuf_silence_part(sdst, sdst->filled, samples_copy); sbuf_silence_part(sdst, sdst->filled, samples_copy);
sbuf_copy_layers(sdst, ssrc, 0, ssrc->filled); sbuf_copy_layers(sdst, ssrc, 0, samples_copy);
#if 0 #if 0
// "faster" but lots of extra ifs per sample format, not worth it // "faster" but lots of extra ifs per sample format, not worth it
while (src_pos < src_max) { while (src_pos < src_max) {
@ -210,49 +230,54 @@ void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int samples_copy) {
int src_max = samples_copy * ssrc->channels; int src_max = samples_copy * ssrc->channels;
// define all posible combos, probably there is a better way to handle this but... // define all posible combos, probably there is a better way to handle this but...
// s16 > s16
if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_S16) { if (ssrc->fmt == SFMT_S16 && sdst->fmt == SFMT_S16) {
int16_t* dst = sdst->buf;
int16_t* src = ssrc->buf; int16_t* src = ssrc->buf;
int16_t* dst = sdst->buf;
sbuf_copy_segments_internal(dst, src, src_pos, dst_pos, src_max); sbuf_copy_segments_internal(dst, src, src_pos, dst_pos, src_max);
} }
else if (sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_S16) { // s16 > f32
float* dst = sdst->buf; else if (ssrc->fmt == SFMT_S16 && sdst->fmt == SFMT_F32) {
int16_t* src = ssrc->buf; int16_t* src = ssrc->buf;
float* dst = sdst->buf;
sbuf_copy_segments_internal(dst, src, src_pos, dst_pos, src_max); sbuf_copy_segments_internal(dst, src, src_pos, dst_pos, src_max);
} }
else if ((sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_F32) || (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_FLT)) { // s16 > flt
else if (ssrc->fmt == SFMT_S16 && sdst->fmt == SFMT_FLT) {
int16_t* src = ssrc->buf;
float* dst = sdst->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* src = ssrc->buf;
float* dst = sdst->buf;
sbuf_copy_segments_internal(dst, src, src_pos, dst_pos, src_max); sbuf_copy_segments_internal(dst, src, src_pos, dst_pos, src_max);
} }
// to s16 // f32 > s16
else if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_F32) { else if (ssrc->fmt == SFMT_F32 && sdst->fmt == SFMT_S16) {
float* src = ssrc->buf;
int16_t* dst = sdst->buf; int16_t* dst = sdst->buf;
float* src = ssrc->buf; sbuf_copy_segments_internal_f16(dst, src, src_pos, dst_pos, src_max);
sbuf_copy_segments_internal_s16(dst, src, src_pos, dst_pos, src_max, 1.0f);
} }
else if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_FLT) { // flt > s16
else if (ssrc->fmt == SFMT_FLT && sdst->fmt == SFMT_S16) {
float* src = ssrc->buf;
int16_t* dst = sdst->buf; int16_t* dst = sdst->buf;
float* src = ssrc->buf; sbuf_copy_segments_internal_s16(dst, src, src_pos, dst_pos, src_max, 32767.0f);
sbuf_copy_segments_internal_s16(dst, src, src_pos, dst_pos, src_max, 32768.0f);
} }
// to f32 // f32 > flt
else if (sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_FLT) { else if (ssrc->fmt == SFMT_F32 && sdst->fmt == SFMT_FLT) {
float* dst = sdst->buf;
float* src = ssrc->buf; float* src = ssrc->buf;
sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, 32768.0f);
}
// to flt
else if (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_S16) {
float* dst = sdst->buf; float* dst = sdst->buf;
int16_t* src = ssrc->buf; sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, (1.0f / 32767.0f));
sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, (1/32768.0f));
} }
else if (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_F32) { // flt > f32
float* dst = sdst->buf; else if (ssrc->fmt == SFMT_FLT && sdst->fmt == SFMT_F32) {
float* src = ssrc->buf; float* src = ssrc->buf;
sbuf_copy_segments_internal_flt(dst, src, src_pos, dst_pos, src_max, (1/32768.0f)); 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? //TODO: may want to handle externally?
@ -260,6 +285,14 @@ void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int 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 //TODO fix missing ->channels
/* ugly thing to avoid repeating functions */ /* 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) \ #define sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step) \
@ -270,14 +303,32 @@ void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int samples_copy) {
dst_pos += dst_ch_step; \ dst_pos += dst_ch_step; \
} \ } \
\ \
for (int s = src_filled; s < dst_expected; s++) { \ 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++) { \ for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = 0; \ dst[dst_pos++] = clamp16(float_to_int(src[src_pos++])); \
} \ } \
dst_pos += dst_ch_step; \ 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 +-32768.0 #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) \ #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 s = 0; s < src_filled; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \ for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
@ -286,14 +337,10 @@ void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int samples_copy) {
dst_pos += dst_ch_step; \ dst_pos += dst_ch_step; \
} \ } \
\ \
for (int s = src_filled; s < dst_expected; s++) { \ sbuf_copy_layers_internal_blank(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \ #endif
dst[dst_pos++] = 0; \
} \
dst_pos += dst_ch_step; \
}
// float +-1.0 <> pcm +-32768.0 // 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) \ #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 s = 0; s < src_filled; s++) { \
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \ for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
@ -302,68 +349,72 @@ void sbuf_copy_segments(sbuf_t* sdst, sbuf_t* ssrc, int samples_copy) {
dst_pos += dst_ch_step; \ dst_pos += dst_ch_step; \
} \ } \
\ \
for (int s = src_filled; s < dst_expected; s++) { \ sbuf_copy_layers_internal_blank(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step);
for (int src_ch = 0; src_ch < src_channels; src_ch++) { \
dst[dst_pos++] = 0; \
} \
dst_pos += dst_ch_step; \
}
/* copy interleaving: dst ch1 ch2 ch3 ch4 w/ src ch1 ch2 ch1 ch2 = only fill dst ch1 ch2 */ // 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_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 // 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_expected) { void sbuf_copy_layers(sbuf_t* sdst, sbuf_t* ssrc, int dst_ch_start, int dst_max) {
int src_filled = ssrc->filled; int src_copy = dst_max;
int src_channels = ssrc->channels; int src_channels = ssrc->channels;
int dst_ch_step = (sdst->channels - ssrc->channels); \ int dst_ch_step = (sdst->channels - ssrc->channels);
int src_pos = 0; int src_pos = 0;
int dst_pos = sdst->filled * sdst->channels + dst_ch_start; 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... // define all posible combos, probably there is a better way to handle this but...
// 1:1 // 1:1
if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_S16) { if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_S16) {
int16_t* dst = sdst->buf; int16_t* dst = sdst->buf;
int16_t* src = ssrc->buf; int16_t* src = ssrc->buf;
sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step); 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) { else if (sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_S16) {
float* dst = sdst->buf; float* dst = sdst->buf;
int16_t* src = ssrc->buf; int16_t* src = ssrc->buf;
sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step); 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)) { else if ((sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_F32) || (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_FLT)) {
float* dst = sdst->buf; float* dst = sdst->buf;
float* src = ssrc->buf; float* src = ssrc->buf;
sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step); sbuf_copy_layers_internal(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step);
} }
// to s16 // to s16
else if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_F32) { else if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_F32) {
int16_t* dst = sdst->buf; int16_t* dst = sdst->buf;
float* src = ssrc->buf; float* src = ssrc->buf;
sbuf_copy_layers_internal_s16(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, 1.0f); 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) { else if (sdst->fmt == SFMT_S16 && ssrc->fmt == SFMT_FLT) {
int16_t* dst = sdst->buf; int16_t* dst = sdst->buf;
float* src = ssrc->buf; float* src = ssrc->buf;
sbuf_copy_layers_internal_s16(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, 32768.0f); sbuf_copy_layers_internal_s16(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step, 32767.0f);
} }
// to f32 // to f32
else if (sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_FLT) { else if (sdst->fmt == SFMT_F32 && ssrc->fmt == SFMT_FLT) {
float* dst = sdst->buf; float* dst = sdst->buf;
float* src = ssrc->buf; float* src = ssrc->buf;
sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, 32768.0f); sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step, 32767.0f);
} }
// to flt // to flt
else if (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_S16) { else if (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_S16) {
float* dst = sdst->buf; float* dst = sdst->buf;
int16_t* src = ssrc->buf; int16_t* src = ssrc->buf;
sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, (1/32768.0f)); 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) { else if (sdst->fmt == SFMT_FLT && ssrc->fmt == SFMT_F32) {
float* dst = sdst->buf; float* dst = sdst->buf;
float* src = ssrc->buf; float* src = ssrc->buf;
sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_filled, dst_expected, src_channels, dst_ch_step, (1/32768.0f)); sbuf_copy_layers_internal_flt(dst, src, src_pos, dst_pos, src_copy, dst_max, src_channels, dst_ch_step, (1.0f / 32767.0f));
} }
} }
@ -428,3 +479,29 @@ void sbuf_fadeout(sbuf_t* sbuf, int start, int to_do, int fade_pos, int fade_dur
int count = sbuf->filled - (start + to_do); int count = sbuf->filled - (start + to_do);
sbuf_silence_part(sbuf, start + to_do, count); sbuf_silence_part(sbuf, start + to_do, count);
} }
void sbuf_interleave(sbuf_t* sbuf, float** ibuf) {
if (sbuf->fmt != SFMT_FLT)
return;
// copy multidimensional buf (pcm[0]=[ch0,ch0,...], pcm[1]=[ch1,ch1,...])
// to interleaved buf (buf[0]=ch0, sbuf[1]=ch1, sbuf[2]=ch0, sbuf[3]=ch1, ...)
for (int ch = 0; ch < sbuf->channels; ch++) {
/* channels should be in standard order unlike Ogg Vorbis (at least in FSB) */
float* ptr = sbuf->buf;
float* channel = ibuf[ch];
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 += sbuf->channels;
}
}
}

View file

@ -57,4 +57,6 @@ 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_fadeout(sbuf_t* sbuf, int start, int to_do, int fade_pos, int fade_duration);
void sbuf_interleave(sbuf_t* sbuf, float** ibuf);
#endif #endif

View file

@ -15,8 +15,7 @@ typedef struct {
static size_t api_read(API_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) { static size_t api_read(API_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) {
void* user_data = sf->libsf->user_data; void* user_data = sf->libsf->user_data;
sf->libsf->seek(sf->libsf->user_data, offset, LIBSTREAMFILE_SEEK_SET); return sf->libsf->read(user_data, dst, offset, length);
return sf->libsf->read(user_data, dst, length);
} }
static size_t api_get_size(API_STREAMFILE* sf) { static size_t api_get_size(API_STREAMFILE* sf) {

View file

@ -288,13 +288,8 @@ int32_t ubi_adpcm_get_samples(ubi_adpcm_codec_data* data);
/* imuse_decoder */ /* imuse_decoder */
typedef struct imuse_codec_data imuse_codec_data; void* init_imuse_mcomp(STREAMFILE* sf, int channels);
void* init_imuse_aifc(STREAMFILE* sf, uint32_t start_offset, int channels);
imuse_codec_data* init_imuse(STREAMFILE* sf, int channels);
void decode_imuse(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do);
void reset_imuse(imuse_codec_data* data);
void seek_imuse(imuse_codec_data* data, int32_t num_sample);
void free_imuse(imuse_codec_data* data);
/* ongakukan_adp_decoder */ /* ongakukan_adp_decoder */
typedef struct ongakukan_adp_data ongakukan_adp_data; typedef struct ongakukan_adp_data ongakukan_adp_data;
@ -308,14 +303,8 @@ void free_ongakukan_adp(ongakukan_adp_data* data);
int32_t ongakukan_adp_get_samples(ongakukan_adp_data* data); int32_t ongakukan_adp_get_samples(ongakukan_adp_data* data);
/* compresswave_decoder */ /* compresswave_decoder */
typedef struct compresswave_codec_data compresswave_codec_data; void* init_compresswave(STREAMFILE* sf);
STREAMFILE* compresswave_get_streamfile(VGMSTREAM* v);
compresswave_codec_data* init_compresswave(STREAMFILE* sf);
void decode_compresswave(compresswave_codec_data* data, sample_t* outbuf, int32_t samples_to_do);
void reset_compresswave(compresswave_codec_data* data);
void seek_compresswave(compresswave_codec_data* data, int32_t num_sample);
void free_compresswave(compresswave_codec_data* data);
STREAMFILE* compresswave_get_streamfile(compresswave_codec_data* data);
/* ea_mt_decoder*/ /* ea_mt_decoder*/
@ -346,10 +335,8 @@ int32_t relic_bytes_to_samples(size_t bytes, int channels, int bitrate);
typedef struct hca_codec_data hca_codec_data; typedef struct hca_codec_data hca_codec_data;
hca_codec_data* init_hca(STREAMFILE* sf); hca_codec_data* init_hca(STREAMFILE* sf);
void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do); void free_hca(void* data);
void reset_hca(hca_codec_data* data);
void loop_hca(hca_codec_data* data, int32_t num_sample);
void free_hca(hca_codec_data* data);
clHCA_stInfo* hca_get_info(hca_codec_data* data); clHCA_stInfo* hca_get_info(hca_codec_data* data);
typedef struct { typedef struct {
@ -369,13 +356,7 @@ STREAMFILE* hca_get_streamfile(hca_codec_data* data);
/* tac_decoder */ /* tac_decoder */
typedef struct tac_codec_data tac_codec_data; void* init_tac(STREAMFILE* sf);
tac_codec_data* init_tac(STREAMFILE* sf);
void decode_tac(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do);
void reset_tac(tac_codec_data* data);
void seek_tac(tac_codec_data* data, int32_t num_sample);
void free_tac(tac_codec_data* data);
/* ice_decoder */ /* ice_decoder */
@ -389,13 +370,13 @@ void free_ice(ice_codec_data* data);
/* ka1a_decoder */ /* ka1a_decoder */
typedef struct ka1a_codec_data ka1a_codec_data; void* init_ka1a(int bitrate_mode, int channels_tracks);
ka1a_codec_data* init_ka1a(int bitrate_mode, int channels_tracks); /* ubimpeg_decoder */
void free_ka1a(ka1a_codec_data* data); void* init_ubimpeg(uint32_t mode);
void reset_ka1a(ka1a_codec_data* data);
bool decode_ka1a_frame(VGMSTREAM* vgmstream); /* mio_decoder */
void seek_ka1a(VGMSTREAM* v, int32_t num_sample); void* init_mio(STREAMFILE* sf, int* p_loop_point);
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
@ -438,6 +419,7 @@ typedef enum {
VORBIS_SK, /* Silicon Knights AUD: "OggS" replaced by "SK" */ VORBIS_SK, /* Silicon Knights AUD: "OggS" replaced by "SK" */
VORBIS_VID1, /* Neversoft VID1: custom packet blocks/headers */ VORBIS_VID1, /* Neversoft VID1: custom packet blocks/headers */
VORBIS_AWC, /* Rockstar AWC: custom packet blocks/headers */ VORBIS_AWC, /* Rockstar AWC: custom packet blocks/headers */
VORBIS_OOR, /* Age .OOR: custom bitpacked pages (custom header + setup) */
} vorbis_custom_t; } vorbis_custom_t;
/* config for Wwise Vorbis (3 types for flexibility though not all combinations exist) */ /* config for Wwise Vorbis (3 types for flexibility though not all combinations exist) */
@ -466,14 +448,13 @@ typedef struct {
/* output (kinda ugly here but to simplify) */ /* output (kinda ugly here but to simplify) */
off_t data_start_offset; off_t data_start_offset;
int64_t last_granule;
} vorbis_custom_config; } vorbis_custom_config;
vorbis_custom_codec_data* init_vorbis_custom(STREAMFILE* sf, off_t start_offset, vorbis_custom_t type, vorbis_custom_config* config); vorbis_custom_codec_data* init_vorbis_custom(STREAMFILE* sf, off_t start_offset, vorbis_custom_t type, vorbis_custom_config* config);
void decode_vorbis_custom(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do, int channels); void free_vorbis_custom(void* data);
void reset_vorbis_custom(VGMSTREAM* vgmstream); int32_t vorbis_custom_get_samples(VGMSTREAM* v);
void seek_vorbis_custom(VGMSTREAM* vgmstream, int32_t num_sample);
void free_vorbis_custom(vorbis_custom_codec_data* data);
#endif #endif
typedef struct { typedef struct {
@ -622,14 +603,8 @@ void free_celt_fsb(celt_codec_data* data);
#ifdef VGM_USE_SPEEX #ifdef VGM_USE_SPEEX
/* speex_decoder */ /* speex_decoder */
typedef struct speex_codec_data speex_codec_data; void* init_speex_ea(int channels);
void* init_speex_torus(int channels);
speex_codec_data* init_speex_ea(int channels);
speex_codec_data* init_speex_torus(int channels);
void decode_speex(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do);
void reset_speex(speex_codec_data* data);
void seek_speex(VGMSTREAM* vgmstream, int32_t num_sample);
void free_speex(speex_codec_data* data);
#endif #endif

View file

@ -1,60 +0,0 @@
#ifndef _CODING_UTILS_SAMPLES_
#define _CODING_UTILS_SAMPLES_
/* sample helpers */
//TODO maybe move to .c
// (as .h can be inlined but these probably aren't called enough times that there is a notable boost)
typedef struct {
int16_t* samples; /* current samples (pointer is moved once consumed) */
int filled; /* samples left */
int channels; /* max channels sample buf handles */
//TODO may be more useful with filled+consumed and not moving *samples?
} s16buf_t;
static inline void s16buf_silence(sample_t** p_outbuf, int32_t* p_samples_silence, int channels) {
int samples_silence;
samples_silence = *p_samples_silence;
memset(*p_outbuf, 0, samples_silence * channels * sizeof(int16_t));
*p_outbuf += samples_silence * channels;
*p_samples_silence -= samples_silence;
}
static inline void s16buf_discard(sample_t** p_outbuf, s16buf_t* sbuf, int32_t* p_samples_discard) {
int samples_discard;
samples_discard = *p_samples_discard;
if (samples_discard > sbuf->filled)
samples_discard = sbuf->filled;
/* just ignore part of samples */
sbuf->samples += samples_discard * sbuf->channels;
sbuf->filled -= samples_discard;
*p_samples_discard -= samples_discard;
}
/* copy, move and mark consumed samples */
static inline void s16buf_consume(sample_t** p_outbuf, s16buf_t* sbuf, int32_t* p_samples_consume) {
int samples_consume;
samples_consume = *p_samples_consume;
if (samples_consume > sbuf->filled)
samples_consume = sbuf->filled;
/* memcpy is safe when filled/samples_copy is 0 (but must pass non-NULL bufs) */
memcpy(*p_outbuf, sbuf->samples, samples_consume * sbuf->channels * sizeof(int16_t));
sbuf->samples += samples_consume * sbuf->channels;
sbuf->filled -= samples_consume;
*p_outbuf += samples_consume * sbuf->channels;
*p_samples_consume -= samples_consume;
}
#endif /* _CODING_UTILS_SAMPLES_ */

View file

@ -1,27 +1,45 @@
#include "coding.h" #include "coding.h"
#include "coding_utils_samples.h" #include "../base/decode_state.h"
#include "../base/codec_info.h"
#include "libs/compresswave_lib.h" #include "libs/compresswave_lib.h"
#define COMPRESSWAVE_MAX_FRAME_SAMPLES 0x1000 /* arbitrary but should be multiple of 2 for 22050 mode */ #define COMPRESSWAVE_MAX_FRAME_SAMPLES 512 // arbitrary, but should be multiple of 2 for 22050 mode
#define COMPRESSWAVE_MAX_CHANNELS 2
/* opaque struct */ typedef struct {
struct compresswave_codec_data {
/* config */
STREAMFILE* sf; STREAMFILE* sf;
TCompressWaveData* cw; TCompressWaveData* handle;
/* frame state */ int16_t pbuf[COMPRESSWAVE_MAX_FRAME_SAMPLES * COMPRESSWAVE_MAX_CHANNELS];
int16_t* samples; int discard;
int frame_samples; } compresswave_codec_data;
/* frame state */ static void reset_compresswave(void* priv_data) {
s16buf_t sbuf; compresswave_codec_data* data = priv_data;
int samples_discard; if (!data) return;
};
/* actual way to reset internal flags */
TCompressWaveData_Stop(data->handle);
TCompressWaveData_Play(data->handle, 0);
compresswave_codec_data* init_compresswave(STREAMFILE* sf) { data->discard = 0;
return;
}
static void free_compresswave(void* priv_data) {
compresswave_codec_data* data = priv_data;
if (!data)
return;
TCompressWaveData_Free(data->handle);
close_streamfile(data->sf);
free(data);
}
void* init_compresswave(STREAMFILE* sf) {
compresswave_codec_data* data = NULL; compresswave_codec_data* data = NULL;
data = calloc(1, sizeof(compresswave_codec_data)); data = calloc(1, sizeof(compresswave_codec_data));
@ -30,15 +48,10 @@ compresswave_codec_data* init_compresswave(STREAMFILE* sf) {
data->sf = reopen_streamfile(sf, 0); data->sf = reopen_streamfile(sf, 0);
if (!data->sf) goto fail; if (!data->sf) goto fail;
data->frame_samples = COMPRESSWAVE_MAX_FRAME_SAMPLES; data->handle = TCompressWaveData_Create();
data->samples = malloc(2 * data->frame_samples * sizeof(int16_t)); /* always stereo */ if (!data->handle) goto fail;
if (!data->samples) goto fail;
TCompressWaveData_LoadFromStream(data->handle, data->sf);
data->cw = TCompressWaveData_Create();
if (!data->cw) goto fail;
TCompressWaveData_LoadFromStream(data->cw, data->sf);
reset_compresswave(data); reset_compresswave(data);
@ -49,90 +62,46 @@ fail:
} }
static int decode_frame(compresswave_codec_data* data, int32_t samples_to_do) { static bool decode_frame_compresswave(VGMSTREAM* v) {
uint32_t Len; compresswave_codec_data* data = v->codec_data;
int ok; decode_state_t* ds = v->decode_state;
data->sbuf.samples = data->samples; int samples = COMPRESSWAVE_MAX_FRAME_SAMPLES;
data->sbuf.channels = 2; //if (samples % 2 && samples > 1)
data->sbuf.filled = 0; // samples -= 1; /* 22khz does 2 samples at once */
if (samples_to_do > data->frame_samples)
samples_to_do = data->frame_samples;
if (samples_to_do % 2 && samples_to_do > 1)
samples_to_do -= 1; /* 22khz does 2 samples at once */
Len = samples_to_do * sizeof(int16_t) * 2; /* forced stereo */ uint32_t len = samples * sizeof(int16_t) * 2; /* forced stereo */
ok = TCompressWaveData_Rendering(data->cw, data->sbuf.samples, Len); int ok = TCompressWaveData_Rendering(data->handle, data->pbuf, len);
if (!ok) goto fail; if (!ok) return false;
data->sbuf.filled = samples_to_do; sbuf_init_s16(&ds->sbuf, data->pbuf, samples, v->channels);
ds->sbuf.filled = ds->sbuf.samples;
return 1; return true;
fail:
return 0;
} }
void seek_compresswave(VGMSTREAM* v, int32_t num_sample) {
void decode_compresswave(compresswave_codec_data* data, sample_t* outbuf, int32_t samples_to_do) { compresswave_codec_data* data = v->codec_data;
int ok;
while (samples_to_do > 0) {
s16buf_t* sbuf = &data->sbuf;
if (sbuf->filled <= 0) {
ok = decode_frame(data, samples_to_do);
if (!ok) goto fail;
}
if (data->samples_discard)
s16buf_discard(&outbuf, sbuf, &data->samples_discard);
else
s16buf_consume(&outbuf, sbuf, &samples_to_do);
}
return;
fail:
VGM_LOG("COMPRESSWAVE: decode fail, missing %i samples\n", samples_to_do);
s16buf_silence(&outbuf, &samples_to_do, 2);
}
void reset_compresswave(compresswave_codec_data* data) {
if (!data) return;
/* actual way to reset internal flags */
TCompressWaveData_Stop(data->cw);
TCompressWaveData_Play(data->cw, 0);
data->sbuf.filled = 0;
data->samples_discard = 0;
return;
}
void seek_compresswave(compresswave_codec_data* data, int32_t num_sample) {
if (!data) return; if (!data) return;
reset_compresswave(data); reset_compresswave(data);
data->samples_discard += num_sample; data->discard += num_sample;
} }
void free_compresswave(compresswave_codec_data* data) { STREAMFILE* compresswave_get_streamfile(VGMSTREAM* v) {
if (!data) compresswave_codec_data* data = v->codec_data;
return;
TCompressWaveData_Free(data->cw);
close_streamfile(data->sf);
free(data->samples);
free(data);
}
STREAMFILE* compresswave_get_streamfile(compresswave_codec_data* data) {
if (!data) return NULL; if (!data) return NULL;
return data->sf; return data->sf;
} }
const codec_info_t compresswave_decoder = {
.sample_type = SFMT_S16,
.decode_frame = decode_frame_compresswave,
.free = free_compresswave,
.reset = reset_compresswave,
.seek = seek_compresswave,
//.frame_samples = 2-4 (lib handles arbitrary calls)
//.frame_size = VBR / huffman codes
};

View file

@ -1,26 +1,44 @@
#include "coding.h" #include "coding.h"
#include "../base/decode_state.h"
#include "libs/clhca.h" #include "libs/clhca.h"
#include "../base/codec_info.h"
struct hca_codec_data { struct hca_codec_data {
STREAMFILE* sf; STREAMFILE* sf;
clHCA_stInfo info; clHCA_stInfo info;
signed short* sample_buffer; void* buf;
size_t samples_filled; float* fbuf;
size_t samples_consumed; int current_delay;
size_t samples_to_discard;
void* data_buffer;
unsigned int current_block; unsigned int current_block;
void* handle; void* handle;
}; };
static void reset_hca(void* priv) {
hca_codec_data* data = priv;
clHCA_DecodeReset(data->handle);
data->current_block = 0;
data->current_delay = data->info.encoderDelay;
}
void free_hca(void* priv) {
hca_codec_data* data = priv;
if (!data) return;
close_streamfile(data->sf);
clHCA_done(data->handle);
free(data->handle);
free(data->buf);
free(data->fbuf);
free(data);
}
/* init a HCA stream; STREAMFILE will be duplicated for internal use. */ /* init a HCA stream; STREAMFILE will be duplicated for internal use. */
hca_codec_data* init_hca(STREAMFILE* sf) { hca_codec_data* init_hca(STREAMFILE* sf) {
uint8_t header_buffer[0x2000]; /* hca header buffer data (probable max ~0x400) */ uint8_t header_buffer[0x1000]; /* hca header buffer data (probable max ~0x400) */
hca_codec_data* data = NULL; /* vgmstream HCA context */ hca_codec_data* data = NULL; /* vgmstream HCA context */
int header_size; int header_size;
int status; int status;
@ -51,11 +69,11 @@ hca_codec_data* init_hca(STREAMFILE* sf) {
status = clHCA_getInfo(data->handle, &data->info); /* extract header info */ status = clHCA_getInfo(data->handle, &data->info); /* extract header info */
if (status < 0) goto fail; if (status < 0) goto fail;
data->data_buffer = malloc(data->info.blockSize); data->buf = malloc(data->info.blockSize);
if (!data->data_buffer) goto fail; if (!data->buf) goto fail;
data->sample_buffer = malloc(sizeof(signed short) * data->info.channelCount * data->info.samplesPerBlock); data->fbuf = malloc(sizeof(float) * data->info.channelCount * data->info.samplesPerBlock);
if (!data->sample_buffer) goto fail; if (!data->fbuf) goto fail;
/* load streamfile for reads */ /* load streamfile for reads */
data->sf = reopen_streamfile(sf, 0); data->sf = reopen_streamfile(sf, 0);
@ -71,86 +89,64 @@ fail:
return NULL; return NULL;
} }
void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do) { static bool read_packet(VGMSTREAM* v) {
int samples_done = 0; hca_codec_data* data = v->codec_data;
const unsigned int channels = data->info.channelCount;
const unsigned int blockSize = data->info.blockSize;
// EOF/error
if (data->current_block >= data->info.blockCount)
return false;
while (samples_done < samples_to_do) { // single block of frames
const unsigned int block_size = data->info.blockSize;
//VGMSTREAMCHANNEL* vs = &v->ch[0];
off_t offset = data->info.headerSize + data->current_block * block_size; //vs->offset
if (data->samples_filled) { int bytes = read_streamfile(data->buf, offset, block_size, data->sf);
int samples_to_get = data->samples_filled; if (bytes != block_size) {
VGM_LOG("HCA: read %x vs expected %x bytes at %x\n", bytes, block_size, (uint32_t)offset);
if (data->samples_to_discard) { return false;
/* discard samples for looping */
if (samples_to_get > data->samples_to_discard)
samples_to_get = data->samples_to_discard;
data->samples_to_discard -= samples_to_get;
} }
else {
/* get max samples and copy */
if (samples_to_get > samples_to_do - samples_done)
samples_to_get = samples_to_do - samples_done;
memcpy(outbuf + samples_done*channels,
data->sample_buffer + data->samples_consumed*channels,
samples_to_get*channels * sizeof(sample_t));
samples_done += samples_to_get;
}
/* mark consumed samples */
data->samples_consumed += samples_to_get;
data->samples_filled -= samples_to_get;
}
else {
off_t offset = data->info.headerSize + data->current_block * blockSize;
int status;
size_t bytes;
/* EOF/error */
if (data->current_block >= data->info.blockCount) {
memset(outbuf, 0, (samples_to_do - samples_done) * channels * sizeof(sample_t));
break;
}
/* read frame */
bytes = read_streamfile(data->data_buffer, offset, blockSize, data->sf);
if (bytes != blockSize) {
VGM_LOG("HCA: read %x vs expected %x bytes at %x\n", bytes, blockSize, (uint32_t)offset);
break;
}
data->current_block++; data->current_block++;
return true;
}
bool decode_frame_hca(VGMSTREAM* v) {
bool ok = read_packet(v);
if (!ok)
return false;
decode_state_t* ds = v->decode_state;
hca_codec_data* data = v->codec_data;
const unsigned int block_size = data->info.blockSize;
/* decode frame */ /* decode frame */
status = clHCA_DecodeBlock(data->handle, (void*)(data->data_buffer), blockSize); int status = clHCA_DecodeBlock(data->handle, data->buf, block_size);
if (status < 0) { if (status < 0) {
VGM_LOG("HCA: decode fail at %x, code=%i\n", (uint32_t)offset, status); VGM_LOG("HCA: decode fail, code=%i\n", status);
break; return false;
} }
/* extract samples */ clHCA_ReadSamples(data->handle, data->fbuf);
clHCA_ReadSamples16(data->handle, data->sample_buffer);
data->samples_consumed = 0; int samples = data->info.samplesPerBlock;
data->samples_filled += data->info.samplesPerBlock; sbuf_init_flt(&ds->sbuf, data->fbuf, samples, v->channels);
} ds->sbuf.filled = samples;
if (data->current_delay) {
ds->discard += data->current_delay;
data->current_delay = 0;
} }
return true;
} }
void reset_hca(hca_codec_data* data) { void seek_hca(VGMSTREAM* v, int32_t num_sample) {
if (!data) return; hca_codec_data* data = v->codec_data;
//decode_state_t* ds = v->decode_state;
clHCA_DecodeReset(data->handle); //TODO handle arbitrary seek points to block N
data->current_block = 0;
data->samples_filled = 0;
data->samples_consumed = 0;
data->samples_to_discard = data->info.encoderDelay;
}
void loop_hca(hca_codec_data* data, int32_t num_sample) {
if (!data) return;
/* manually calc loop values if not set (should only happen with installed/forced looping, /* manually calc loop values if not set (should only happen with installed/forced looping,
* as actual files usually pad encoder delay so earliest loopStartBlock becomes 1-2, * as actual files usually pad encoder delay so earliest loopStartBlock becomes 1-2,
@ -163,20 +159,9 @@ void loop_hca(hca_codec_data* data, int32_t num_sample) {
} }
data->current_block = data->info.loopStartBlock; data->current_block = data->info.loopStartBlock;
data->samples_filled = 0; data->current_delay = data->info.loopStartDelay;
data->samples_consumed = 0; //ds->discard = data->info.loopStartDelay //overwritten on decode
data->samples_to_discard = data->info.loopStartDelay;
}
void free_hca(hca_codec_data* data) {
if (!data) return;
close_streamfile(data->sf);
clHCA_done(data->handle);
free(data->handle);
free(data->data_buffer);
free(data->sample_buffer);
free(data);
} }
clHCA_stInfo* hca_get_info(hca_codec_data* data) { clHCA_stInfo* hca_get_info(hca_codec_data* data) {
@ -235,14 +220,14 @@ static int test_hca_score(hca_codec_data* data, hca_keytest_t* hk) {
size_t bytes; size_t bytes;
/* read and test frame */ /* read and test frame */
bytes = read_streamfile(data->data_buffer, offset, block_size, data->sf); bytes = read_streamfile(data->buf, offset, block_size, data->sf);
if (bytes != block_size) { if (bytes != block_size) {
/* normally this shouldn't happen, but pre-fetch ACB stop with frames in half, so just keep score */ /* normally this shouldn't happen, but pre-fetch ACB stop with frames in half, so just keep score */
//total_score = -1; //total_score = -1;
break; break;
} }
score = clHCA_TestBlock(data->handle, data->data_buffer, block_size); score = clHCA_TestBlock(data->handle, data->buf, block_size);
/* get first non-blank frame */ /* get first non-blank frame */
if (!hk->start_offset && score != 0) { if (!hk->start_offset && score != 0) {
@ -315,3 +300,13 @@ void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode, uint64_t sub
} }
clHCA_SetKey(data->handle, (unsigned long long)keycode); clHCA_SetKey(data->handle, (unsigned long long)keycode);
} }
const codec_info_t hca_decoder = {
.sample_type = SFMT_FLT,
.decode_frame = decode_frame_hca,
.free = free_hca,
.reset = reset_hca,
.seek = seek_hca,
// frame_samples: 1024 + discard
// frame_size: variable
};

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,31 @@
#include "coding.h" #include "coding.h"
#include "../base/decode_state.h" #include "../base/decode_state.h"
#include "../base/codec_info.h"
#include "libs/ka1a_dec.h" #include "libs/ka1a_dec.h"
/* opaque struct */ /* opaque struct */
struct ka1a_codec_data { typedef struct {
uint8_t* buf; uint8_t* buf;
float* fbuf; float* fbuf;
int frame_size; int frame_size;
void* handle; void* handle;
}; } ka1a_codec_data;
ka1a_codec_data* init_ka1a(int bitrate_mode, int channels_tracks) { static void free_ka1a(void* priv_data) {
ka1a_codec_data* data = priv_data;
if (!data) return;
if (data->handle)
ka1a_free(data->handle);
free(data->buf);
free(data->fbuf);
free(data);
}
void* init_ka1a(int bitrate_mode, int channels_tracks) {
ka1a_codec_data* data = NULL; ka1a_codec_data* data = NULL;
int buf_size; int buf_size;
@ -39,7 +51,7 @@ fail:
return NULL; return NULL;
} }
static bool read_ka1a_frame(VGMSTREAM* v) { static bool read_frame(VGMSTREAM* v) {
ka1a_codec_data* data = v->codec_data; ka1a_codec_data* data = v->codec_data;
int bytes; int bytes;
@ -72,8 +84,8 @@ static bool read_ka1a_frame(VGMSTREAM* v) {
return true; return true;
} }
bool decode_ka1a_frame(VGMSTREAM* v) { bool decode_frame_ka1a(VGMSTREAM* v) {
bool ok = read_ka1a_frame(v); bool ok = read_frame(v);
if (!ok) if (!ok)
return false; return false;
@ -90,13 +102,14 @@ bool decode_ka1a_frame(VGMSTREAM* v) {
return true; return true;
} }
void reset_ka1a(ka1a_codec_data* data) { static void reset_ka1a(void* priv_data) {
ka1a_codec_data* data = priv_data;
if (!data || !data->handle) return; if (!data || !data->handle) return;
ka1a_reset(data->handle); ka1a_reset(data->handle);
} }
void seek_ka1a(VGMSTREAM* v, int32_t num_sample) { static void seek_ka1a(VGMSTREAM* v, int32_t num_sample) {
ka1a_codec_data* data = v->codec_data; ka1a_codec_data* data = v->codec_data;
decode_state_t* ds = v->decode_state; decode_state_t* ds = v->decode_state;
if (!data) return; if (!data) return;
@ -135,12 +148,10 @@ void seek_ka1a(VGMSTREAM* v, int32_t num_sample) {
#endif #endif
} }
void free_ka1a(ka1a_codec_data* data) { const codec_info_t ka1a_decoder = {
if (!data) return; .sample_type = SFMT_FLT,
.decode_frame = decode_frame_ka1a,
if (data->handle) .free = free_ka1a,
ka1a_free(data->handle); .reset = reset_ka1a,
free(data->buf); .seek = seek_ka1a,
free(data->fbuf); };
free(data);
}

View file

@ -329,19 +329,16 @@ int clHCA_getInfo(clHCA* hca, clHCA_stInfo *info) {
} }
//HCADecoder_DecodeBlockInt32 //HCADecoder_DecodeBlockInt32
void clHCA_ReadSamples16(clHCA* hca, signed short *samples) { void clHCA_ReadSamples16(clHCA* hca, short* samples) {
const float scale_f = 32768.0f; const float scale_f = 32768.0f;
float f;
signed int s;
unsigned int i, j, k;
/* PCM output is generally unused, but lib functions seem to use SIMD for f32 to s32 + round to zero */ /* PCM output is generally unused, but lib functions seem to use SIMD for f32 to s32 + round to zero */
for (i = 0; i < HCA_SUBFRAMES; i++) { for (int i = 0; i < HCA_SUBFRAMES; i++) {
for (j = 0; j < HCA_SAMPLES_PER_SUBFRAME; j++) { for (int j = 0; j < HCA_SAMPLES_PER_SUBFRAME; j++) {
for (k = 0; k < hca->channels; k++) { for (int k = 0; k < hca->channels; k++) {
f = hca->channel[k].wave[i][j]; float f = hca->channel[k].wave[i][j];
//f = f * hca->rva_volume; /* rare, won't apply for now */ //f = f * hca->rva_volume; /* rare, won't apply for now */
s = (signed int)(f * scale_f); int s = (signed int)(f * scale_f);
if (s > 32767) if (s > 32767)
s = 32767; s = 32767;
else if (s < -32768) else if (s < -32768)
@ -352,6 +349,20 @@ void clHCA_ReadSamples16(clHCA* hca, signed short *samples) {
} }
} }
void clHCA_ReadSamples(clHCA* hca, float* samples) {
/* interleave output */
for (int i = 0; i < HCA_SUBFRAMES; i++) {
for (int j = 0; j < HCA_SAMPLES_PER_SUBFRAME; j++) {
for (int k = 0; k < hca->channels; k++) {
float f = hca->channel[k].wave[i][j];
//f = f * hca->rva_volume; /* rare, won't apply for now */
*samples++ = f;
}
}
}
}
//-------------------------------------------------- //--------------------------------------------------
// Allocation and creation // Allocation and creation

View file

@ -64,7 +64,9 @@ int clHCA_DecodeBlock(clHCA* hca, void* data, unsigned int size);
/* Extracts signed and clipped 16 bit samples into sample buffer. /* Extracts signed and clipped 16 bit samples into sample buffer.
* May be called after clHCA_DecodeBlock, and will return the same data until * May be called after clHCA_DecodeBlock, and will return the same data until
* next decode. Buffer must be at least (samplesPerBlock*channels) long. */ * next decode. Buffer must be at least (samplesPerBlock*channels) long. */
void clHCA_ReadSamples16(clHCA* hca, short* outSamples); void clHCA_ReadSamples16(clHCA* hca, short* samples);
void clHCA_ReadSamples(clHCA* hca, float* samples);
/* Sets a 64 bit encryption key, to properly decode blocks. This may be called /* Sets a 64 bit encryption key, to properly decode blocks. This may be called
* multiple times to change the key, before or after clHCA_DecodeHeader. * multiple times to change the key, before or after clHCA_DecodeHeader.

View file

@ -695,7 +695,10 @@ int TCompressWaveData_Rendering(TCompressWaveData* self, int16_t* buf, uint32_t
} }
else { //in case of playback without loop else { //in case of playback without loop
self->FPlay = CW_FALSE; self->FPlay = CW_FALSE;
return result; //exit //return result; //exit
// OG lib returns error if requested more than avaiable, return partial buf here
break;
} }
} }
@ -761,10 +764,10 @@ int TCompressWaveData_Rendering(TCompressWaveData* self, int16_t* buf, uint32_t
self->FWavePosition += WaveStep; self->FWavePosition += WaveStep;
} }
//remainder calcs // remainder calcs
//depending on buffer lenght remainder may happen // depending on buffer length remainder may happen
//example: 44100 / 4 = 11025...OK 44100 / 8 = 5512.5...NG // example: 44100 / 4 = 11025...OK 44100 / 8 = 5512.5...NG
// in that case appear as noise // in that case it appears as noise
if (Len % 8 == 4) { if (Len % 8 == 4) {
TCompressWaveData_Rendering_WriteWave(self, &buf1, RVol, LVol); TCompressWaveData_Rendering_WriteWave(self, &buf1, RVol, LVol);
} }

File diff suppressed because it is too large Load diff

View file

@ -0,0 +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 <stdlib.h>
#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;
}

View file

@ -0,0 +1,123 @@
/* Handles bitreading from blocks and code unpacking (huffman/arithmetical decoding).
*/
#ifndef _MIO_ERISA_CONTEXT_H_
#define _MIO_ERISA_CONTEXT_H_
/* tree for huffman coding ("ERINA" codes) */
#define ERINA_CODE_FLAG 0x80000000u
#define ERINA_HUFFMAN_ESCAPE 0x7FFFFFFF
#define ERINA_HUFFMAN_NULL 0x8000u
#define ERINA_HUFFMAN_MAX 0x4000
#define ERINA_HUFFMAN_ROOT 0x200
#define MIO_HUFFMAN_SYMBOLS 256
typedef struct {
uint16_t weight;
uint16_t parent;
uint32_t child_code;
} ERINA_HUFFMAN_NODE;
typedef struct {
ERINA_HUFFMAN_NODE m_hnTree[0x201];
int m_iSymLookup[MIO_HUFFMAN_SYMBOLS];
int m_iEscape;
int m_iTreePointer;
} ERINA_HUFFMAN_TREE;
/* probability model for arithmetic coding ("ERISA" codes) */
#define ERISA_TOTAL_LIMIT 0x2000 // parameter limit
#define ERISA_SYMBOL_SORTS 0x101 // max types
#define ERISA_SUB_SORT_MAX 0x80
#define ERISA_PROB_SLOT_MAX 0x800 // max slots for probability model
#define ERISA_ESCAPE_CODE (-1)
typedef struct {
WORD wOccured; // symbol occurence count
SWORD wSymbol; // symbol (lower 8-bit only
} ERISA_CODE_SYMBOL;
typedef struct {
UDWORD dwTotalCount; // param < 2000H
UDWORD dwSymbolSorts; // number of symbol types
ERISA_CODE_SYMBOL acsSymTable[ERISA_SYMBOL_SORTS]; // probability model
ERISA_CODE_SYMBOL acsSubModel[ERISA_SUB_SORT_MAX]; // sub-probability model index
} ERISA_PROB_MODEL;
typedef enum {
ERINAEncodingFlag_efERINAOrder0 = 0x0000,
ERINAEncodingFlag_efERINAOrder1 = 0x0001
} ERINAEncodingFlag;
/* coding context for the decoder (AKA ERISADecodeContext), used to extract codes from a bitstream buffer */
typedef struct MIOContext MIOContext;
struct MIOContext {
// bitstream buffer
int m_nIntBufCount; // helper input buffer bitpos
UDWORD m_dwIntBuffer; // helper input buffer
uint8_t* m_pFileBuf;
int m_pFileLength;
int m_pFilePos;
// current symbol expansion
ULONG (*m_pfnDecodeSymbolBytes)(MIOContext* context, SBYTE* ptrDst, ULONG nCount);
// for run-length encoding
ULONG m_nLength;
// ERINA (huffman) code context
UDWORD m_dwERINAFlags;
ERINA_HUFFMAN_TREE* m_pLastHuffmanTree;
ERINA_HUFFMAN_TREE** m_ppHuffmanTree;
// ERISA (arithmetic) code context
UDWORD m_dwCodeRegister; // 16-bit
UDWORD m_dwAugendRegister; // 16-bit
int m_nPostBitCount; // end bit buffer counter
// ERISA-N context
ERISA_PROB_MODEL* m_pPhraseLenProb;
ERISA_PROB_MODEL* m_pPhraseIndexProb;
ERISA_PROB_MODEL* m_pRunLenProb;
ERISA_PROB_MODEL* m_pLastERISAProb;
ERISA_PROB_MODEL** m_ppTableERISA;
};
MIOContext* MIOContext_Open();
void MIOContext_Close(MIOContext* context);
void MIOContext_AttachInputFile(MIOContext* context, uint8_t* pFileBuf, int pFileLength);
int MIOContext_GetABit(MIOContext* context);
UINT MIOContext_GetNBits(MIOContext* context, int n);
void MIOContext_FlushBuffer(MIOContext* context);
ULONG MIOContext_DecodeSymbolBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount);
ESLError MIOContext_PrepareToDecodeERINACode(MIOContext* context, UDWORD dwFlags);
// (indirect call)
ULONG MIOContext_DecodeERINACodeBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount);
ESLError MIOContext_PrepareToDecodeERISACode(MIOContext* context);
void MIOContext_InitializeERISACode(MIOContext* context);
int MIOContext_DecodeERISACode(MIOContext* context, ERISA_PROB_MODEL* pModel);
//int MIOContext_DecodeERISACodeIndex(MIOContext* context, ERISA_PROB_MODEL* pModel);
// (indirect call)
ULONG MIOContext_DecodeERISACodeBytes(MIOContext* context, SBYTE* ptrDst, ULONG nCount);
ULONG MIOContext_DecodeERISACodeWords(MIOContext* context, SWORD* ptrDst, ULONG nCount);
#endif

View file

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

View file

@ -0,0 +1,40 @@
/* iDTC/iLOT/etc helper functions.
*/
#ifndef _MIO_ERISA_FILE_H_
#define _MIO_ERISA_FILE_H_
/* custom IO (OG lib uses FILEs) */
#include "../../util/io_callback.h"
typedef struct {
EMC_FILE_HEADER emcfh; // base header (EMC = Entis Media Complex)
ERI_FILE_HEADER erifh; // common file chunk
MIO_INFO_HEADER mioih; // audio audio chunk
uint32_t start;
char* desc; // text info
int desc_len; // extra
MIO_DATA_HEADER miodh; // packet info
uint8_t* buf;
int buf_size;
uint8_t* packet; //m_ptrBuffer
int packet_size;
void* ptrWaveBuf; // not part of the original code but to simplify usage
int ptrWaveBuf_len;
} MIOFile;
MIOFile* MIOFile_Open();
void MIOFile_Close(MIOFile* mf);
ESLError MIOFile_Initialize(MIOFile* mf, io_callback_t* file);
ESLError MIOFile_Reset(MIOFile* mf, io_callback_t* file);
ESLError MIOFile_NextPacket(MIOFile* mf, io_callback_t* file);
int MIOFile_GetTagLoop(MIOFile* mf, const char* tag);
// extra
void* MIOFile_GetCurrentWaveBuffer(MIOFile* mf);
int MIOFile_GetCurrentWaveBufferCount(MIOFile* mf);
#endif

View file

@ -0,0 +1,392 @@
/*****************************************************************************
E R I S A - L i b r a r y
----------------------------------------------------------------------------
Copyright (C) 2000-2003 Leshade Entis. All rights reserved.
*****************************************************************************/
#include <stdlib.h>
#include <math.h>
#include "mio_xerisa.h"
static volatile int g_eri_initialized = 0; //extra, not really that important but..
void ERI_eriInitializeLibrary(void) {
if (g_eri_initialized)
return;
EMT_eriInitializeMatrix();
g_eri_initialized = 1;
}
void ERI_eriCloseLibrary(void) {
}
//
static int round_f32(float r) {
if (r >= 0.0) {
return (int)floor(r + 0.5);
}
else {
return (int)ceil(r - 0.5);
}
}
void EMT_eriRoundR32ToWordArray(SWORD* ptrDst, int nStep, const float* ptrSrc, int nCount) {
for (int i = 0; i < nCount; i++) {
int nValue = round_f32(ptrSrc[i]);
if (nValue <= -0x8000) {
*ptrDst = -0x8000;
}
else if (nValue >= 0x7FFF) {
*ptrDst = 0x7FFF;
}
else {
*ptrDst = (SWORD)nValue;
}
ptrDst += nStep;
}
}
static const double ERI_PI = 3.141592653589; // = π
static const float ERI_rHalf = 0.5F; // = 1/2
//static const float ERI_r2 = 2.0F; // = 2.0
// revolve 2-point matrix (for MSS)
void EMT_eriRevolve2x2(float* ptrBuf1, float* ptrBuf2, float rSin, float rCos, unsigned int nStep, unsigned int nCount) {
for (int i = 0; i < nCount; i++) {
float r1 = *ptrBuf1;
float r2 = *ptrBuf2;
*ptrBuf1 = r1 * rCos - r2 * rSin;
*ptrBuf2 = r1 * rSin + r2 * rCos;
ptrBuf1 += nStep;
ptrBuf2 += nStep;
}
}
// create rotation matrix parameter for LOT transformation
ERI_SIN_COS* EMT_eriCreateRevolveParameter(unsigned int nDegreeDCT) {
int i, nDegreeNum;
nDegreeNum = 1 << nDegreeDCT;
int lc = 1, n = nDegreeNum / 2;
while (n >= 8) {
n /= 8;
++lc;
}
ERI_SIN_COS* ptrRevolve = malloc(lc * 8 * sizeof(ERI_SIN_COS));
if (!ptrRevolve)
return NULL;
double k = ERI_PI / (nDegreeNum * 2);
ERI_SIN_COS* ptrNextRev = ptrRevolve;
int nStep = 2;
do {
for (i = 0; i < 7; i++) {
double ws = 1.0;
double a = 0.0;
for (int j = 0; j < i; j++) {
a += nStep;
ws = ws * ptrNextRev[j].rSin + ptrNextRev[j].rCos * cos(a * k);
}
double r = atan2(ws, cos((a + nStep) * k));
ptrNextRev[i].rSin = (float)sin(r);
ptrNextRev[i].rCos = (float)cos(r);
}
ptrNextRev += 7;
nStep *= 8;
}
while (nStep < nDegreeNum);
return ptrRevolve;
}
void EMT_eriOddGivensInverseMatrix(float* ptrSrc, const ERI_SIN_COS* ptrRevolve, unsigned int nDegreeDCT) {
int i, j, k;
int nDegreeNum = 1 << nDegreeDCT;
// odd number rotate operation
int nStep, lc, index;
index = 1;
nStep = 2;
lc = (nDegreeNum / 2) / 8;
for (;;) {
ptrRevolve += 7;
index += nStep * 7;
nStep *= 8;
if (lc <= 8)
break;
lc /= 8;
}
k = index + nStep * (lc - 2);
for (j = lc - 2; j >= 0; j--) {
float r1 = ptrSrc[k];
float r2 = ptrSrc[k + nStep];
ptrSrc[k] = r1 * ptrRevolve[j].rCos + r2 * ptrRevolve[j].rSin;
ptrSrc[k + nStep] = r2 * ptrRevolve[j].rCos - r1 * ptrRevolve[j].rSin;
k -= nStep;
}
for (;;) {
if (lc > (nDegreeNum / 2) / 8)
break;
ptrRevolve -= 7;
nStep /= 8;
index -= nStep * 7;
for (i = 0; i < lc; i++) {
k = i * (nStep * 8) + index + nStep * 6;
for (j = 6; j >= 0; j--) {
float r1 = ptrSrc[k];
float r2 = ptrSrc[k + nStep];
ptrSrc[k] = r1 * ptrRevolve[j].rCos + r2 * ptrRevolve[j].rSin;
ptrSrc[k + nStep] = r2 * ptrRevolve[j].rCos - r1 * ptrRevolve[j].rSin;
k -= nStep;
}
}
lc *= 8;
}
}
// Inverse Previous LOT
void EMT_eriFastIPLOT(float* ptrSrc, unsigned int nDegreeDCT) {
unsigned int nDegreeNum = 1 << nDegreeDCT;
// divide odd and even freqs
for (int i = 0; i < nDegreeNum; i += 2) {
float r1 = ptrSrc[i];
float r2 = ptrSrc[i + 1];
ptrSrc[i] = ERI_rHalf * (r1 + r2);
ptrSrc[i + 1] = ERI_rHalf * (r1 - r2);
}
}
// Inverse LOT
void EMT_eriFastILOT(float* ptrDst, const float* ptrSrc1, const float* ptrSrc2, unsigned int nDegreeDCT) {
unsigned int nDegreeNum = 1 << nDegreeDCT;
// reverse duplication
for (int i = 0; i < nDegreeNum; i += 2) {
float r1 = ptrSrc1[i];
float r2 = ptrSrc2[i + 1];
ptrDst[i] = r1 + r2;
ptrDst[i + 1] = r1 - r2;
}
}
//////////////////////////////////////////////////////////////////////////////
static float ERI_rCosPI4; // = cos(pi/4)
static float ERI_r2CosPI4; // = 2*cos(pi/4)
// matrix coefs: k(n,i) = cos( (2*i+1) / (4*n) )
//
static float ERI_DCTofK2[2]; // = cos( (2*i+1) / 8 )
static float ERI_DCTofK4[4]; // = cos( (2*i+1) / 16 )
static float ERI_DCTofK8[8]; // = cos( (2*i+1) / 32 )
static float ERI_DCTofK16[16]; // = cos( (2*i+1) / 64 )
static float ERI_DCTofK32[32]; // = cos( (2*i+1) / 128 )
static float ERI_DCTofK64[64]; // = cos( (2*i+1) / 256 )
static float ERI_DCTofK128[128]; // = cos( (2*i+1) / 512 )
static float ERI_DCTofK256[256]; // = cos( (2*i+1) / 1024 )
static float ERI_DCTofK512[512]; // = cos( (2*i+1) / 2048 )
static float ERI_DCTofK1024[1024]; // = cos( (2*i+1) / 4096 )
static float ERI_DCTofK2048[2048]; // = cos( (2*i+1) / 8192 )
// matrix coefs table
static float* ERI_pMatrixDCTofK[MAX_DCT_DEGREE] = {
NULL,
ERI_DCTofK2,
ERI_DCTofK4,
ERI_DCTofK8,
ERI_DCTofK16,
ERI_DCTofK32,
ERI_DCTofK64,
ERI_DCTofK128,
ERI_DCTofK256,
ERI_DCTofK512,
ERI_DCTofK1024,
ERI_DCTofK2048
};
// initialize tables for DCT matrix operations
void EMT_eriInitializeMatrix(void) {
// prepare special constants
ERI_rCosPI4 = (float)cos(ERI_PI * 0.25);
ERI_r2CosPI4 = 2.0F * ERI_rCosPI4;
// matrix coefs init
for (int i = 1; i < MAX_DCT_DEGREE; i++) {
int n = (1 << i);
float* pDCTofK = ERI_pMatrixDCTofK[i];
double nr = ERI_PI / (4.0 * n);
double dr = nr + nr;
double ir = nr;
for (int j = 0; j < n; j++) {
pDCTofK[j] = (float)cos(ir);
ir += dr;
}
}
}
static void eriFastDCT(float* ptrDst, unsigned int nDstInterval, float* ptrSrc, float* ptrWorkBuf, unsigned int nDegreeDCT) {
if (nDegreeDCT < MIN_DCT_DEGREE || nDegreeDCT > MAX_DCT_DEGREE)
return;
if (nDegreeDCT == MIN_DCT_DEGREE) {
// 4th order DCT
float r32Buf[4];
// cross ops
r32Buf[0] = ptrSrc[0] + ptrSrc[3];
r32Buf[2] = ptrSrc[0] - ptrSrc[3];
r32Buf[1] = ptrSrc[1] + ptrSrc[2];
r32Buf[3] = ptrSrc[1] - ptrSrc[2];
// first half: A2 * DCT2
ptrDst[0] = ERI_rHalf * (r32Buf[0] + r32Buf[1]);
ptrDst[nDstInterval * 2] = ERI_rCosPI4 * (r32Buf[0] - r32Buf[1]);
// last half: R2 * 2 * A2 * DCT2 * K2
r32Buf[2] = ERI_DCTofK2[0] * r32Buf[2];
r32Buf[3] = ERI_DCTofK2[1] * r32Buf[3];
r32Buf[0] = r32Buf[2] + r32Buf[3];
r32Buf[1] = ERI_r2CosPI4 * (r32Buf[2] - r32Buf[3]);
r32Buf[1] -= r32Buf[0];
ptrDst[nDstInterval] = r32Buf[0];
ptrDst[nDstInterval * 3] = r32Buf[1];
}
else {
// regular DCT
//////////////////////////////////////////////////////////////////////
// | I J |
// cross ops = | |
// | I -J |
unsigned int nDegreeNum = (1 << nDegreeDCT);
unsigned int nHalfDegree = (nDegreeNum >> 1);
for (int i = 0; i < nHalfDegree; i++) {
ptrWorkBuf[i] = ptrSrc[i] + ptrSrc[nDegreeNum - i - 1];
ptrWorkBuf[i + nHalfDegree] = ptrSrc[i] - ptrSrc[nDegreeNum - i - 1];
}
// first half DCT : A * DCT
unsigned int nDstStep = (nDstInterval << 1);
eriFastDCT(ptrDst, nDstStep, ptrWorkBuf, ptrSrc, (nDegreeDCT - 1));
// last half DCT-IV : R * 2 * A * DCT * K
float* pDCTofK = ERI_pMatrixDCTofK[nDegreeDCT - 1];
ptrSrc = ptrWorkBuf + nHalfDegree;
ptrDst += nDstInterval;
for (int i = 0; i < nHalfDegree; i++) {
ptrSrc[i] *= pDCTofK[i];
}
eriFastDCT(ptrDst, nDstStep, ptrSrc, ptrWorkBuf, (nDegreeDCT - 1));
float* ptrNext = ptrDst;
for (int i = 0; i < nHalfDegree; i++) {
*ptrNext += *ptrNext;
ptrNext += nDstStep;
}
ptrNext = ptrDst;
for (int i = 1; i < nHalfDegree; i++) {
ptrNext[nDstStep] -= *ptrNext;
ptrNext += nDstStep;
}
}
}
void EMT_eriFastIDCT(float* ptrDst, float* ptrSrc, unsigned int nSrcInterval, float* ptrWorkBuf, unsigned int nDegreeDCT) {
if (nDegreeDCT < MIN_DCT_DEGREE || nDegreeDCT > MAX_DCT_DEGREE)
return;
if (nDegreeDCT == MIN_DCT_DEGREE) {
// 4th order IDCT
float r32Buf1[2];
float r32Buf2[4];
// even rows: IDCT2
r32Buf1[0] = ptrSrc[0];
r32Buf1[1] = ERI_rCosPI4 * ptrSrc[nSrcInterval * 2];
r32Buf2[0] = r32Buf1[0] + r32Buf1[1];
r32Buf2[1] = r32Buf1[0] - r32Buf1[1];
// odd rows: R * 2 * A * DCT * K
r32Buf1[0] = ERI_DCTofK2[0] * ptrSrc[nSrcInterval];
r32Buf1[1] = ERI_DCTofK2[1] * ptrSrc[nSrcInterval * 3];
r32Buf2[2] = r32Buf1[0] + r32Buf1[1];
r32Buf2[3] = ERI_r2CosPI4 * (r32Buf1[0] - r32Buf1[1]);
r32Buf2[3] -= r32Buf2[2];
// cross ops
ptrDst[0] = r32Buf2[0] + r32Buf2[2];
ptrDst[3] = r32Buf2[0] - r32Buf2[2];
ptrDst[1] = r32Buf2[1] + r32Buf2[3];
ptrDst[2] = r32Buf2[1] - r32Buf2[3];
}
else {
// regular IDCT
//////////////////////////////////////////////////////////////////////
// even rows: IDCT
unsigned int nDegreeNum = (1 << nDegreeDCT);
unsigned int nHalfDegree = (nDegreeNum >> 1);
unsigned int nSrcStep = (nSrcInterval << 1);
EMT_eriFastIDCT(ptrDst, ptrSrc, nSrcStep, ptrWorkBuf, (nDegreeDCT - 1));
// odd rows: R * 2 * A * DCT * K
float* pDCTofK = ERI_pMatrixDCTofK[nDegreeDCT - 1];
float* pOddSrc = ptrSrc + nSrcInterval;
float* pOddDst = ptrDst + nHalfDegree;
float* ptrNext = pOddSrc;
for (int i = 0; i < nHalfDegree; i++) {
ptrWorkBuf[i] = *ptrNext * pDCTofK[i];
ptrNext += nSrcStep;
}
eriFastDCT(pOddDst, 1, ptrWorkBuf, (ptrWorkBuf + nHalfDegree), (nDegreeDCT - 1));
for (int i = 0; i < nHalfDegree; i++) {
pOddDst[i] += pOddDst[i];
}
for (int i = 1; i < nHalfDegree; i++) {
pOddDst[i] -= pOddDst[i - 1];
}
// | I I |
// cross ops = | |
// | J -J |
float r32Buf[4];
unsigned int nQuadDegree = (nHalfDegree >> 1);
for (int i = 0; i < nQuadDegree; i++) {
r32Buf[0] = ptrDst[i] + ptrDst[nHalfDegree + i];
r32Buf[3] = ptrDst[i] - ptrDst[nHalfDegree + i];
r32Buf[1] = ptrDst[nHalfDegree - 1 - i] + ptrDst[nDegreeNum - 1 - i];
r32Buf[2] = ptrDst[nHalfDegree - 1 - i] - ptrDst[nDegreeNum - 1 - i];
ptrDst[i] = r32Buf[0];
ptrDst[nHalfDegree - 1 - i] = r32Buf[1];
ptrDst[nHalfDegree + i] = r32Buf[2];
ptrDst[nDegreeNum - 1 - i] = r32Buf[3];
}
}
}

View file

@ -0,0 +1,30 @@
/* Handles file ops like parsing header and reading blocks.
*/
#ifndef _MIO_ERISA_MATRIX_H_
#define _MIO_ERISA_MATRIX_H_
#define MIN_DCT_DEGREE 2
#define MAX_DCT_DEGREE 12
typedef struct {
float rSin;
float rCos;
} ERI_SIN_COS;
void EMT_eriInitializeMatrix(void);
void EMT_eriRoundR32ToWordArray(SWORD* ptrDst, int nStep, const float* ptrSrc, int nCount);
void EMT_eriRevolve2x2(float* ptrBuf1, float* ptrBuf2, float rSin, float rCos, unsigned int nStep, unsigned int nCount);
ERI_SIN_COS* EMT_eriCreateRevolveParameter(unsigned int nDegreeDCT);
void EMT_eriOddGivensInverseMatrix(float* ptrSrc, const ERI_SIN_COS* ptrRevolve, unsigned int nDegreeDCT);
void EMT_eriFastIPLOT(float* ptrSrc, unsigned int nDegreeDCT);
void EMT_eriFastILOT(float* ptrDst, const float* ptrSrc1, const float* ptrSrc2, unsigned int nDegreeDCT);
void EMT_eriFastIDCT(float* ptrDst, float* ptrSrc, unsigned int nSrcInterval, float* ptrWorkBuf, unsigned int nDegreeDCT);
#endif

View file

@ -0,0 +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 <stdlib.h>
#include <math.h>
#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;
}

View file

@ -0,0 +1,49 @@
/* Decodes audio context data into samples.
*/
#ifndef _MIO_ERISA_SOUND_H_
#define _MIO_ERISA_SOUND_H_
typedef struct {
MIO_INFO_HEADER m_mioih; // voice info header (current file)
unsigned int m_nBufLength; // block's sample count
// various internal (alloc'd) bufs
void* m_ptrBuffer1; // processing
void* m_ptrBuffer2; // reordering
void* m_ptrBuffer3; // interleave
BYTE* m_ptrDivisionTable; // block's division codes
BYTE* m_ptrRevolveCode; // block's revolve codes
SDWORD* m_ptrWeightCode; // block's quant weights
INT* m_ptrCoefficient; // block's scales
float* m_ptrMatrixBuf; // matrix ops
float* m_ptrInternalBuf; // ops helper
float* m_ptrWorkBuf; // DCT work buf
float* m_ptrWeightTable; // freq weights
float* m_ptrLastDCT; // previous DCT values
// temp pointers for the above (current pos)
BYTE* m_ptrNextDivision;
BYTE* m_ptrNextRevCode;
SDWORD* m_ptrNextWeight;
INT* m_ptrNextCoefficient;
INT* m_ptrNextSource;
float* m_ptrLastDCTBuf;
// file degree config
unsigned int m_nSubbandDegree; // matrix size (N)
unsigned int m_nDegreeNum; // derived matrix size (2^N)
ERI_SIN_COS* m_pRevolveParam; //
int m_nFrequencyPoint[7]; // freq center points
} MIODecoder;
MIODecoder* MIODecoder_Open();
void MIODecoder_Close(MIODecoder* dec);
ESLError MIODecoder_Initialize(MIODecoder* dec, const MIO_INFO_HEADER* infhdr);
ESLError MIODecoder_DecodeSound(MIODecoder* dec, MIOContext* context, const MIO_DATA_HEADER* datahdr, void* ptrWaveBuf);
#endif

View file

@ -0,0 +1,103 @@
/*****************************************************************************
E R I S A - L i b r a r y
-----------------------------------------------------------------------------
Copyright (C) 2002-2004 Leshade Entis, Entis-soft. All rights reserved.
*****************************************************************************/
#ifndef _MIO_ERISALIB_H_
#define _MIO_ERISALIB_H_
#include <stdint.h>
//#include <stdbool.h>
typedef unsigned char BYTE; //, *PBYTE;
typedef unsigned short int WORD; //, *PWORD;
typedef unsigned int UDWORD;
typedef signed int INT; //, *PINT;
typedef unsigned int UINT;
//typedef signed long int LONG; //, *PLONG;
typedef unsigned long int ULONG;
typedef signed char SBYTE;
typedef signed short int SWORD;
typedef signed int SDWORD;
typedef enum {
eslErrSuccess = 0,
eslErrGeneral = 1,
eslErrEof = 2, //extra
} ESLError;
void ERI_eriInitializeLibrary(void);
void ERI_eriCloseLibrary(void);
typedef struct {
uint64_t cHeader; // signature
UDWORD dwFileID;
UDWORD dwReserved; // 0
char cFormatDesc[0x30]; // format name
} EMC_FILE_HEADER;
typedef struct {
uint64_t nRecordID;
uint64_t nRecLength;
} EMC_RECORD_HEADER;
typedef struct {
UDWORD dwVersion;
UDWORD dwContainedFlag;
UDWORD dwKeyFrameCount;
UDWORD dwFrameCount;
UDWORD dwAllFrameTime;
} ERI_FILE_HEADER;
/* transformation (either lossless or LOT) */
#define CVTYPE_LOSSLESS_ERI 0x03020000
#define CVTYPE_DCT_ERI 0x00000001 // not used in audio
#define CVTYPE_LOT_ERI 0x00000005
#define CVTYPE_LOT_ERI_MSS 0x00000105
/* architecture (huffman for lossless or gamma/nemesis for LOT) */
#define ERI_ARITHMETIC_CODE 32 // not used in audio?
#define ERI_RUNLENGTH_GAMMA 0xFFFFFFFF //same as huffman with "gamma escape codes"
#define ERI_RUNLENGTH_HUFFMAN 0xFFFFFFFC
#define ERISA_NEMESIS_CODE 0xFFFFFFF0 // arithmetic coding (sliding window?)
// per file
typedef struct {
UDWORD dwVersion;
UDWORD fdwTransformation;
UDWORD dwArchitecture;
UDWORD dwChannelCount;
UDWORD dwSamplesPerSec; // input sample rate (output is fixed)
UDWORD dwBlocksetCount;
UDWORD dwSubbandDegree;
UDWORD dwAllSampleCount;
UDWORD dwLappedDegree;
UDWORD dwBitsPerSample;
// extra from comments
UDWORD rewindPoint;
} MIO_INFO_HEADER;
// per chunk
typedef struct {
BYTE bytVersion;
BYTE bytFlags;
BYTE bytReserved1;
BYTE bytReserved2;
UDWORD dwSampleCount;
} MIO_DATA_HEADER;
// Block is a "keyframe" and can be user to start decoding after flush/seek.
// Starting to decode in a non-keyframe returns an error.
#define MIO_LEAD_BLOCK 0x01
#include "mio_erisacontext.h"
#include "mio_erisafile.h"
#include "mio_erisamatrix.h"
#include "mio_erisasound.h"
#endif

View file

@ -0,0 +1,254 @@
#ifdef VGM_USE_VORBIS
#include <string.h>
#include <math.h>
#include "oor_helpers.h"
// .oor is divided into pages like "OggS", but simplified (variable sized)
// - v0: 0x01
// - v1: 0x0A
void oor_read_page(bitstream_t* is, oor_page_t* page) {
uint32_t granule_hi = 0, granule_lo = 0; //bitreader only handles 32b
page->version = bm_read(is, 2);
page->flags = bm_read(is, 4); // vorbis packet flags
// extra fields in V1
switch(page->version) {
case 0:
page->granule = 0;
page->padding1 = 0;
page->padding2 = 0;
// bitstream ends with into bit 6 of current byte
break;
case 1:
page->padding1 = bm_read(is, 2); // padding as granule must be byte-aligned
granule_hi = bm_read(is, 32);
granule_lo = bm_read(is, 32);
page->granule = ((uint64_t)granule_hi << 32) | granule_lo;
page->padding2 = bm_read(is, 6); // padding to leave bitstream into bit 6, like v0
break;
default: // unknown version
break;
}
}
// each .oor page except the first (header) has N packets:
// size is variable but theoretical max is ~0x200 (plus page header)
void oor_read_size(bitstream_t* is, oor_size_t* size) {
// right after page info (meaning 6 bits into bitstream)
size->vps_bits = bm_read(is, 4);
size->padding1 = bm_read(is, 1);
size->packet_count = bm_read(is, 8);
size->bps_selector = bm_read(is, 2);
switch(size->bps_selector) {
case 0: size->base_packet_size = 0; break; // 0 bits
case 1: size->base_packet_size = bm_read(is, 8); break;
case 2: size->base_packet_size = bm_read(is, 11); break;
case 3: //undefined
default:
size->base_packet_size = 0;
break;
}
for (int i = 0; i < size->packet_count; i++) {
if (size->vps_bits) {
size->variable_packet_size[i] = bm_read(is, size->vps_bits);
}
else {
size->variable_packet_size[i] = 0; //reset in case of reusing struct
}
}
uint32_t bit_pos = bm_pos(is) % 8;
if (bit_pos > 0) {
size->post_padding = bm_read(is, 8 - bit_pos); // aligned to next byte
}
else {
size->post_padding = 0;
}
// bitstream is now byte-aligned, and next is N packets of base + variable packet sizes (in bytes)
}
// bit-packed header (variable-sized):
// - v0 (sr_selector!=3): 0x02
// - v0 (sr_selector==3): 0x03
// - v1 (sr_selector!=3): 0x12
// - v1 (sr_selector==3): 0x13
void oor_read_header(bitstream_t* is, oor_header_t* hdr) {
hdr->pre_padding = bm_read(is, 2); // from first page, header is byte-aligned
hdr->version = bm_read(is, 2);
hdr->channels = bm_read(is, 3);
int sr_selector = bm_read(is, 2);
if (sr_selector == 3) {
int sr_index = bm_read(is, 8);
// few known modes, though they have 8 bits
// seems v1 lib can handle v0 files but sample rate is not compatible, maybe an oversight
// (note that some games somehow have both v0 and v1 files)
switch(hdr->version) {
case 0:
switch(sr_index) {
case 3: hdr->sample_rate = 32000; break;
case 4: hdr->sample_rate = 48000; break;
case 5: hdr->sample_rate = 96000; break;
default: hdr->sample_rate = 0; break;
}
case 1:
switch(sr_index) {
case 4: hdr->sample_rate = 32000; break;
case 5: hdr->sample_rate = 48000; break;
case 6: hdr->sample_rate = 64000; break;
case 7: hdr->sample_rate = 88200; break;
case 8: hdr->sample_rate = 96000; break;
default: hdr->sample_rate = 0; break;
}
break;
default:
break;
}
// shouldn't happen, but allow to catch missing cases
if (hdr->sample_rate == 0) // && sr_index < 256
hdr->sample_rate = 8000;
}
else {
hdr->sample_rate = 11025 * pow(2, sr_selector);
}
if (hdr->version == 1) {
uint32_t granule_hi = 0, granule_lo = 0; //bitreader only handles 32b
hdr->unknown1 = bm_read(is, 1); // always 1?
hdr->unknown2 = bm_read(is, 1); // always 1?
hdr->unknown3 = bm_read(is, 7); // always 0?
granule_hi = bm_read(is, 32);
granule_lo = bm_read(is, 32);
hdr->last_granule = ((uint64_t)granule_hi << 32) | granule_lo;
}
else {
hdr->unknown1 = 0;
hdr->unknown2 = 0;
hdr->unknown3 = 0;
hdr->last_granule = 0;
}
hdr->blocksize1_exp = bm_read(is, 4);
hdr->blocksize0_exp = bm_read(is, 4);
hdr->framing = bm_read(is, 1); //always 1
uint32_t bit_pos = bm_pos(is) % 8;
if (bit_pos > 0) {
hdr->post_padding = bm_read(is, 8 - bit_pos); // aligned to next byte
}
else {
hdr->post_padding = 0;
}
}
// bit-packed setup (should be byte-aligned)
void oor_read_setup(bitstream_t* is, oor_setup_t* setup) {
setup->type = bm_read(is, 2);
setup->codebook_id = bm_read(is, 6);
// known codebooks:
// 1~6: common on PC games
// 7: Muv-Luv, Muv-Luv Alternative (Vita)
}
// extra validations since bitpacket headers are a bit simple
bool oor_validate_header_page(oor_page_t* page, oor_header_t* hdr) {
if (page->version > 1 || page->flags != 0x02)
return false;
if (page->granule != 0 || page->padding1 != 0 || page->padding2 != 0)
return false;
if (hdr->pre_padding != 0 || hdr->version > 1 || hdr->version != page->version)
return false;
if (hdr->channels == 0 || hdr->sample_rate == 0)
return false;
//if (hdr->channels > OOR_MAX_CHANNELS) // known max is 2, allow to detect other cases
// return false;
if (hdr->version == 1 && hdr->last_granule == 0)
return false;
if (hdr->blocksize0_exp < 6 || hdr->blocksize0_exp > 13 || hdr->blocksize1_exp < 6 || hdr->blocksize1_exp > 13)
return false;
if (hdr->framing != 1)
return false;
if (hdr->post_padding != 0)
return false;
return true;
}
bool oor_validate_setup_page(oor_page_t* page, oor_size_t* size, oor_header_t* hdr) {
if (page->version != hdr->version)
return false;
// oddly enough codebooks may be split into other pages using OOR_FLAG_PARTIAL
if (page->flags & OOR_FLAG_CONTINUED || page->flags & OOR_FLAG_BOS || page->flags & OOR_FLAG_EOS)
return false;
if (page->granule != 0 || page->padding1 != 0 || page->padding2 != 0)
return false;
if (size->padding1 != 0 || size->bps_selector == 3)
return false;
if (size->post_padding != 0)
return false;
//if (setup->type != 0x01)
// return false;
//if (setup->codebook_id > OOR_MAX_CODEBOOK_ID) // known max is 7, allow to detect other cases
// return false;
return true;
}
bool oor_validate_setup_info(oor_page_t* page, oor_size_t* size, oor_setup_t* setup) {
// setup packet always has 2 packets: setup info + vorbis codebook
if (size->packet_count != 2)
return false;
int packet0_size = size->base_packet_size + size->variable_packet_size[0];
int packet1_size = size->base_packet_size + size->variable_packet_size[1];
if (packet0_size != 0x01)
return false;
// size is 0 when using codebook ids
if ((setup->codebook_id > 0 && packet1_size != 0) || (setup->codebook_id == 0 && packet1_size == 0))
return false;
return true;
}
bool oor_validate_audio_page(oor_page_t* page, oor_size_t* size, oor_header_t* hdr) {
if (hdr != NULL && page->version != hdr->version)
return false;
if (page->flags & OOR_FLAG_BOS)
return false;
if (page->padding1 != 0 || page->padding2 != 0)
return false;
if (size->padding1 != 0 || size->bps_selector == 3)
return false;
if (size->post_padding != 0)
return false;
if (size->packet_count == 0)
return false;
return true;
}
#endif

View file

@ -0,0 +1,77 @@
#ifndef _OOR_HELPERS_H
#define _OOR_HELPERS_H
#include <stdint.h>
#include <stdbool.h>
#include "../../util/bitstream_msb.h"
/**
* OOR has custom pages similar to OggS but not quite equivalent (needs to fiddle with packets).
* Header and setup packets are custom, but audio packets are standard.
* Format is bitpacked and some parts may be ambiguous, but it should fail midway on bad data.
* Lib expects the whole file in memory and isn't well tuned for streaming though.
*
* Info from:
* - mostly https://github.com/tsudoko/deoptimizeobs (FORMAT doc describes .oor, but some info is slightly off)
* - some bits from decompilation
*/
#define OOR_FLAG_CONTINUED (1<<3) // 1000 = continued (first packet in page is part of last; equivalent to OggS 0x01)
#define OOR_FLAG_PARTIAL (1<<2) // 0100 = partial (last packet in page is not complete and must be merged with prev; OggS uses size 0xFF for this)
#define OOR_FLAG_BOS (1<<1) // 0010 = beginning-of-stream (irst page, OggS 0x02)
#define OOR_FLAG_EOS (1<<0) // 0001 = end-of-stream (last page, OggS 0x04)
//#define OOR_FLAG_NORMAL 0 // any other regular packet
typedef struct {
uint8_t version;
uint8_t flags;
int64_t granule;
int padding1;
int padding2;
} oor_page_t;
typedef struct {
uint8_t vps_bits;
uint8_t padding1;
uint8_t packet_count;
uint8_t bps_selector;
int16_t base_packet_size; // max 7FF (may be 0)
int16_t variable_packet_size[256]; // max 7FFF of N packet_count (may be 0)
uint8_t post_padding;
} oor_size_t;
typedef struct {
uint8_t pre_padding;
uint8_t version;
uint8_t channels;
int sample_rate;
uint8_t unknown1;
uint8_t unknown2;
uint8_t unknown3;
int64_t last_granule;
uint8_t blocksize0_exp;
uint8_t blocksize1_exp;
uint8_t framing;
uint8_t post_padding;
} oor_header_t;
// codebooks are set in plugin with a table of size + codebook
typedef struct {
int type;
int codebook_id;
//int codebook_size;
//uint8_t* codebook;
} oor_setup_t;
// page headers, assumes buf in bitstream (probable max ~0x200)
void oor_read_page(bitstream_t* is, oor_page_t* page);
void oor_read_size(bitstream_t* is, oor_size_t* size);
void oor_read_header(bitstream_t* is, oor_header_t* hdr);
void oor_read_setup(bitstream_t* is, oor_setup_t* setup);
bool oor_validate_header_page(oor_page_t* page, oor_header_t* hdr);
bool oor_validate_setup_page(oor_page_t* page, oor_size_t* size, oor_header_t* hdr);
bool oor_validate_setup_info(oor_page_t* page, oor_size_t* size, oor_setup_t* setup);
bool oor_validate_audio_page(oor_page_t* page, oor_size_t* size, oor_header_t* hdr);
#endif

View file

@ -1260,12 +1260,11 @@ static inline int16_t clamp16f(float sample) {
} }
void tac_get_samples_pcm16(tac_handle_t* handle, int16_t* dst) { void tac_get_samples_pcm16(tac_handle_t* handle, int16_t* dst) {
int ch, i;
int chs = TAC_CHANNELS; int chs = TAC_CHANNELS;
for (ch = 0; ch < chs; ch++) { for (int ch = 0; ch < chs; ch++) {
int s = 0; int s = 0;
for (i = 0; i < TAC_FRAME_SAMPLES / 4; i++) { for (int i = 0; i < TAC_FRAME_SAMPLES / 4; i++) {
dst[(s+0)*chs + ch] = clamp16f(handle->wave[ch][i].f.x); dst[(s+0)*chs + ch] = clamp16f(handle->wave[ch][i].f.x);
dst[(s+1)*chs + ch] = clamp16f(handle->wave[ch][i].f.y); dst[(s+1)*chs + ch] = clamp16f(handle->wave[ch][i].f.y);
dst[(s+2)*chs + ch] = clamp16f(handle->wave[ch][i].f.z); dst[(s+2)*chs + ch] = clamp16f(handle->wave[ch][i].f.z);
@ -1275,6 +1274,21 @@ void tac_get_samples_pcm16(tac_handle_t* handle, int16_t* dst) {
} }
} }
// TAC originally returns PCM16 but allow internal floats for flexility
void tac_get_samples_float(tac_handle_t* handle, float* dst) {
int chs = TAC_CHANNELS;
for (int ch = 0; ch < chs; ch++) {
int s = 0;
for (int i = 0; i < TAC_FRAME_SAMPLES / 4; i++) {
dst[(s+0)*chs + ch] = (handle->wave[ch][i].f.x);
dst[(s+1)*chs + ch] = (handle->wave[ch][i].f.y);
dst[(s+2)*chs + ch] = (handle->wave[ch][i].f.z);
dst[(s+3)*chs + ch] = (handle->wave[ch][i].f.w);
s += 4;
}
}
}
void tac_set_loop(tac_handle_t* handle) { void tac_set_loop(tac_handle_t* handle) {
handle->frame_number = handle->header.loop_frame; handle->frame_number = handle->header.loop_frame;

View file

@ -49,6 +49,7 @@ void tac_free(tac_handle_t* handle);
int tac_decode_frame(tac_handle_t* handle, const uint8_t* block); int tac_decode_frame(tac_handle_t* handle, const uint8_t* block);
void tac_get_samples_pcm16(tac_handle_t* handle, int16_t* dst); void tac_get_samples_pcm16(tac_handle_t* handle, int16_t* dst);
void tac_get_samples_float(tac_handle_t* handle, float* dst);
void tac_set_loop(tac_handle_t* handle); void tac_set_loop(tac_handle_t* handle);

View file

@ -0,0 +1,393 @@
/* Handles Ubi-MPEG, a modified VBR MP2 (format seems to be called simply 'MPEG').
*
* Sync is slightly different and MPEG config is fixed (info removed from the bitstream). Frames
* are also not byte-aligned, meaning a new frame starts right after prev ends in the bitstream
* (in practice frames are aligned to 4-bits though so recognizable in plain sight).
* It also has a mode where 1 stereo frame + 1 mono frame are used make surround(?) output.
*
* TODO: this doesn't handle surround modes at the moment, so it isn't fully accurate.
*
* Partially reverse engineered from DLLs.
* - MPGMXBVR.DLL: regular version, seems to (mostly) not use simd (ex. sub_10001400)
* - MPGMXSVR.DLL: xmm version
*
* Info+crosschecking from spec and libmpg123/various:
* - http://www.mp3-tech.org/programmer/frame_header.html
* - https://github.com/dreamerc/mpg123/blob/master/src/libmpg123/layer2.c
*/
//TODO: test if files have encoding delay, but some files seem to have very few spare samples vs declared block samples
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "ubi_mpeg_helpers.h"
#include "../../util/log.h"
// forced size to simplify (explained later): (144 * bitrate * 1000 / sample_rate) + (1 optional padding byte)
//#define UBIMPEG_STEREO_FRAME_SIZE 0x20B // 128~160kkbps
//#define UBIMPEG_MONO_FRAME_SIZE 0x106 // 64~80kbps
#define UBIMPEG_FIXED_FRAME_SIZE 0x300 // ~256kbps at 48000hz
// standard MPEG modes
#define CH_MODE_MONO 3
#define CH_MODE_JOINT 1
#define CH_MODE_STEREO 0
#define MAX_BANDS 32 //30?
#define MAX_GRANULES 12
// band <> used allocation bits
// table 0 for 27 subbands (out of ~4); Ubi-MPEG only has this table.
// (spec's Table 3-B.2a, though we separate it into multiple tables for clarity)
static const uint8_t BITALLOC_TABLE_0[32] = {
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 0, 0, 0, 0, 0,
};
// index of "number of steps" to the "bits per codeword" (qbit) table, [band][index]
static const uint8_t QINDEX_TABLE_0[32][16] = {
{ 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, },
{ 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, },
{ 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 2, 3, 4, 5, 16, },
{ 0, 1, 16, },
{ 0, 1, 16, },
{ 0, 1, 16, },
{ 0, 1, 16, },
{ 0, 1, 16, },
{ 0, 1, 16, },
{ 0, 1, 16, },
};
// "bits per codeword" (qbit) table, number of bits used to quantize a value
// usually negative has a special meaning of "3 grouped qs"
static const int8_t QBITS_TABLE_0[17] = {
-5, -7, 3, -10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
};
#if 0
// often QBITS_TABLE uses negative values meaning "grouping" to avoid this table (-5, -7, 3, -10, ...)
static const int8_t GROUPING_TABLE[17] = {
3, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
#endif
// bands in the bitstream, fixed to index 0 in Ubi MPEG
static const int MAX_SUBBANDS[5] = { 27, 30, 8, 12, 30 };
// number of subbands that are regular stereo, depending on mode extension (rest are intensity stereo)
static int JOINT_BOUNDS[4] = { 4, 8, 12, 16 };
// most Ubi MPEG files have frames right after other, but sometimes they'll have some
// of padding. This doesn't seem a bitreading issue, their OG libs do seem to manually
// try to find sync until EOF on every new frame.
static int find_sync(bitstream_t* is) {
// read until some limit rather than EOF
int tests = 0;
while (tests < 32) {
//TODO: OG lib seems to advance bit-by-bit, but this seems to work
uint16_t sync = bm_read(is, 12); // 12 bits unlike 11 in MPEG
if (sync != 0)
return sync;
tests++;
}
return 0;
}
// reads a UBI-MPEG frame and transforms it into a regular MP2 frame
// Note that UBI-MPEG simply reads and decodes it by itself while handling surround modes,
// so this is just a quick hack.
int ubimpeg_transform_frame(bitstream_t* is, bitstream_t* os) {
//uint32_t offset = bm_pos(is) / 8;
// config per sample rae + bitrate + channels, fixed in Ubi MPEG
const int table = 0;
// bit info about how samples in subband are quantized
uint8_t bit_alloc[MAX_BANDS][2] = {0};//todo invert ch, todo 'allocation'
uint32_t scfsi[MAX_BANDS][2] = {0};
/* read 16-bit Ubi-MPEG header */
uint16_t sync = find_sync(is);
if (sync != 0xFFF) {
//VGM_LOG("UBI-MPEG: sync not found at %x (+ %i), value=%x\n", is->b_off / 8, is->b_off % 8, sync);
return 0;
}
uint8_t mode = bm_read(is, 4);
int extmode = (mode >> 0) & 0x03;
int ch_mode = (mode >> 2) & 0x03;
int channels = (ch_mode == CH_MODE_MONO) ? 1 : 2;
int subbands = MAX_SUBBANDS[table];
int joint_bound = (ch_mode != CH_MODE_JOINT) ? subbands : JOINT_BOUNDS[extmode]; // boundary of non-js bands
// Ubi-MPEG uses VBR and settings close to 44100 + 128~160kbps (stereo) / 64~80kbps (mono). However some
// frames spill into 1 more byte than the 0x20b allowed by 160kbps (even with padding bit). Sample rate + bitrate
// combo must end up using certain tables in decoders, so use a setting that allows a consistenct bitrate.
// Free bitrate (br_index 0) is usable too but decoders need several frames to detect sizes.
int frame_size = UBIMPEG_FIXED_FRAME_SIZE;
int br_index = 12; // 256kbps
int sr_index = 1; // fixed to 48000 (Ubi MPEG is 44100 but shouldn't affect decoding)
int padding = 0;
// real-ish settings, but doesn't work for all frames
//frame_size = (channels == 2) ? UBIMPEG_STEREO_FRAME_SIZE : UBIMPEG_MONO_FRAME_SIZE;
//br_index = (channels == 2) ? 9 : 5; // 160kbps / 80kbps
//sr_index = 0; // fixed to 44100
//padding = 1;
/* write 32-bit MPEG frame header */
bm_put(os, 11, 0x7FF); // sync
bm_put(os, 2, 3); // MPEG 1 index
bm_put(os, 2, 2); // layer II index
bm_put(os, 1, 1); // "no CRC" flag
bm_put(os, 4, br_index); // bitrate index
bm_put(os, 2, sr_index); // sample rate index
bm_put(os, 1, padding); // padding
bm_put(os, 1, 0); // private
bm_put(os, 2, ch_mode); // channel mode
bm_put(os, 2, extmode); // mode extension
bm_put(os, 1, 1); // copyrighted
bm_put(os, 1, 1); // original
bm_put(os, 2, 0); // emphasis
// step I: read allocation bits
for (int i = 0; i < joint_bound; i++) {
int ba_bits = BITALLOC_TABLE_0[i];
for (int ch = 0; ch < channels; ch++) {
bit_alloc[i][ch] = bm_read(is, ba_bits);
bm_put(os, ba_bits, bit_alloc[i][ch]);
}
}
// step I: read rest of joint stereo allocation bits (same for L and R)
for (int i = joint_bound; i < subbands; i++) {
int ba_bits = BITALLOC_TABLE_0[i];
bit_alloc[i][0] = bm_read(is, ba_bits);
bit_alloc[i][1] = bit_alloc[i][0];
bm_put(os, ba_bits, bit_alloc[i][0]);
}
// step I: read scalefactor selector information (how many scalefactors are included)
for (int i = 0; i < subbands; i++) {
for (int ch = 0; ch < channels; ch++) {
if (bit_alloc[i][ch] == 0)
continue;
scfsi[i][ch] = bm_read(is, 2);
bm_put(os, 2, scfsi[i][ch]);
}
}
// step I: read scalefactors from scfsi indexes
for (int i = 0; i < subbands; i++) {
for (int ch = 0; ch < channels; ch++) {
if (bit_alloc[i][ch] == 0)
continue;
int scf;
switch(scfsi[i][ch]) {
case 0: // 3 scalefactors
scf = bm_read(is, 6);
bm_put(os, 6, scf);
scf = bm_read(is, 6);
bm_put(os, 6, scf);
scf = bm_read(is, 6);
bm_put(os, 6, scf);
break;
case 1: // 2 scalefactors (reuses 1st for 2nd)
case 3: // 2 scalefactors (reuses 2nd for 3rd)
scf = bm_read(is, 6);
bm_put(os, 6, scf);
scf = bm_read(is, 6);
bm_put(os, 6, scf);
break;
case 2: // 1 scalefactor (reuses all 3)
scf = bm_read(is, 6);
bm_put(os, 6, scf);
break;
default:
break;
}
}
}
// step II: read quantized DCT coefficients
// (restored to 3 samples per granule and up to 32 subbands)
for (int gr = 0; gr < MAX_GRANULES; gr++) {
// regular quants
for (int i = 0; i < joint_bound; i++) {
for (int ch = 0; ch < channels; ch++) {
int ba_index = bit_alloc[i][ch];
if (ba_index == 0)
continue;
int qb_index = QINDEX_TABLE_0[i][ba_index - 1];
int qbits = QBITS_TABLE_0[qb_index];
int qs;
if (qbits < 0) { // grouping used
qbits = -qbits; // remove flag
qs = 1; // same value for 3 codes
}
else {
qs = 3; // 3 distinct codes
}
for (int q = 0; q < qs; q++) {
int qcode = bm_read(is, qbits);
bm_put(os, qbits, qcode);
}
}
}
// joint stereo quants (1 channel only)
for (int i = joint_bound; i < subbands; i++) {
{
int ba_index = bit_alloc[i][0];
if (ba_index == 0)
continue;
int qb_index = QINDEX_TABLE_0[i][ba_index - 1];
int qbits = QBITS_TABLE_0[qb_index];
int qs;
if (qbits < 0) { // grouping used
qbits = -qbits; // remove flag
qs = 1; // same value for 3 codes
}
else {
qs = 3; // 3 distinct codes
}
for (int q = 0; q < qs; q++) {
int qcode = bm_read(is, qbits);
bm_put(os, qbits, qcode);
}
}
}
}
// real MPEG frames are byte padded, but not Ubi-MPEG's (usually)
uint32_t bitpos = bm_pos(os);
if (bitpos % 8) {
bm_skip(os, 8 - (bitpos % 8));
}
//uint32_t end_offset = bm_pos(is) / 8;
//VGM_LOG("frame: ch_mode=%x, extmode=%x = chs=%i, reg_bands=%i, o=%x + %x\n", ch_mode, extmode, channels, joint_bound, offset, end_offset - offset);
// 0-pad as may confuse decoders otherwise
uint32_t obuf_done = bm_pos(os) / 8;
if (obuf_done > frame_size) {
//VGM_LOG("error: buf done=%x (%i) vs %x\n", obuf_done, bm_pos(os), frame_size);
return 0;
}
else {
memset(os->buf + obuf_done, 0x00, frame_size - obuf_done);
}
return frame_size;
}
#if 0
static bool parse_file(uint8_t* buf, int buf_size, FILE* outfile_mp2a, FILE* outfile_mp2b, FILE* outfile0_wav, FILE* outfile1_wav) {
printf("UBI-MPEG: samples=%i, 2rus=%i, 1rus=%i\n", samples, is_2rus, is_1rus);
bitstream_t is;
bm_setup(&is, buf, buf_size);
bm_skip(&is, 0x04 * 8);
if (is_1rus || is_2rus)
bm_skip(&is, 0x04 * 8);
uint8_t obuf[0x800];
bitstream_t os;
mp3dec_t mp3d0;
mp3dec_init(&mp3d0);
mp3dec_frame_info_t info0;
short pcm0[MINIMP3_MAX_SAMPLES_PER_FRAME];
mp3dec_t mp3d1;
mp3dec_init(&mp3d1);
mp3dec_frame_info_t info1;
short pcm1[MINIMP3_MAX_SAMPLES_PER_FRAME];
int frames = 0;
int done = 0;
int obuf_size;
while (1) {
// 1st frame
{
bm_setup(&os, obuf, sizeof(obuf));
obuf_size = ubimpeg_transform_frame(&is, &os);
if (!obuf_size) break;
frames++;
fwrite(obuf, sizeof(uint8_t), obuf_size, outfile_mp2a);
int pcm0_samples = mp3dec_decode_frame(&mp3d0, obuf, obuf_size, pcm0, &info0);
printf("mpeg0: pcm=%i, br=%i, ch=%i, by=%x\n", pcm0_samples, info0.bitrate_kbps, info0.channels, info0.frame_bytes);
fwrite(pcm0, sizeof(short), pcm0_samples * info0.channels, outfile0_wav);
}
// 2nd frame
if (is_1rus || is_2rus) {
bm_setup(&os, obuf, sizeof(obuf));
obuf_size = ubimpeg_transform_frame(&is, &os);
if (!obuf_size) break;
frames++;
fwrite(obuf, sizeof(uint8_t), obuf_size, outfile_mp2b);
int pcm1_samples = mp3dec_decode_frame(&mp3d1, obuf, obuf_size, pcm1, &info1);
printf("mpeg1: pcm=%i, br=%i, ch=%i, by=%x\n", pcm1_samples, info1.bitrate_kbps, info1.channels, info1.frame_bytes);
fwrite(pcm1, sizeof(short), pcm1_samples * info1.channels, outfile1_wav);
}
done += 1152;
printf("samples: %i / %i, obuf=%x (%x)\n", done, samples, obuf_size);
if (done >= samples)
break;
}
printf("frames: done=%i (%x) / samples=%i (%x)\n", done, done, samples, samples);
return true;
}
#endif

View file

@ -0,0 +1,9 @@
#ifndef _UBI_MPEG_HELPERS_H
#define _UBI_MPEG_HELPERS_H
#include "../../util/bitstream_msb.h"
int ubimpeg_transform_frame(bitstream_t* is, bitstream_t* os);
#endif

View file

@ -0,0 +1,777 @@
#ifndef _VORBIS_CODEBOOKS_OOR_H_
#define _VORBIS_CODEBOOKS_OOR_H_
#include "../../util/vorbis_codebooks.h"
/**
* Codebooks can be found like this packed in executables or riooor lib
* (with a table of size + offset to binary, ID is just an index to entry N though).
* Bigger .oor use codebooks in file so there aren't many setups.
*/
/* ******************************************** */
/* autogenerated */
/* ******************************************** */
static const uint8_t vcb_1[] = {
0x1F,0x42,0x43,0x56,0x01,0x00,0x00,0x01,0x00,0x9C,0x73,0x9A,0x31,0x87,0x99,0x62,0x94,0x52,0x89,0x21,0x94,0xDE,0x39,0x68,0x19,0x63,0x94,0x52,0x69,0x29,0xA5,0x5A,
0x4A,0xA9,0xA1,0x83,0x16,0x6B,0xAB,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,0xDE,0x7B,0xEF,0x1D,0x73,0x94,0x31,0x46,0x95,0x52,0x52,0x4A,0xA9,0x9D,0x73,0x96,0x31,0x47,
0x15,0x63,0x52,0x4A,0x89,0xA5,0x94,0x56,0x42,0x68,0x21,0x84,0xD6,0x62,0xAB,0xBD,0xF7,0xDE,0x6B,0xEF,0xB5,0xF6,0xDE,0x7B,0xEF,0x99,0x42,0x4C,0x29,0xA4,0x14,0x42,
0x08,0x4A,0x28,0x1D,0x53,0x8C,0x29,0xA4,0x94,0x42,0x4A,0x4A,0x08,0x25,0x64,0x0E,0x3A,0xC6,0x1C,0x53,0x8C,0x52,0x09,0x3D,0xD6,0x5E,0x6B,0xCC,0xBD,0xB6,0xD8,0x7B,
0xED,0xA1,0x63,0xCE,0x39,0xE6,0x1C,0x53,0x4C,0x4A,0x68,0x21,0x74,0x0E,0x3A,0xE6,0x9C,0x53,0x4C,0x4A,0x68,0xA9,0x84,0x52,0x42,0x06,0xA1,0x53,0xD0,0x52,0x89,0xAD,
0xF7,0xDE,0x62,0xEB,0xB9,0xA5,0xDA,0x7B,0xEF,0x81,0xD0,0x90,0x55,0x00,0x00,0x01,0x00,0xC0,0x40,0x10,0x1A,0xB2,0x0A,0x00,0x50,0x00,0x00,0x10,0x8A,0xA1,0x18,0x8A,
0x02,0x84,0x86,0xAC,0x02,0x00,0x32,0x00,0x00,0x04,0xE0,0x28,0x8E,0xE3,0x38,0x8E,0xE2,0x38,0x92,0x62,0x39,0x16,0x10,0x1A,0xB2,0x0A,0x00,0x00,0x02,0x00,0x10,0x00,
0x00,0xC0,0x90,0x0C,0x4B,0xB1,0x14,0xCD,0xD1,0x24,0x4D,0xD2,0x2C,0xCF,0x13,0x4D,0xD3,0x37,0x7D,0xD3,0x36,0x6D,0x55,0xD7,0x75,0x5D,0xD7,0x75,0x5D,0xD7,0x75,0x20,
0x34,0x64,0x15,0x00,0x00,0x01,0x00,0x40,0x40,0xA7,0x19,0xA6,0x1A,0x20,0xC2,0x8C,0x64,0x16,0x08,0x0D,0x59,0x05,0x00,0x20,0x00,0x00,0x00,0x44,0x20,0xC3,0x14,0x03,
0x42,0x43,0x56,0x01,0x00,0x00,0x01,0x00,0x00,0x52,0x24,0x39,0x49,0xA2,0xE4,0xA4,0x94,0x52,0x0E,0x83,0x64,0x31,0x49,0x2A,0xE5,0xA4,0x94,0x52,0x1E,0xC5,0xE4,0x51,
0x4D,0x32,0x06,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x0A,0x83,0x64,0x39,0x4A,0x2A,0xE5,0xA4,0x94,0x52,0x12,0xA3,0x64,0x31,0x4A,0xAA,
0xD4,0xA4,0x94,0x52,0x1E,0xE5,0xE4,0x49,0x4D,0x32,0xF6,0xA4,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x16,0xA4,0xE4,0x49,0x4B,0xBA,0x06,0xA5,
0x94,0x52,0x92,0xA3,0xA4,0x41,0x4B,0x36,0xF5,0xA4,0x94,0x52,0xA2,0x14,0x25,0x4A,0x4E,0xB6,0x27,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x3E,0x28,0xE5,0x83,0x50,0x4A,0x29,0xA5,0x94,0x52,0xAE,0xF6,0xE4,0x5A,0x4F,0x4A,0x29,0xA5,0x94,0x52,0xC6,0x28,0x25,0x7C,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x32,0x82,0xD0,0x90,0x55,0x00,0x00,0x10,0x00,0x00,0x60,0x9C,0x35,0xCA,0xA1,0xE8,0x24,0x3A,0x5F,0x9C,0xA1,0x9C,0x69,0x0A,0x92,
0x0A,0xA5,0x09,0xDD,0x9B,0xE4,0x28,0x79,0x4E,0x72,0x2B,0x2D,0x37,0xA7,0x9B,0x70,0xCE,0xE9,0xE6,0x94,0x73,0x3E,0x39,0xE7,0x9C,0x20,0x34,0x64,0x15,0x00,0x00,0x08,
0x00,0x00,0x21,0x84,0x14,0x52,0x48,0x21,0x85,0x14,0x52,0x48,0x21,0x85,0x14,0x62,0x88,0x21,0x86,0x1C,0x72,0xCA,0x29,0xA8,0xA0,0x82,0x4A,0x2A,0xA9,0xA8,0xA2,0x8A,
0x2A,0xAB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x3A,0xEB,0xA8,0xA3,0xCE,0x42,0x0A,0xA1,0xA4,0xD0,0x42,0x6B,0x35,0xC6,0x1A,0x63,0x6C,
0xB5,0x37,0x27,0x6D,0xCD,0x51,0x4A,0x27,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x73,0xCE,0x39,0x27,0x08,0x0D,0x59,0x05,0x00,0x80,0x00,0x00,0x10,0x08,0x19,0x64,0x90,0x41,
0x46,0x19,0x85,0x14,0x62,0x88,0x29,0xA7,0x9C,0x72,0x0A,0x2A,0xA9,0xA4,0x02,0x42,0x43,0x56,0x01,0x00,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x44,0xC9,0x74,0x4C,0x47,
0x74,0x44,0x45,0x74,0x44,0x47,0x74,0x44,0x47,0x74,0x44,0xC7,0x73,0x3C,0xC7,0x93,0x44,0x49,0xB4,0x3C,0x4B,0xD4,0x4C,0xCF,0x14,0x4D,0xD3,0x74,0x55,0xD9,0x95,0x65,
0x5D,0xB6,0x65,0xDB,0xD5,0x65,0xDD,0xD6,0x65,0xDF,0xF6,0x6D,0xDD,0xB6,0x6D,0x5F,0x37,0x76,0xE3,0x37,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,
0x8E,0xE3,0x18,0x82,0xD0,0x90,0x55,0x00,0x00,0x08,0x00,0x00,0x80,0x10,0x42,0x08,0x21,0x85,0x14,0x52,0x48,0x21,0xA5,0x98,0x62,0xCC,0x39,0xE8,0x20,0x84,0x50,0x4A,
0x20,0x34,0x64,0x15,0x00,0x00,0x08,0x00,0x20,0x00,0x00,0x00,0x40,0x51,0x1C,0xC5,0x71,0x24,0x47,0x92,0x24,0xC9,0x92,0x2C,0x4B,0xB3,0x34,0x4D,0xD3,0x34,0xCD,0x13,
0x3D,0xD1,0x33,0x3D,0xD5,0x73,0x45,0x59,0xB4,0x45,0xDB,0x73,0x3D,0x5B,0xB4,0x3D,0xD7,0x53,0x3D,0xD5,0x53,0x45,0xD5,0x54,0x4D,0xD7,0x74,0x55,0xD7,0x75,0x5D,0x57,
0x75,0x55,0x59,0x95,0x5D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0x19,0x08,0x0D,0x59,0x05,0x00,0x48,0x00,0x00,0xE8,0x48,0x8E,
0xA4,0x48,0x8A,0xA4,0x48,0x8E,0xE3,0x48,0x8E,0x24,0x01,0xA1,0x21,0xAB,0x00,0x00,0x19,0x00,0x00,0x01,0x00,0x28,0x8A,0xA2,0x38,0x8E,0x23,0x39,0x96,0x64,0x49,0x9A,
0x24,0x4A,0xA6,0xA5,0x5A,0xAE,0x26,0x7B,0xBA,0xA7,0x8B,0xBA,0xA8,0x03,0xA1,0x21,0xAB,0x00,0x00,0x40,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x18,0xA2,0x21,0x1A,
0xA2,0x23,0x5A,0xA2,0x26,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,
0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0xE7,0x79,0x9E,0xE7,0x79,0x9E,0xE7,0x79,0x1E,0x10,0x1A,0xB2,0x0A,0x00,0x90,0x00,0x00,0xD0,
0x91,0x1C,0xC9,0xB1,0x14,0x4B,0x91,0x14,0x49,0xB1,0x1C,0xCB,0x01,0x42,0x43,0x56,0x01,0x00,0x32,0x00,0x00,0x02,0x00,0x70,0x0C,0xC7,0x90,0x14,0xC9,0xB1,0x2C,0xCB,
0xD2,0x34,0xCD,0xF3,0x3C,0xCF,0x13,0x3D,0x51,0x14,0x45,0xD1,0x34,0x55,0x53,0x05,0x42,0x43,0x56,0x01,0x00,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x50,0x14,
0xC5,0x72,0x2C,0x47,0x92,0x34,0xC7,0x93,0x44,0x47,0x94,0x44,0x49,0xB4,0x44,0x49,0xD4,0x44,0x4D,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,
0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x20,0x34,0x64,0x25,0x00,0x00,0x04,
0x00,0x40,0x49,0x6A,0xB1,0xB5,0xD6,0x28,0x05,0xA1,0xA4,0x98,0x18,0xC2,0x94,0x93,0x1C,0x31,0x06,0x1D,0xA4,0x5E,0x31,0xE4,0x10,0x93,0x9E,0x39,0x06,0x15,0x93,0x5E,
0x2A,0x82,0x0C,0x62,0x1E,0x3B,0xC4,0x14,0x93,0x1C,0x08,0x0D,0x59,0x11,0x00,0x44,0x01,0x00,0x00,0xC6,0x20,0xC7,0x10,0x73,0xC8,0x39,0x47,0xA9,0x93,0x14,0x39,0xE7,
0xA4,0x74,0x94,0x1A,0xE7,0x1C,0xA5,0x8E,0x52,0x47,0x29,0xC5,0x9A,0x62,0xCD,0x28,0x95,0xDA,0x52,0xAC,0x8D,0x73,0x8E,0x52,0x47,0xA9,0xA3,0x94,0x6A,0x2C,0x2D,0x76,
0xD4,0x52,0xAD,0xA9,0xC6,0x02,0x00,0x00,0x02,0x1C,0x00,0x00,0x02,0x2C,0x84,0x42,0x43,0x56,0x04,0x00,0x51,0x00,0x00,0x84,0x31,0x48,0x29,0xA4,0x14,0x62,0x8A,0x39,
0xA7,0x98,0x43,0x8A,0x29,0xC7,0x98,0x73,0x88,0x31,0xE6,0x1C,0x73,0x8E,0x39,0xE7,0xA0,0x74,0x52,0x2A,0xE7,0x98,0x74,0x4E,0x4A,0xC4,0x18,0x73,0x8E,0x39,0xA7,0x9C,
0x73,0x52,0x32,0x27,0x95,0x73,0x4E,0x4A,0x27,0xA1,0x00,0x00,0x80,0x00,0x07,0x00,0x80,0x00,0x0B,0xA1,0xD0,0x90,0x15,0x01,0x40,0x9C,0x00,0x80,0x41,0x92,0x3C,0x4F,
0xD2,0x34,0x51,0x94,0x34,0x4F,0x14,0x3D,0x53,0x74,0x55,0x4F,0x34,0x55,0xD7,0xF2,0x3C,0xD3,0xF4,0x4C,0x53,0x55,0x3D,0xD1,0x54,0x55,0xD3,0x55,0x65,0xD9,0x54,0x55,
0x59,0xB6,0x3C,0xCF,0x34,0x3D,0x53,0x54,0x55,0xCF,0x34,0x55,0xD5,0x54,0x55,0x59,0x36,0x55,0x55,0x96,0x45,0x55,0xD5,0x6D,0xD3,0x55,0x75,0xDB,0x74,0x55,0xDD,0x76,
0x6D,0xD9,0xD7,0x5D,0x59,0x16,0x76,0x51,0x55,0x6D,0xDB,0x54,0x5D,0x5B,0x37,0x55,0xD7,0x16,0x5E,0xD9,0xD6,0x7D,0x59,0xB6,0x75,0x61,0xF2,0x3C,0x55,0xF5,0x4C,0xD3,
0x75,0x3D,0xD3,0x74,0x5D,0xD5,0x75,0x75,0x5B,0x75,0x5D,0x5B,0xF7,0x4C,0x53,0x76,0x4D,0xD7,0x95,0x65,0xD3,0x75,0x6D,0xDB,0x95,0x65,0x5D,0x57,0x65,0x59,0xF7,0x35,
0xD3,0x74,0x5D,0xD1,0x55,0x6D,0xD9,0x74,0x5D,0xD9,0x76,0x65,0x57,0xD7,0x5D,0x59,0xF6,0x85,0xD3,0x75,0x75,0xDF,0x95,0x65,0x61,0x57,0x65,0x59,0xF8,0x75,0x5D,0x17,
0x86,0x59,0xF7,0x8D,0x63,0x74,0x5D,0x5D,0x58,0x65,0xD7,0xF7,0x55,0x59,0xF6,0x8D,0x5B,0xB7,0x7D,0x5F,0xD6,0x75,0xE1,0x98,0x3C,0x4F,0x55,0x3D,0xD3,0x74,0x5D,0xCF,
0x34,0x5D,0xD7,0x74,0x5D,0x5D,0x57,0x5D,0xD7,0xD6,0x35,0xD3,0x74,0x5D,0xD3,0x75,0x6D,0x5B,0x54,0x5D,0x59,0x76,0x65,0xD9,0xF7,0x5D,0x57,0xD6,0x75,0xCF,0x34,0x5D,
0xD9,0x74,0x5D,0xD9,0x36,0x5D,0x57,0x96,0x5D,0x59,0xF6,0x7D,0x57,0x96,0x75,0xDD,0x74,0x5D,0xDD,0x57,0x65,0x59,0xF8,0x55,0x57,0x16,0x7E,0x59,0xD7,0x8D,0xE5,0xB6,
0x6D,0xE1,0x37,0x5D,0x57,0xD7,0x55,0x59,0xD6,0x7D,0x55,0x96,0x75,0x61,0xD6,0x75,0xE3,0xB9,0x75,0x5D,0x18,0x3E,0x55,0xD5,0x7D,0x53,0x76,0x85,0xDF,0x74,0x65,0x5F,
0xD8,0x7D,0xDD,0x59,0x6E,0xDD,0x37,0x96,0xD1,0x75,0x75,0x61,0x95,0x6D,0xE3,0x58,0x65,0x5B,0x18,0x7E,0xE1,0x58,0x96,0xDD,0x37,0x96,0x67,0x74,0x5D,0xDF,0x57,0x6D,
0x57,0x18,0x56,0x59,0xF6,0x95,0xDD,0xD7,0x9D,0x65,0xD7,0x75,0x65,0x78,0x6D,0xDB,0x58,0x6E,0x5D,0x57,0x8E,0x59,0xD7,0x8D,0x61,0x38,0x96,0xA7,0xEE,0x0B,0x4F,0x57,
0xB7,0x85,0x63,0xF6,0x6D,0xE7,0x99,0x7D,0x5D,0x39,0x7E,0x67,0x78,0x96,0x5F,0xF8,0x29,0x9F,0xAA,0xEA,0xBA,0xE9,0xBA,0xC2,0x70,0xBA,0xB2,0xEF,0xCB,0xB6,0x2E,0x0C,
0xBB,0x2F,0x2C,0xCB,0xE8,0xBA,0xBE,0xB0,0xCA,0xB2,0xF1,0xAB,0xB2,0xEC,0x0B,0xB7,0xEE,0x2B,0xC7,0xEE,0x0B,0xC3,0x31,0xBA,0xAE,0xF0,0xAB,0xB6,0xEC,0xFB,0xAE,0x2D,
0x0B,0xC7,0xED,0xEB,0xC6,0x32,0x0C,0xC3,0x72,0xBC,0xB6,0xAD,0x0C,0xB3,0xAE,0x0B,0x65,0xDB,0x47,0xF7,0x7D,0xA5,0xEF,0x2B,0x4B,0x57,0xB7,0x95,0x63,0xD6,0x75,0xA5,
0xED,0xEB,0x94,0x5D,0x18,0x2A,0xC3,0x31,0x54,0x06,0x00,0x00,0x0C,0x38,0x00,0x00,0x04,0x98,0x50,0x06,0x0A,0x0D,0x59,0x11,0x00,0xC4,0x09,0x00,0x30,0x08,0x39,0x87,
0x98,0x82,0x10,0x29,0x06,0x21,0x84,0x90,0x52,0x08,0x21,0xA5,0x88,0x31,0x08,0x99,0x73,0x52,0x2A,0xE6,0xA0,0x94,0x52,0x52,0x0B,0xA5,0xA4,0x16,0x31,0x06,0xA1,0x72,
0x4C,0x4A,0xE6,0x9C,0x94,0x50,0x4A,0x4B,0xA5,0x94,0x96,0x42,0x29,0xAD,0x95,0x54,0x62,0x0C,0xA5,0xC4,0xD8,0x5A,0xAB,0x35,0xB5,0x56,0x6B,0x28,0xA5,0xB5,0x50,0x4A,
0x8C,0xA5,0x94,0x16,0x53,0x6B,0xB5,0xB6,0xD8,0x6A,0x8D,0x18,0x93,0x92,0x39,0x27,0x25,0x73,0x4E,0x4A,0x29,0x25,0xB6,0x52,0x4A,0x6B,0x99,0x73,0x54,0x3A,0x07,0x25,
0x75,0x10,0x52,0x2A,0x25,0xB5,0x58,0x52,0x8A,0xB5,0x72,0x4E,0x4A,0x06,0x1D,0x95,0x0E,0x42,0x4A,0x25,0x95,0x98,0x4A,0x4A,0x31,0x96,0x54,0x62,0x2C,0x25,0xC5,0x5A,
0x52,0xAA,0xB1,0xA5,0xD8,0x6A,0x8B,0x31,0xE7,0x50,0x4A,0x8C,0x25,0x95,0x18,0x4B,0x4A,0xB1,0xB6,0x98,0x72,0x6B,0x31,0xD6,0x1C,0x31,0x26,0x21,0x73,0x4E,0x4A,0xE6,
0x9C,0x94,0x52,0x4A,0x6B,0xA5,0x94,0x16,0x2B,0xE7,0xA4,0x74,0x10,0x52,0xCA,0x1C,0x94,0x54,0x52,0x8A,0xB1,0x94,0x94,0x6A,0xE6,0x9C,0x94,0x0E,0x42,0x4A,0x1D,0x74,
0x54,0x4A,0x4A,0x31,0x96,0x54,0x62,0x0A,0xA5,0xC4,0x58,0x52,0xAA,0xB1,0x94,0xD4,0x62,0x8C,0x31,0xD7,0x96,0x62,0xCB,0xA1,0xA4,0x18,0x4B,0x4A,0xB1,0x96,0x54,0x62,
0x6C,0x31,0xE6,0xDC,0x62,0xCA,0xAD,0x93,0x12,0x5B,0x49,0x29,0xC6,0x50,0x52,0x8C,0x31,0xC6,0x9C,0x5B,0x8C,0x39,0x87,0x52,0x62,0x2C,0x29,0xC5,0x5A,0x52,0xAA,0x31,
0xC6,0x5A,0x73,0x8C,0xB1,0xE6,0x50,0x4A,0x8C,0x25,0x95,0x1A,0x4B,0x4A,0xB1,0xC6,0x1A,0x73,0x6D,0x31,0xD6,0x9C,0x62,0xCC,0x35,0xA5,0x58,0x73,0xAB,0x31,0xE7,0xD8,
0x72,0xEB,0xB5,0xE6,0xE0,0x53,0x6B,0x35,0xA7,0x98,0x72,0x6D,0x31,0xE6,0x5C,0x6B,0x0B,0xB2,0xE6,0x5C,0x7C,0x27,0x25,0xB6,0x50,0x4A,0x8C,0xA5,0xA4,0x18,0x5B,0x8C,
0xB5,0xB6,0x18,0x73,0x0E,0xA5,0xC4,0x58,0x52,0xAA,0xB1,0x94,0x14,0x6B,0x8B,0x31,0xE8,0xD6,0x62,0xED,0xA1,0x94,0x18,0x4B,0x4A,0x31,0x96,0x54,0x6A,0x8C,0x31,0xD6,
0x1C,0x6B,0xCC,0x39,0xC5,0x56,0x6B,0x8B,0xB1,0xD7,0xD4,0x62,0xCE,0x35,0xF7,0x60,0x6C,0xCB,0xB5,0xA7,0x16,0x6B,0x6E,0x31,0xE6,0x9E,0x62,0xCA,0xB5,0xF6,0xDA,0x83,
0xCD,0xAD,0xB7,0x02,0x00,0x00,0x06,0x1C,0x00,0x00,0x02,0x4C,0x28,0x03,0x85,0x86,0xAC,0x04,0x00,0xA2,0x00,0x00,0x00,0x63,0x18,0x73,0x0E,0x42,0xA3,0x90,0x73,0xCE,
0x49,0x69,0x90,0x72,0xCE,0x39,0x29,0x99,0x73,0x10,0x42,0x48,0x29,0x73,0x0E,0x42,0x08,0x29,0x75,0xCE,0x49,0x28,0xA9,0xB5,0xCE,0x39,0x08,0x29,0xB5,0x16,0x4A,0x49,
0xA9,0xB5,0x18,0x43,0x29,0x29,0xB5,0x16,0x63,0x01,0x00,0x00,0x05,0x0E,0x00,0x00,0x01,0x36,0x68,0x4A,0x2C,0x0E,0x50,0x68,0xC8,0x4A,0x00,0x20,0x15,0x00,0xC0,0xE0,
0x38,0x96,0xE5,0x79,0xA6,0x68,0x9A,0xB6,0xED,0x58,0x92,0xE7,0x89,0xA2,0x69,0xAA,0xAA,0x6D,0x3B,0x92,0xE5,0x79,0xA2,0x68,0x9A,0xAA,0x6A,0xDB,0x9A,0xE7,0x89,0xA2,
0x69,0xAA,0xAA,0xEB,0xEA,0xBA,0xE6,0x79,0xA2,0x68,0x9A,0xAA,0xEA,0xBA,0xB6,0x2E,0x8A,0xA2,0x69,0xAA,0xAA,0xAB,0xBA,0xAE,0xEE,0x8B,0xA2,0x68,0x9A,0xAA,0xAA,0xAA,
0xAE,0xAB,0xEB,0xA6,0x69,0xAA,0xAA,0xAB,0xBA,0xAE,0x2C,0xFB,0xBE,0x69,0x9A,0xAA,0xEA,0xBA,0xAE,0x2B,0xCB,0xBE,0xB0,0xAA,0xAE,0xEB,0xCA,0xB2,0x2D,0xDB,0xB6,0x31,
0xAC,0xAA,0xEA,0xBA,0xAE,0x2B,0xDB,0xB6,0x6D,0x1C,0xB7,0x6D,0xEB,0xBA,0xEE,0xFB,0xBE,0x30,0x54,0x6E,0xDB,0xD6,0x75,0x5F,0xF8,0x85,0x61,0x58,0x0A,0x00,0x00,0x4F,
0x70,0x00,0x00,0x2A,0xB0,0x61,0x75,0x84,0x93,0xA2,0xB1,0xC0,0x42,0x43,0x56,0x02,0x00,0x19,0x00,0x00,0x84,0x31,0x08,0x19,0x84,0x10,0x32,0x08,0x21,0x84,0x94,0x52,
0x0A,0x29,0xA5,0x94,0x00,0x00,0x80,0x01,0x07,0x00,0x80,0x00,0x13,0xCA,0x40,0xA1,0x21,0x2B,0x02,0x80,0x38,0x01,0x00,0x00,0x21,0x4A,0x21,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0xD4,0x51,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x42,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,
0x29,0xA5,0x94,0x52,0x4A,0x1D,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,
0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x4A,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x2A,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,
0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,
0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x00,0x80,
0x54,0x84,0x03,0x80,0xD4,0x83,0x09,0x65,0xA0,0xD0,0x90,0x95,0x00,0x40,0x2A,0x00,0x00,0x60,0x8C,0x52,0x8C,0x39,0x07,0xA1,0x94,0x86,0x31,0xE7,0x9C,0x83,0x90,0x4A,
0x4B,0x8D,0x62,0xCE,0x31,0x07,0xA1,0xA4,0x96,0x32,0xE7,0x20,0x94,0x92,0x52,0x4B,0x31,0x66,0xCE,0x41,0x29,0x25,0xA5,0xD6,0x5A,0xCC,0x9C,0x93,0xD2,0x5A,0x6C,0x3D,
0xC6,0x9A,0x39,0x27,0xA9,0xB5,0xD8,0x62,0xAC,0xB5,0x83,0xD2,0x5A,0x8D,0x3D,0xF7,0xDE,0x73,0x27,0xA5,0xB5,0x1A,0x6B,0xEE,0x3D,0xF7,0x92,0x5A,0xAD,0xB5,0xF6,0xD8,
0x73,0xEF,0x25,0xB5,0x18,0x73,0xAD,0xB9,0xF7,0x5A,0x63,0x8D,0xB9,0xF7,0x9E,0x73,0xEF,0xBD,0xA7,0x5C,0x7B,0xAF,0xB5,0xE7,0x5E,0x7B,0x2E,0x00,0x00,0xA7,0xC1,0x01,
0x00,0xF4,0xC0,0x86,0xD5,0x11,0x4E,0x8A,0xC6,0x02,0x0B,0x0D,0x59,0x09,0x00,0xA4,0x02,0x00,0x10,0x08,0x29,0xC5,0x98,0x73,0xCE,0x39,0x87,0x90,0x62,0xCC,0x39,0xE7,
0x20,0x84,0x10,0x21,0xC4,0x98,0x73,0xCE,0x41,0x08,0xA1,0x62,0x8C,0x39,0xE7,0x20,0x84,0x10,0x42,0xC5,0x98,0x63,0xCE,0x41,0x08,0x21,0x84,0xCE,0x39,0xE7,0x9C,0x83,
0x10,0x42,0x08,0x9D,0x73,0xCE,0x39,0x07,0x21,0x84,0x10,0x3A,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x74,0x0E,0x42,0x08,0x1D,0x84,0x10,0x42,0xE8,0x20,0x84,0x10,0x42,
0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0xA1,0x83,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x02,0x00,0x00,0x0B,
0x1C,0x00,0x00,0x02,0x6C,0x58,0x1D,0xE1,0xA4,0x68,0x2C,0xB0,0xD0,0x90,0x95,0x00,0x00,0x10,0x00,0x00,0xC2,0xAC,0xE4,0x12,0x8A,0x24,0x90,0x72,0x0C,0x9A,0x69,0x8C,
0x52,0x8E,0x9A,0x88,0x14,0x62,0x0A,0x9A,0xCA,0x10,0x43,0x4C,0x9A,0xA9,0x98,0x52,0xCA,0x81,0xE8,0x24,0x63,0x08,0x81,0x2A,0xCA,0xC6,0xD0,0x91,0x00,0x00,0x00,0x04,
0x01,0x00,0x01,0x26,0x80,0xC0,0x00,0x41,0xC1,0x17,0x42,0x40,0x8C,0x01,0x00,0x08,0x42,0x64,0x86,0x48,0x28,0xAC,0x82,0x05,0x06,0x65,0xD0,0xE0,0x30,0x0F,0x00,0x1E,
0x20,0x22,0x24,0x02,0x80,0xC4,0x04,0x45,0xDA,0xC5,0x05,0x74,0x19,0xE0,0x82,0x2E,0xEE,0x3A,0x10,0x42,0x10,0x82,0x10,0xC4,0xE2,0x00,0x0A,0x48,0xC0,0xC1,0x09,0x37,
0x3C,0xF1,0x86,0x27,0xDC,0xE0,0x04,0x9D,0xA2,0x52,0x07,0x01,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x00,0x00,0x07,0x05,0x10,0x11,0xD1,0x5C,0x85,0xC5,0x05,0x46,
0x86,0xC6,0x06,0x47,0x87,0x47,0x00,0x00,0x00,0x00,0x00,0xB8,0x00,0xC0,0x07,0x00,0xC0,0xF1,0x01,0x44,0x44,0x34,0x57,0x61,0x71,0x81,0x91,0xA1,0xB1,0xC1,0xD1,0xE1,
0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x04,
};
static const uint8_t vcb_2[] = {
0x1F,0x42,0x43,0x56,0x01,0x00,0x00,0x01,0x00,0x9C,0x73,0x9A,0x31,0x87,0x99,0x62,0x94,0x52,0x89,0x21,0x94,0xDE,0x39,0x68,0x19,0x63,0x94,0x52,0x69,0x29,0xA5,0x5A,
0x4A,0xA9,0xA1,0x83,0x16,0x6B,0xAB,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,0xDE,0x7B,0xEF,0x1D,0x73,0x94,0x31,0x46,0x95,0x52,0x52,0x4A,0xA9,0x9D,0x73,0x96,0x31,0x47,
0x15,0x63,0x52,0x4A,0x89,0xA5,0x94,0x56,0x42,0x68,0x21,0x84,0xD6,0x62,0xAB,0xBD,0xF7,0xDE,0x6B,0xEF,0xB5,0xF6,0xDE,0x7B,0xEF,0x99,0x42,0x4C,0x29,0xA4,0x14,0x42,
0x08,0x4A,0x28,0x1D,0x53,0x8C,0x29,0xA4,0x94,0x42,0x4A,0x4A,0x08,0x25,0x64,0x0E,0x3A,0xC6,0x1C,0x53,0x8C,0x52,0x09,0x3D,0xD6,0x5E,0x6B,0xCC,0xBD,0xB6,0xD8,0x7B,
0xED,0xA1,0x63,0xCE,0x39,0xE6,0x1C,0x53,0x4C,0x4A,0x68,0x21,0x74,0x0E,0x3A,0xE6,0x9C,0x53,0x4C,0x4A,0x68,0xA9,0x84,0x52,0x42,0x06,0xA1,0x53,0xD0,0x52,0x89,0xAD,
0xF7,0xDE,0x62,0xEB,0xB9,0xA5,0xDA,0x7B,0xEF,0x81,0xD0,0x90,0x55,0x00,0x00,0x01,0x00,0xC0,0x40,0x10,0x1A,0xB2,0x0A,0x00,0x50,0x00,0x00,0x10,0x8A,0xA1,0x18,0x8A,
0x02,0x84,0x86,0xAC,0x02,0x00,0x32,0x00,0x00,0x04,0xE0,0x28,0x8E,0xE3,0x38,0x8E,0xE2,0x38,0x92,0x62,0x39,0x16,0x10,0x1A,0xB2,0x0A,0x00,0x00,0x02,0x00,0x10,0x00,
0x00,0xC0,0x90,0x0C,0x4B,0xB1,0x14,0xCD,0xD1,0x24,0x4D,0xD2,0x2C,0xCF,0x13,0x4D,0xD3,0x37,0x7D,0xD3,0x36,0x6D,0x55,0xD7,0x75,0x5D,0xD7,0x75,0x5D,0xD7,0x75,0x20,
0x34,0x64,0x15,0x00,0x00,0x01,0x00,0x40,0x40,0xA7,0x19,0xA6,0x1A,0x20,0xC2,0x8C,0x64,0x16,0x08,0x0D,0x59,0x05,0x00,0x20,0x00,0x00,0x00,0x44,0x20,0xC3,0x14,0x03,
0x42,0x43,0x56,0x01,0x00,0x00,0x01,0x00,0x00,0x52,0x24,0x39,0x49,0xA2,0xE4,0xA4,0x94,0x52,0x0E,0x83,0x64,0x31,0x49,0x2A,0xE5,0xA4,0x94,0x52,0x1E,0xC5,0xE4,0x51,
0x4D,0x32,0x06,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x0A,0x83,0x64,0x39,0x4A,0x2A,0xE5,0xA4,0x94,0x52,0x12,0xA3,0x64,0x31,0x4A,0xAA,
0xD4,0xA4,0x94,0x52,0x1E,0xE5,0xE4,0x49,0x4D,0x32,0xF6,0xA4,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x16,0xA4,0xE4,0x49,0x4B,0xBA,0x06,0xA5,
0x94,0x52,0x92,0xA3,0xA4,0x41,0x4B,0x36,0xF5,0xA4,0x94,0x52,0xA2,0x14,0x25,0x4A,0x4E,0xB6,0x27,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x3E,0x28,0xE5,0x83,0x50,0x4A,0x29,0xA5,0x94,0x52,0xAE,0xF6,0xE4,0x5A,0x4F,0x4A,0x29,0xA5,0x94,0x52,0xC6,0x28,0x25,0x7C,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x32,0x82,0xD0,0x90,0x55,0x00,0x00,0x10,0x00,0x00,0x60,0x9C,0x35,0xCA,0xA1,0xE8,0x24,0x3A,0x5F,0x9C,0xA1,0x9C,0x69,0x0A,0x92,
0x0A,0xA5,0x09,0xDD,0x9B,0xE4,0x28,0x79,0x4E,0x72,0x2B,0x2D,0x37,0xA7,0x9B,0x70,0xCE,0xE9,0xE6,0x94,0x73,0x3E,0x39,0xE7,0x9C,0x20,0x34,0x64,0x15,0x00,0x00,0x08,
0x00,0x00,0x21,0x84,0x14,0x52,0x48,0x21,0x85,0x14,0x52,0x48,0x21,0x85,0x14,0x62,0x88,0x21,0x86,0x1C,0x72,0xCA,0x29,0xA8,0xA0,0x82,0x4A,0x2A,0xA9,0xA8,0xA2,0x8A,
0x2A,0xAB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x3A,0xEB,0xA8,0xA3,0xCE,0x42,0x0A,0xA1,0xA4,0xD0,0x42,0x6B,0x35,0xC6,0x1A,0x63,0x6C,
0xB5,0x37,0x27,0x6D,0xCD,0x51,0x4A,0x27,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x73,0xCE,0x39,0x27,0x08,0x0D,0x59,0x05,0x00,0x80,0x00,0x00,0x10,0x08,0x19,0x64,0x90,0x41,
0x46,0x19,0x85,0x14,0x62,0x88,0x29,0xA7,0x9C,0x72,0x0A,0x2A,0xA9,0xA4,0x02,0x42,0x43,0x56,0x01,0x00,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x44,0xC9,0x74,0x4C,0x47,
0x74,0x44,0x45,0x74,0x44,0x47,0x74,0x44,0x47,0x74,0x44,0xC7,0x73,0x3C,0xC7,0x93,0x44,0x49,0xB4,0x3C,0x4B,0xD4,0x4C,0xCF,0x14,0x4D,0xD3,0x74,0x55,0xD9,0x95,0x65,
0x5D,0xB6,0x65,0xDB,0xD5,0x65,0xDD,0xD6,0x65,0xDF,0xF6,0x6D,0xDD,0xB6,0x6D,0x5F,0x37,0x76,0xE3,0x37,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,
0x8E,0xE3,0x18,0x82,0xD0,0x90,0x55,0x00,0x00,0x08,0x00,0x00,0x80,0x10,0x42,0x08,0x21,0x85,0x14,0x52,0x48,0x21,0xA5,0x98,0x62,0xCC,0x39,0xE8,0x20,0x84,0x50,0x4A,
0x20,0x34,0x64,0x15,0x00,0x00,0x08,0x00,0x20,0x00,0x00,0x00,0x40,0x51,0x1C,0xC5,0x71,0x24,0x47,0x92,0x24,0xC9,0x92,0x2C,0x4B,0xB3,0x34,0x4D,0xD3,0x34,0xCD,0x13,
0x3D,0xD1,0x33,0x3D,0xD5,0x73,0x45,0x59,0xB4,0x45,0xDB,0x73,0x3D,0x5B,0xB4,0x3D,0xD7,0x53,0x3D,0xD5,0x53,0x45,0xD5,0x54,0x4D,0xD7,0x74,0x55,0xD7,0x75,0x5D,0x57,
0x75,0x55,0x59,0x95,0x5D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0x19,0x08,0x0D,0x59,0x05,0x00,0x48,0x00,0x00,0xE8,0x48,0x8E,
0xA4,0x48,0x8A,0xA4,0x48,0x8E,0xE3,0x48,0x8E,0x24,0x01,0xA1,0x21,0xAB,0x00,0x00,0x19,0x00,0x00,0x01,0x00,0x28,0x8A,0xA2,0x38,0x8E,0x23,0x39,0x96,0x64,0x49,0x9A,
0x24,0x4A,0xA6,0xA5,0x5A,0xAE,0x26,0x7B,0xBA,0xA7,0x8B,0xBA,0xA8,0x03,0xA1,0x21,0xAB,0x00,0x00,0x40,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x18,0xA2,0x21,0x1A,
0xA2,0x23,0x5A,0xA2,0x26,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,
0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0xE7,0x79,0x9E,0xE7,0x79,0x9E,0xE7,0x79,0x1E,0x10,0x1A,0xB2,0x0A,0x00,0x90,0x00,0x00,0xD0,
0x91,0x1C,0xC9,0xB1,0x14,0x4B,0x91,0x14,0x49,0xB1,0x1C,0xCB,0x01,0x42,0x43,0x56,0x01,0x00,0x32,0x00,0x00,0x02,0x00,0x70,0x0C,0xC7,0x90,0x14,0xC9,0xB1,0x2C,0xCB,
0xD2,0x34,0xCD,0xF3,0x3C,0xCF,0x13,0x3D,0x51,0x14,0x45,0xD1,0x34,0x55,0x53,0x05,0x42,0x43,0x56,0x01,0x00,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x50,0x14,
0xC5,0x72,0x2C,0x47,0x92,0x34,0xC7,0x93,0x44,0x47,0x94,0x44,0x49,0xB4,0x44,0x49,0xD4,0x44,0x4D,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,
0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x20,0x34,0x64,0x25,0x00,0x00,0x04,
0x00,0x80,0x59,0xAB,0x3D,0xB6,0x5C,0x41,0x89,0x29,0xB5,0xD6,0x20,0xE4,0x10,0x83,0x56,0x31,0x27,0x1D,0xA4,0x1E,0x21,0xC3,0x0C,0x62,0x5C,0x21,0xE4,0x10,0x52,0xDC,
0x31,0xC3,0x88,0x41,0x9E,0x53,0xE5,0x90,0x72,0x1E,0x08,0x0D,0x59,0x11,0x00,0x44,0x01,0x00,0x00,0xC6,0x20,0xC7,0x10,0x73,0xC8,0x39,0x47,0xA9,0x93,0x14,0x39,0xE7,
0xA8,0x74,0x94,0x1A,0xE7,0x1C,0xA5,0x8E,0x52,0x47,0x29,0xC5,0x9A,0x62,0xED,0x28,0x95,0x9A,0x52,0xAC,0x8D,0x73,0x8E,0x52,0x47,0x29,0xA3,0x94,0x6A,0x2C,0x2D,0x76,
0x94,0x52,0xAD,0xA9,0xC6,0x02,0x00,0x00,0x02,0x1C,0x00,0x00,0x02,0x2C,0x84,0x42,0x43,0x56,0x04,0x00,0x51,0x00,0x00,0x04,0x42,0x48,0x29,0xA4,0x14,0x52,0x8A,0x39,
0xA7,0x98,0x43,0x4A,0x29,0xC7,0x98,0x73,0x48,0x29,0xE6,0x9C,0x72,0x8E,0x39,0xE7,0xA0,0x74,0x10,0x2A,0xE7,0x18,0x74,0x0E,0x4A,0xA4,0x94,0x72,0x8E,0x39,0xA7,0x9C,
0x73,0x12,0x32,0x07,0x99,0x73,0x0E,0x42,0x27,0xA1,0x00,0x00,0x80,0x00,0x07,0x00,0x80,0x00,0x0B,0xA1,0xD0,0x90,0x15,0x01,0x40,0x9C,0x00,0x80,0x43,0x72,0x34,0x4D,
0xD2,0x34,0xD1,0x93,0x34,0xCD,0x13,0x3D,0x51,0x54,0x55,0x4F,0x14,0x55,0x55,0xD2,0x34,0xD3,0xD4,0x44,0x51,0x35,0x35,0x51,0x34,0x4D,0x51,0x35,0x65,0x57,0x34,0x4D,
0x57,0x96,0x34,0xCD,0x14,0x35,0x51,0x54,0x4D,0x4D,0x14,0x4D,0x55,0x34,0x4D,0xD7,0x35,0x4D,0xD5,0x95,0x3D,0xD3,0xB4,0x65,0x51,0x55,0x75,0x59,0x54,0x55,0x5D,0x76,
0x6D,0xD7,0xB7,0x5D,0xD9,0xD5,0x6D,0xCF,0x34,0x65,0x5B,0x54,0x55,0xD9,0x36,0x55,0x55,0xD6,0x5D,0x57,0xB6,0x75,0x57,0xB6,0x6D,0x5F,0xD2,0x34,0xD3,0xD4,0x44,0x51,
0x55,0x35,0x51,0x54,0x5D,0x53,0x55,0x6D,0xDB,0x54,0x55,0xDB,0xD6,0x44,0xD1,0x75,0x45,0x55,0x95,0x5D,0x51,0x55,0x65,0xD9,0x75,0x5D,0xDB,0x56,0x5D,0x59,0xD7,0x35,
0x51,0x74,0x55,0x51,0x35,0x5D,0x57,0x54,0x55,0x57,0x56,0x5D,0xD5,0xB6,0x55,0xD7,0xD5,0x7D,0x51,0x55,0x75,0x5D,0x75,0x5D,0x5F,0x37,0x5D,0xD7,0xD7,0x6D,0x5D,0x17,
0x7E,0xD9,0xB6,0x85,0x61,0x54,0x55,0x5B,0x37,0x5D,0x55,0xD7,0x4D,0xD7,0xD5,0x85,0xD9,0x96,0x7D,0x5D,0xB6,0x75,0x61,0x98,0x34,0xCD,0x34,0x35,0x51,0x74,0x55,0x4D,
0x14,0x55,0xD7,0x54,0x55,0xDB,0x36,0x55,0x55,0xB6,0x35,0x51,0x54,0x5D,0x51,0x55,0x65,0x59,0x34,0x55,0xD7,0x55,0x5D,0x57,0xD7,0x55,0xD7,0x95,0x6D,0xCD,0x14,0x5D,
0x57,0x54,0x55,0x59,0x16,0x55,0xD5,0x75,0x55,0xD7,0xF5,0x75,0xD5,0x75,0x6D,0x5B,0x54,0x55,0xDD,0x36,0x5D,0xD7,0xD7,0x4D,0xD5,0xD5,0x75,0xD9,0xB6,0x85,0x63,0x96,
0x6D,0xDD,0x17,0x55,0x55,0xF7,0x4D,0xD7,0xD5,0x75,0xD5,0x75,0x6D,0x61,0xB6,0x6D,0x61,0xB8,0x6D,0xDB,0x37,0x36,0xD3,0xB4,0x75,0xD3,0x75,0x7D,0xDD,0x54,0x5D,0xDF,
0xB7,0x7D,0xDD,0x18,0x66,0xDD,0x16,0x96,0x51,0x75,0x7D,0x5D,0x95,0x65,0xE1,0x37,0x65,0xD9,0xF7,0x75,0xDF,0x17,0x96,0x59,0xD7,0x85,0xE1,0x53,0x55,0x5D,0x37,0x65,
0xD5,0xF7,0x4D,0x59,0xF6,0x85,0xDB,0xD7,0x8D,0x65,0xD6,0x75,0x61,0x78,0x6D,0xDB,0x38,0x66,0x5B,0x37,0x96,0xD7,0xD6,0x85,0xE3,0x37,0x8E,0xA5,0xAD,0xFB,0xC6,0xB1,
0xDA,0xB2,0x70,0xBC,0xBE,0xAD,0x2C,0xAF,0x6E,0x33,0x76,0xE1,0x37,0x86,0x5B,0xF8,0x8D,0x63,0x33,0x4D,0xDD,0x36,0x5D,0xD5,0xF7,0x4D,0xD5,0xF5,0x7D,0x59,0xB7,0x95,
0xE3,0xD6,0x7D,0xE3,0xF8,0x54,0x55,0xD7,0x4D,0xD9,0x15,0x7E,0xD3,0x95,0x7D,0xE1,0xB6,0x75,0xE5,0xB8,0x75,0xDF,0x28,0xAA,0xAA,0xAF,0xAB,0xB2,0xAB,0xFB,0xAA,0x2C,
0xFB,0xBE,0xAD,0xDB,0x84,0xDD,0xF7,0x95,0x63,0xB5,0x6D,0x63,0x78,0x6D,0x5D,0x18,0x5E,0x59,0x27,0xDC,0xBA,0x6F,0x0C,0xBF,0x70,0x0C,0xCB,0x6A,0xCB,0xC2,0xF2,0xEA,
0xB6,0xB1,0xCC,0xBE,0x4D,0xB9,0x85,0x9D,0xB1,0x1B,0x3F,0x02,0x00,0x00,0x06,0x1C,0x00,0x00,0x02,0x4C,0x28,0x03,0x85,0x86,0xAC,0x08,0x00,0xE2,0x04,0x00,0x18,0x84,
0x9C,0x53,0x4C,0x41,0xA8,0x14,0x83,0x10,0x42,0x48,0x29,0x84,0x90,0x52,0xC5,0x18,0x84,0xCC,0x39,0x29,0x15,0x73,0x50,0x4A,0x29,0xA9,0x85,0x50,0x52,0xAB,0x18,0x83,
0x50,0x39,0x26,0x21,0x73,0x4E,0x4A,0x28,0xA1,0xA5,0x52,0x4A,0x4B,0xA1,0x94,0xD6,0x4A,0x29,0xB1,0x85,0x52,0x5A,0x6B,0xAD,0xD5,0x9A,0x5A,0x8B,0x35,0x94,0xD2,0x5A,
0x28,0x25,0xB6,0x52,0x4A,0x8B,0xAD,0xB5,0x1A,0x5B,0x6B,0xB5,0x46,0x8C,0x41,0xC8,0x1C,0x93,0x92,0x31,0x27,0xA5,0x94,0xD2,0x5A,0x29,0xA5,0xB5,0xCC,0x39,0x29,0x9D,
0x83,0x92,0x3A,0xE7,0x28,0x95,0x92,0x52,0x2C,0x29,0xB5,0x58,0x31,0x26,0x25,0x73,0x8E,0x4A,0xE7,0x20,0xA5,0x92,0x4A,0x4C,0x25,0xA5,0xD8,0x4A,0x2A,0xB1,0x95,0x92,
0x62,0x2C,0x29,0xC5,0xD8,0x52,0x6C,0xB5,0xC5,0x98,0x73,0x28,0xA5,0xC5,0x92,0x4A,0x8C,0x25,0xA5,0x58,0x5B,0x4C,0xB5,0xB5,0x18,0x6B,0x8E,0x18,0x83,0x92,0x39,0x26,
0x25,0x63,0x4E,0x4A,0x29,0xA5,0xB5,0x52,0x4A,0x6B,0x15,0x63,0x52,0x3A,0xE8,0x28,0x65,0xCE,0x49,0x2A,0x29,0xB5,0x58,0x4A,0x4A,0x31,0x73,0x4E,0x4A,0xE7,0x1C,0xA5,
0x0E,0x3A,0x2A,0x25,0x95,0xD8,0x4A,0x2A,0xB1,0x85,0x52,0x62,0x2B,0x29,0xC5,0x18,0x4A,0x69,0x31,0xC6,0x98,0x6B,0x4B,0xB1,0xE5,0x52,0x52,0x8B,0x25,0xA5,0x18,0x4B,
0x2A,0x31,0xB6,0x18,0x73,0x6E,0x31,0xD5,0xD6,0x49,0x68,0x2D,0x94,0x12,0x63,0x28,0x25,0xC6,0x18,0x63,0xCD,0xAD,0xB5,0x5A,0x43,0x29,0xB1,0x95,0x94,0x62,0x2C,0x29,
0xC5,0x16,0x63,0xAD,0xBD,0xC5,0x98,0x6B,0x28,0x25,0xC6,0x92,0x4A,0x8C,0x25,0xA5,0x18,0x63,0x6D,0xB9,0xB6,0x18,0x6B,0x6E,0xAD,0xD5,0x9A,0x5A,0xAB,0xB9,0xC5,0x98,
0x6B,0x6D,0xB9,0xF5,0x5A,0x73,0xF0,0xA9,0xB5,0x5A,0x53,0x4B,0xB9,0xB6,0x18,0x73,0x8E,0xB5,0xF5,0x58,0x6B,0x0E,0xBE,0x93,0xD2,0x5A,0x28,0x25,0xB6,0x52,0x4A,0x8C,
0x2D,0xB6,0x5A,0x5B,0x8C,0xB9,0x86,0x52,0x62,0x2C,0x29,0xC5,0x58,0x4A,0x6A,0x31,0xC6,0x98,0x73,0x6B,0xB1,0xE6,0x50,0x4A,0x8B,0x25,0xA5,0x16,0x4B,0x2A,0x31,0xB6,
0x18,0x6B,0x8E,0x35,0xE6,0x9A,0x5A,0xCB,0xB5,0xC5,0x98,0x6B,0x6A,0xAD,0xE6,0x5A,0x6B,0xD0,0xB1,0xE5,0xD8,0x5B,0x6B,0x35,0xB7,0x18,0x6B,0x4E,0xAD,0xE5,0x5A,0x73,
0xED,0x41,0xE6,0xD6,0x5B,0x01,0x00,0x00,0x03,0x0E,0x00,0x00,0x01,0x26,0x94,0x81,0x42,0x43,0x56,0x02,0x00,0x51,0x00,0x00,0x80,0x31,0x8C,0x39,0x27,0xA5,0x51,0xC8,
0x39,0xE7,0xA4,0x34,0x48,0x39,0xE7,0x9C,0x94,0xCC,0x31,0x08,0x21,0xA4,0x94,0x39,0x07,0x21,0x84,0x94,0x3A,0xE7,0x20,0x94,0xD4,0x5A,0xE7,0x20,0x84,0x52,0x5A,0x2B,
0xA5,0xA4,0xD4,0x5A,0x8C,0xA5,0x94,0x94,0x5A,0x8B,0xB1,0x00,0x00,0x80,0x02,0x07,0x00,0x80,0x00,0x1B,0x34,0x25,0x16,0x07,0x28,0x34,0x64,0x25,0x00,0x90,0x0A,0x00,
0x60,0x70,0x1C,0x4D,0x13,0x3D,0x53,0x54,0x4D,0x5B,0x76,0x24,0xC9,0xF3,0x44,0x51,0x55,0x55,0xD5,0xB6,0x1D,0x49,0xF2,0x3C,0x51,0x34,0x55,0x55,0xB5,0x6D,0xCD,0xF3,
0x44,0x51,0x35,0x55,0xD5,0x75,0x7D,0x5D,0xF3,0x3C,0x51,0x34,0x55,0x55,0x75,0x5D,0x5D,0x17,0x4D,0x53,0x55,0x55,0xD5,0x75,0x65,0xD9,0xF7,0x45,0xD3,0x54,0x55,0x55,
0x75,0x5D,0x57,0xF6,0x75,0x53,0x55,0x55,0xD5,0x75,0x65,0x59,0x96,0x7D,0xE1,0x54,0x55,0x55,0x75,0x5D,0xD7,0x95,0x6D,0xDF,0x57,0x5D,0xD7,0x75,0x65,0xD9,0xB6,0x6D,
0xDD,0x18,0x56,0xD7,0x75,0x5D,0x59,0x96,0x6D,0x5B,0x37,0x8E,0xDD,0xD6,0x75,0xDD,0xF7,0x85,0xE1,0x18,0x9E,0xE7,0xD6,0x75,0x5D,0xF7,0x85,0xE1,0x37,0x2A,0x05,0x00,
0x80,0x27,0x38,0x00,0x00,0x15,0xD8,0xB0,0x3A,0xC2,0x49,0xD1,0x58,0x60,0xA1,0x21,0x2B,0x01,0x80,0x0C,0x00,0x00,0xC2,0x18,0x84,0x0C,0x42,0x0A,0x19,0x84,0x90,0x42,
0x0A,0x29,0x85,0x90,0x52,0x4A,0x00,0x00,0xC0,0x80,0x03,0x00,0x40,0x80,0x09,0x65,0xA0,0xD0,0x90,0x95,0x00,0x40,0x0C,0x00,0x00,0x40,0x08,0x84,0x10,0x22,0xC6,0x20,
0x84,0x10,0x29,0xE5,0x9C,0x73,0xCE,0x39,0xE7,0x9C,0x73,0xCE,0x39,0xE7,0x9C,0x73,0xCE,0x39,0xE7,0x9C,0x73,0xCE,0x39,0x27,0x00,0x60,0x3F,0xC2,0x01,0x40,0xEA,0xC1,
0xC4,0xC4,0x14,0x16,0x1A,0xB2,0x12,0x00,0x48,0x05,0x00,0x00,0x8C,0x51,0x4A,0x31,0xE7,0x20,0xA4,0xD2,0x30,0xE6,0x9C,0x73,0x10,0x52,0x69,0xA9,0x51,0xCC,0x39,0xE7,
0xA4,0x94,0xD4,0x52,0xE6,0x1C,0x84,0x52,0x52,0x6A,0x2D,0xC6,0xCC,0x39,0x08,0xA5,0xA4,0xD4,0x5A,0x8C,0x99,0x73,0x52,0x62,0x8B,0xB1,0xC7,0x58,0x33,0xE7,0x24,0xB5,
0x16,0x63,0xAD,0xB5,0x76,0x52,0x62,0x8B,0xB1,0xD7,0x9C,0x7B,0xEE,0x24,0xB5,0x18,0x63,0xEC,0xB9,0xF7,0x5A,0x5A,0xAC,0x39,0xD7,0x5A,0x73,0xCF,0xBD,0xA4,0x16,0x63,
0xCE,0xBD,0xF7,0xDA,0x7B,0x8B,0x31,0xD7,0x5C,0x73,0xAE,0xB9,0xF7,0x54,0x6B,0xAE,0x3D,0xF7,0x9A,0x7B,0xCD,0x05,0x00,0xE0,0x34,0x38,0x00,0x80,0x1E,0xD8,0xB0,0x3A,
0xC2,0x49,0xD1,0x58,0x60,0xA1,0x21,0x2B,0x01,0x80,0x54,0x00,0x00,0x02,0x21,0xA5,0x18,0x73,0xCE,0x39,0xE7,0x90,0x52,0x8A,0x39,0xE6,0x9C,0x83,0x10,0x22,0xA5,0x18,
0x73,0xCE,0x39,0xE7,0x1C,0x54,0x8C,0x31,0xE6,0x9C,0x83,0x10,0x42,0xA8,0x18,0x63,0xCC,0x39,0x08,0x21,0x84,0x90,0x39,0xE7,0x9C,0x73,0xD0,0x41,0x08,0x21,0x73,0xCE,
0x39,0xE7,0x20,0x84,0x10,0x42,0xE7,0x20,0x84,0x0E,0x42,0x08,0x21,0x84,0xCE,0x39,0x08,0xA1,0x83,0x10,0x42,0x08,0x1D,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x3A,0x08,
0x21,0x84,0x10,0x42,0x08,0x21,0x74,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x50,0x00,0x00,0x60,0x81,0x03,0x00,0x40,0x80,0x0D,
0xAB,0x23,0x9C,0x14,0x8D,0x05,0x16,0x1A,0xB2,0x12,0x00,0x00,0x02,0x00,0x60,0x1C,0xA6,0x9A,0x4A,0xAD,0x08,0x52,0x8E,0x41,0x6D,0x0D,0x51,0x88,0x49,0x51,0x95,0x52,
0x4A,0x39,0x8F,0x99,0x51,0x46,0x41,0x52,0x95,0x42,0x08,0x31,0x2F,0x1D,0x64,0x50,0x19,0x4B,0xBD,0x28,0x63,0x32,0x0A,0x00,0x00,0x80,0x20,0x00,0x20,0xC0,0x04,0x10,
0x18,0x20,0x28,0xF8,0x42,0x08,0x88,0x31,0x00,0x00,0x41,0x88,0xCC,0x10,0x09,0x85,0x55,0xB0,0xC0,0xA0,0x0C,0x1A,0x1C,0xE6,0x01,0xC0,0x03,0x44,0x84,0x44,0x00,0x90,
0x98,0xA0,0x48,0xBB,0xB8,0x80,0x2E,0x03,0x5C,0xD0,0xC5,0x5D,0x07,0x42,0x08,0x42,0x10,0x82,0x58,0x1C,0x40,0x01,0x09,0x38,0x38,0xE1,0x86,0x27,0xDE,0xF0,0x84,0x1B,
0x9C,0xA0,0x53,0x54,0xEA,0x20,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0xE0,0x01,0x00,0xE0,0xA0,0x00,0x22,0x22,0x9A,0xAB,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,
0x08,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0xF8,0x00,0x00,0x38,0x3E,0x80,0x88,0x88,0xE6,0x2A,0x2C,0x2E,0x30,0x32,0x34,0x36,0x38,0x3A,0x3C,0x02,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x80,0x80,
};
static const uint8_t vcb_3[] = {
0x24,0x42,0x43,0x56,0x01,0x00,0x40,0x00,0x00,0x18,0x42,0x10,0x2A,0x05,0xAD,0x63,0x8E,0x3A,0xC8,0x15,0x21,0x8C,0x19,0xA2,0xA0,0x42,0xCA,0x29,0xC7,0x1D,0x42,0xD0,
0x21,0xA3,0x24,0x43,0x88,0x3A,0xC6,0x35,0xC7,0x18,0x63,0x47,0xB9,0x64,0x8A,0x42,0xC9,0x81,0xD0,0x90,0x55,0x00,0x00,0x40,0x00,0x00,0xA4,0x1C,0x57,0x50,0x72,0x49,
0x2D,0xE7,0x9C,0x73,0xA3,0x18,0x57,0xCC,0x71,0xE8,0x20,0xE7,0x9C,0x73,0xE5,0x20,0x67,0xCC,0x71,0x09,0x25,0xE7,0x9C,0x73,0x8E,0x39,0xE7,0x92,0x72,0x8E,0x31,0xE7,
0x9C,0x73,0xA3,0x18,0x57,0x0E,0x72,0x29,0x2D,0xE7,0x9C,0x73,0x81,0x14,0x47,0x8A,0x71,0xA7,0x18,0xE7,0x9C,0x73,0xA4,0x1C,0x47,0x8A,0x71,0xA8,0x18,0xE7,0x9C,0x73,
0x6D,0x31,0xB7,0x92,0x72,0xCE,0x39,0xE7,0x9C,0x73,0xE6,0x20,0x87,0x52,0x72,0xAE,0x35,0xE7,0x9C,0x73,0xA4,0x18,0x67,0x0E,0x72,0x0B,0x25,0xE7,0x9C,0x73,0xC6,0x20,
0x67,0xCC,0x71,0xEB,0x20,0xE7,0x9C,0x73,0x8C,0x35,0xB7,0xD4,0x72,0xCE,0x39,0xE7,0x9C,0x73,0xCE,0x39,0xE7,0x9C,0x73,0xCE,0x39,0xE7,0x9C,0x73,0x8C,0x31,0xE7,0x9C,
0x73,0xCE,0x39,0xE7,0x9C,0x73,0x6E,0x31,0xE7,0x16,0x73,0xAE,0x39,0xE7,0x9C,0x73,0xCE,0x39,0xE7,0x1C,0x73,0xCE,0x39,0xE7,0x9C,0x73,0x20,0x34,0x64,0x15,0x00,0x90,
0x00,0x00,0xA0,0xA1,0x28,0x8A,0xE2,0x28,0x0E,0x10,0x1A,0xB2,0x0A,0x00,0xC8,0x00,0x00,0x10,0x40,0x71,0x14,0x47,0x91,0x14,0x4B,0xB1,0x1C,0xCB,0xD1,0x24,0x0D,0x08,
0x0D,0x59,0x05,0x00,0x00,0x01,0x00,0x08,0x00,0x00,0xA0,0x48,0x86,0xA4,0x48,0x8A,0xA5,0x58,0x8E,0x66,0x69,0x9E,0x26,0x7A,0xA2,0x28,0x9A,0xA2,0x2A,0xAB,0xB2,0x69,
0xCA,0xB2,0x2C,0xCB,0xB2,0xEB,0xBA,0x2E,0x10,0x1A,0xB2,0x0A,0x00,0x48,0x00,0x00,0x50,0x51,0x14,0xC5,0x70,0x14,0x07,0x08,0x0D,0x59,0x05,0x00,0x64,0x00,0x00,0x08,
0x60,0x28,0x8A,0xA3,0x38,0x8E,0xE4,0x58,0x92,0xA5,0x59,0x9E,0x07,0x84,0x86,0xAC,0x02,0x00,0x80,0x00,0x00,0x04,0x00,0x00,0x50,0x0C,0x47,0xB1,0x14,0x4D,0xF1,0x24,
0xCF,0xF2,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0x0D,0x08,0x0D,0x59,0x05,0x00,0x20,0x00,0x00,0x00,0x82,
0x28,0x64,0x18,0x03,0x42,0x43,0x56,0x01,0x00,0x40,0x00,0x00,0x08,0x21,0x1A,0x19,0x43,0x9D,0x52,0x12,0x5C,0x0A,0x16,0x42,0x1C,0x11,0x43,0x1D,0x42,0xCE,0x43,0xA9,
0xA5,0x83,0xE0,0x29,0x85,0x25,0x63,0xD2,0x53,0xAC,0x41,0x08,0x21,0x7C,0xEF,0x3D,0xF7,0xDE,0x7B,0xEF,0x81,0xD0,0x90,0x55,0x00,0x00,0x10,0x00,0x00,0x61,0x14,0x38,
0x88,0x81,0xC7,0x24,0x08,0x21,0x84,0x62,0x14,0x27,0x44,0x71,0xA6,0x20,0x08,0x21,0x84,0xE5,0x24,0x58,0xCA,0x79,0xE8,0x24,0x08,0xDD,0x83,0x10,0x42,0xB8,0x9C,0x7B,
0xCB,0xB9,0xF7,0xDE,0x7B,0x20,0x34,0x64,0x15,0x00,0x00,0x08,0x00,0xC0,0x20,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x29,0xA4,0x94,0x52,0x48,0x29,0xA6,0x98,
0x62,0x8A,0x29,0xC7,0x1C,0x73,0xCC,0x31,0xC7,0x20,0x83,0x0C,0x32,0xE8,0xA0,0x93,0x4E,0x3A,0xC9,0xA4,0x92,0x4E,0x3A,0xCA,0x24,0xA3,0x8E,0x52,0x6B,0x29,0xB5,0x14,
0x53,0x4C,0xB1,0xE5,0x16,0x63,0xAD,0xB5,0xD6,0x9C,0x73,0xAF,0x41,0x29,0x63,0x8C,0x31,0xC6,0x18,0x63,0x8C,0x31,0xC6,0x18,0x63,0x8C,0x31,0xC6,0x18,0x23,0x08,0x0D,
0x59,0x05,0x00,0x80,0x00,0x00,0x10,0x06,0x19,0x64,0x90,0x41,0x08,0x21,0x84,0x14,0x52,0x48,0x29,0xA6,0x98,0x72,0xCC,0x31,0xC7,0x1C,0x03,0x42,0x43,0x56,0x01,0x00,
0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x1C,0x45,0x52,0x24,0x47,0x72,0x24,0x47,0x92,0x24,0xC9,0x92,0x2C,0x49,0x93,0x3C,0xCB,0xB3,0x3C,0xCB,0xB3,0x3C,0x4D,0xD4,0x44,
0x4D,0x15,0x55,0xD5,0x55,0x6D,0xD7,0xF6,0x6D,0x5F,0xF6,0x6D,0xDF,0xD5,0x65,0xDF,0xF6,0x65,0xDB,0xD5,0x65,0x5D,0x96,0x65,0xDD,0xB5,0x6D,0x5D,0xD6,0x5D,0x5D,0xD7,
0x75,0x5D,0xD7,0x75,0x5D,0xD7,0x75,0x5D,0xD7,0x75,0x5D,0xD7,0x75,0x5D,0xD7,0x81,0xD0,0x90,0x55,0x00,0x80,0x04,0x00,0x80,0x8E,0xE4,0x38,0x8E,0xE4,0x38,0x8E,0xE4,
0x48,0x8E,0xA4,0x48,0x0A,0x10,0x1A,0xB2,0x0A,0x00,0x90,0x01,0x00,0x10,0x00,0x80,0xA3,0x38,0x8A,0xE3,0x48,0x8E,0xE4,0x58,0x8E,0x25,0x59,0x92,0x26,0x69,0x96,0x67,
0x79,0x96,0xA7,0x79,0x9A,0xA8,0x89,0x1E,0x10,0x1A,0xB2,0x0A,0x00,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x80,0xA2,0x28,0x8A,0xA3,0x38,0x8E,0x24,0x59,0x96,
0xA6,0x69,0x9E,0xA7,0x7A,0xA2,0x28,0x9A,0xAA,0xAA,0x8A,0xA6,0xA9,0xAA,0xAA,0x6A,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,
0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x02,0xA1,0x21,0xAB,0x00,0x00,0x09,0x00,0x00,0x1D,0xC7,0x71,0x1C,0x47,0x71,
0x1C,0xC7,0x71,0x24,0x47,0x92,0x24,0x20,0x34,0x64,0x15,0x00,0x20,0x03,0x00,0x20,0x00,0x00,0x43,0x51,0x1C,0x45,0x72,0x2C,0xC7,0x92,0x34,0x4B,0xB3,0x3C,0xCB,0xD3,
0x44,0xCF,0xF4,0x5C,0x51,0x36,0x75,0x53,0x57,0x6D,0x20,0x34,0x64,0x15,0x00,0x00,0x08,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0xC7,0x73,0x3C,0xC7,0x73,0x3C,0xC9,
0x93,0x3C,0xCB,0x73,0x3C,0xC7,0x93,0x3C,0x49,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,
0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0xD3,0x34,0x4D,0x03,0x42,0x43,0x56,0x02,0x00,0x64,0x00,0x00,0x1C,0xB5,0x56,0x73,
0xEF,0xBD,0x87,0x8C,0x39,0x48,0xB1,0xF6,0x1E,0x33,0xA5,0x18,0xB4,0x98,0x7B,0xCE,0x14,0x32,0x4A,0x52,0xED,0xAD,0x63,0x46,0x18,0x26,0xB5,0xA7,0x90,0x21,0x62,0x14,
0xD4,0x9E,0x4A,0xC8,0x10,0x52,0xD0,0x7B,0x29,0xA1,0x53,0x8A,0x49,0xEF,0x29,0xA5,0x52,0x4A,0xAA,0xBD,0xF7,0x5A,0x63,0xED,0xBD,0xF7,0x1E,0x08,0x0D,0x59,0x11,0x00,
0x44,0x01,0x00,0x00,0x08,0x21,0xC6,0x10,0x63,0x88,0x31,0x06,0x21,0x83,0x10,0x31,0xC6,0x20,0x64,0x10,0x22,0xC6,0x1C,0x84,0x0C,0x42,0x06,0x21,0x94,0x12,0x4A,0xC9,
0x20,0x84,0x52,0x42,0x49,0x11,0x73,0x0E,0x42,0x07,0x21,0x83,0x10,0x4A,0x09,0xA1,0x64,0x10,0x42,0x29,0x21,0x95,0x02,0x00,0x00,0x02,0x1C,0x00,0x00,0x02,0x2C,0x84,
0x42,0x43,0x56,0x04,0x00,0x71,0x02,0x00,0x08,0x42,0xCE,0x21,0xC6,0x20,0x44,0x8C,0x41,0x08,0x25,0xA4,0x14,0x42,0x48,0x29,0x62,0x0C,0x42,0xE6,0x9C,0x94,0xCC,0x39,
0x29,0xA5,0x94,0xD6,0x42,0x29,0xA9,0x45,0x8C,0x41,0xC8,0x9C,0x93,0x92,0x39,0x27,0x25,0x94,0xD2,0x52,0x29,0xA5,0xB5,0x50,0x4A,0x6B,0x25,0x95,0xD8,0x42,0x29,0xAD,
0xB5,0xD6,0x6A,0x4D,0xAD,0xC5,0x1A,0x4A,0x69,0x2D,0x94,0xD2,0x5A,0x29,0xA5,0xB5,0xD4,0x5A,0x8D,0x2D,0xB6,0x5A,0x23,0xC6,0x20,0x64,0xCE,0x49,0xC9,0x9C,0x93,0x52,
0x52,0x69,0xAD,0x94,0xD4,0x5A,0xE6,0x9C,0x94,0x0E,0x42,0x4A,0x1D,0x84,0x94,0x52,0x4A,0x2D,0x96,0x94,0x5A,0xCC,0x9C,0x93,0xD2,0x41,0x47,0xA5,0x83,0x90,0x52,0x49,
0x25,0xB6,0x92,0x52,0x8C,0x21,0x95,0x18,0x4B,0x4A,0x31,0x96,0x94,0x62,0x6C,0x2D,0xC6,0xDC,0x5A,0xAC,0x39,0x94,0xD2,0x5A,0x49,0x25,0xB6,0x92,0x52,0x8C,0x29,0xA6,
0x1A,0x5B,0x8C,0x39,0x47,0x8C,0x41,0xC8,0x9C,0x93,0x92,0x39,0x27,0xA5,0x94,0xD2,0x5A,0x29,0xA9,0xB5,0xCC,0x39,0x29,0x1D,0x84,0x94,0x3A,0x07,0x25,0x95,0x94,0x62,
0x2C,0x25,0xB5,0x98,0x39,0x27,0xA9,0x83,0x90,0x52,0x07,0x21,0xA5,0x92,0x52,0x6C,0x29,0xA5,0xD8,0x42,0x29,0xAD,0x95,0x94,0x62,0x2C,0x25,0xB5,0xD8,0x62,0xCC,0x35,
0xA5,0xD8,0x6A,0x29,0x29,0xC6,0x92,0x52,0x8C,0x25,0xA5,0x18,0x5B,0x8C,0xB5,0xB6,0xD8,0x6A,0xEC,0x24,0xB4,0x16,0x52,0x89,0x31,0x94,0xD2,0x62,0x8B,0xB1,0xD6,0xD6,
0x62,0xAD,0x21,0x95,0x18,0x4B,0x4A,0x31,0x96,0x94,0x62,0x6C,0x31,0xE6,0x1C,0x63,0xAC,0x39,0x94,0xD2,0x62,0x49,0x25,0xB6,0x92,0x52,0x8C,0x2D,0xB6,0x5C,0x63,0x8C,
0x35,0xA7,0xD6,0x72,0x6D,0x2D,0xE6,0xDC,0x62,0xCC,0xB5,0xC6,0x5C,0x7B,0xAC,0xB9,0xF7,0xD4,0x5A,0xAD,0xA9,0xB5,0x5C,0x5B,0x8C,0x39,0xC7,0x1A,0x7B,0xAD,0xB5,0xF6,
0xDE,0x41,0x68,0x2D,0x94,0x12,0x5B,0x28,0x25,0xC6,0xD6,0x5A,0xAD,0xAD,0xC5,0x9C,0x43,0x29,0xB1,0x95,0x94,0x62,0x2C,0x25,0xC5,0xDA,0x62,0xCC,0xB9,0xB5,0x58,0x73,
0x28,0x25,0xC6,0x92,0x52,0x8C,0x25,0xA5,0x18,0x5B,0x8C,0xB5,0xC6,0x1A,0x73,0x4D,0xAD,0xD5,0xDA,0x62,0xCC,0x35,0xB5,0x56,0x73,0xAD,0xB5,0xE7,0xD8,0x6A,0xED,0xA9,
0xC5,0x9A,0x5B,0x8C,0xB5,0xB7,0xD8,0x72,0x8D,0xB9,0xF6,0x5E,0x73,0xEC,0xB1,0x00,0x00,0x80,0x01,0x07,0x00,0x80,0x00,0x13,0xCA,0x40,0xA1,0x21,0x2B,0x01,0x80,0x28,
0x00,0x00,0xC2,0x18,0xA5,0x18,0x83,0xD0,0x20,0xA4,0x94,0x63,0x10,0x1A,0x84,0x94,0x62,0x0E,0x42,0xA5,0x14,0x63,0xCE,0x49,0xA9,0x94,0x62,0xCC,0x39,0x28,0x99,0x63,
0xCE,0x41,0x28,0x25,0x73,0xCE,0x39,0x08,0xA5,0x84,0x10,0x4A,0x28,0x25,0xA5,0x10,0x42,0x29,0xA5,0xA4,0x54,0x00,0x00,0x40,0x81,0x03,0x00,0x40,0x80,0x0D,0x9A,0x12,
0x8B,0x03,0x14,0x1A,0xB2,0x12,0x00,0x08,0x09,0x00,0x20,0x8C,0x51,0x8A,0x31,0xE7,0x20,0x94,0x92,0x52,0x4A,0x11,0x42,0x8C,0x39,0x07,0x21,0x84,0x52,0x52,0x6A,0x29,
0x42,0x88,0x31,0xE7,0x20,0x84,0x50,0x4A,0x4A,0xAD,0x55,0x8C,0x31,0xE6,0x1C,0x84,0x10,0x4A,0x49,0xA9,0xB5,0x8A,0x31,0xC6,0x9C,0x83,0x10,0x42,0x29,0x29,0xB5,0x96,
0x39,0xE7,0x1C,0x84,0x10,0x4A,0x49,0xA9,0xB5,0xD6,0x32,0xE7,0x9C,0x83,0x10,0x42,0x29,0x29,0xA5,0xD6,0x5A,0x08,0x21,0x84,0x50,0x4A,0x29,0x25,0xA5,0xD6,0x62,0xEC,
0x20,0x84,0x50,0x42,0x29,0xA5,0xA4,0xD4,0x5A,0x8C,0x21,0x84,0x10,0x4A,0x29,0x25,0xA5,0xD4,0x5A,0x8B,0x31,0x84,0x10,0x42,0x29,0xA5,0xA4,0xD4,0x52,0x6B,0x31,0x96,
0x52,0x4A,0x49,0x29,0xA5,0xD4,0x5A,0x6B,0x31,0xD6,0x52,0x4A,0x29,0x29,0xA5,0xD4,0x52,0x6B,0xB1,0xC5,0x98,0x52,0x4A,0xA9,0xB5,0xD6,0x5A,0x8B,0x31,0xC6,0x5A,0x53,
0x4A,0x29,0xB5,0xD6,0x5A,0x6B,0xB1,0xC5,0x58,0x6B,0x6A,0xAD,0xB5,0xD6,0x62,0x8C,0x31,0xC6,0x5A,0x6B,0x4D,0xAD,0xB5,0xD6,0x5A,0x8C,0x31,0xD6,0x58,0x6B,0xAD,0x05,
0x00,0x00,0x1C,0x38,0x00,0x00,0x04,0x18,0x41,0x27,0x19,0x55,0x16,0x61,0xA3,0x09,0x17,0x1E,0x80,0x42,0x43,0x56,0x04,0x00,0x51,0x00,0x00,0x80,0x31,0x88,0x31,0xC4,
0x18,0x82,0x8E,0x49,0xC8,0x24,0x44,0x0E,0x32,0x28,0x19,0x94,0x06,0x42,0x48,0xA9,0xA3,0x94,0x51,0x2A,0x25,0x96,0x1A,0x33,0x4A,0x25,0xA6,0x12,0x6B,0x04,0xA1,0xA3,
0x14,0x52,0xCA,0x28,0x95,0x1A,0x4B,0xAB,0x19,0xA5,0x12,0x63,0x89,0xA5,0x00,0x00,0xB0,0x03,0x07,0x00,0xB0,0x03,0x0B,0xA1,0xD0,0x90,0x95,0x00,0x40,0x1E,0x00,0x00,
0x81,0x90,0x52,0x8C,0x39,0xE7,0x1C,0x42,0x88,0x31,0xC6,0x9C,0x73,0x0E,0x21,0xC5,0x18,0x63,0xCE,0x39,0xA7,0x18,0x63,0xCC,0x39,0xE7,0x9C,0x53,0x8C,0x31,0xE6,0x9C,
0x73,0xCE,0x31,0xC6,0x9C,0x73,0x0E,0x42,0x08,0x19,0x63,0xCE,0x39,0x07,0x21,0x84,0xCE,0x39,0xE7,0x20,0x84,0x10,0x42,0xE7,0x9C,0x73,0x10,0x42,0x08,0xA1,0x73,0xCE,
0x39,0x08,0x21,0x84,0xD0,0x39,0xE7,0x1C,0x84,0x10,0x42,0x28,0x00,0x00,0xA8,0xC0,0x01,0x00,0x20,0xC0,0x46,0x91,0xCD,0x09,0x46,0x82,0x0A,0x0D,0x59,0x09,0x00,0xA4,
0x02,0x00,0x00,0xC6,0x30,0xE6,0x9C,0x73,0x10,0x4A,0x69,0x94,0x72,0x0E,0x42,0x08,0xA5,0xB4,0xD4,0x28,0xE5,0x1C,0x84,0x10,0x4A,0x49,0x2D,0x73,0x0E,0x42,0x29,0xA5,
0xB4,0x16,0x5B,0xE6,0x1C,0x84,0x52,0x4A,0x49,0xAD,0xB5,0x0E,0x42,0x29,0x29,0xA5,0xD4,0x5A,0x8C,0x1D,0x84,0x52,0x52,0x4A,0xA9,0xC5,0x18,0x3B,0x08,0xA5,0xA4,0xD4,
0x5A,0x8C,0xB5,0x76,0x10,0x4A,0x49,0xA9,0xB5,0x18,0x6B,0x0D,0xA5,0xA4,0x16,0x5B,0xAC,0xB5,0xD6,0x1A,0x4A,0x49,0xAD,0xC5,0x18,0x6B,0xAD,0xB5,0xA4,0xD4,0x5A,0x8C,
0xB5,0xE6,0x9C,0x73,0x49,0xA9,0xB5,0x18,0x6B,0xAD,0x35,0xE7,0x02,0x00,0xC0,0x13,0x1C,0x00,0x80,0x0A,0x6C,0x58,0x1D,0xE1,0xA4,0x68,0x2C,0xB0,0xD0,0x90,0x95,0x00,
0x40,0x06,0x00,0x00,0x61,0x0C,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x94,0x42,0x08,0x29,0x25,0x00,0x00,0x60,0xC0,0x01,0x00,0x20,0xC0,0x84,0x32,0x50,0x68,
0xC8,0x4A,0x00,0x20,0x15,0x00,0x00,0x30,0x86,0x31,0xC6,0x9C,0x83,0x50,0x4A,0xA3,0x14,0x84,0x10,0x42,0x28,0x25,0xA5,0x46,0x29,0x07,0x21,0x84,0x50,0x52,0x4B,0x99,
0x83,0x52,0x4A,0x49,0x25,0xB5,0x16,0x33,0x08,0xA5,0x94,0x52,0x4A,0x6A,0x31,0x66,0xD0,0x49,0x49,0x29,0xB5,0x16,0x63,0xCD,0x20,0x94,0x92,0x52,0x6A,0x31,0xC6,0xD8,
0x41,0x28,0x29,0xB5,0xD6,0x62,0x8C,0xB1,0x83,0x50,0x52,0x4A,0xAD,0xC5,0x58,0x6B,0x28,0xA5,0xA5,0x16,0x63,0xAC,0x31,0xC6,0x50,0x4A,0x4A,0xAD,0xC5,0x1A,0x63,0x8D,
0x25,0xA5,0x16,0x6B,0xAD,0xB9,0xD6,0x5A,0x4B,0x4A,0xAD,0xC5,0x18,0x6B,0xAD,0xB9,0x16,0x00,0x80,0xD0,0xE0,0x00,0x00,0x76,0x60,0xC3,0xEA,0x08,0x27,0x45,0x63,0x81,
0x85,0x86,0xAC,0x04,0x00,0xF2,0x00,0x00,0x10,0x84,0x94,0x62,0x8C,0x31,0xC6,0x90,0x52,0x8C,0x31,0xC6,0x98,0x73,0x48,0x29,0xA5,0x18,0x63,0xCC,0x39,0xA5,0x18,0x63,
0x8E,0x39,0xE7,0x9C,0x62,0x8C,0x31,0xC6,0x9C,0x73,0x8E,0x31,0xC6,0x98,0x73,0xCE,0x39,0xC7,0x18,0x63,0xCE,0x39,0xE7,0x9C,0x63,0x8C,0x39,0xE7,0x9C,0x73,0xCE,0x31,
0xC6,0x9C,0x73,0xCE,0x39,0xE7,0x98,0x73,0xCE,0x39,0xE7,0x9C,0x73,0xCC,0x39,0xE7,0x9C,0x73,0xCE,0x39,0x01,0x00,0x40,0x05,0x0E,0x00,0x00,0x01,0x36,0x8A,0x6C,0x4E,
0x30,0x12,0x54,0x68,0xC8,0x4A,0x00,0x20,0x1C,0x00,0x00,0x40,0x88,0x31,0xE7,0x18,0x73,0x4E,0x42,0x4A,0x8D,0x52,0xCE,0x49,0x08,0x1D,0x84,0x52,0x5A,0x6D,0x14,0x73,
0x10,0x4A,0xE8,0x20,0x94,0xD6,0x52,0xE6,0x9C,0x94,0x52,0x42,0x28,0x25,0xC5,0xD8,0x32,0xE7,0x20,0xA5,0x12,0x42,0x2A,0x2D,0xA5,0xDA,0x41,0x48,0x25,0xA5,0x52,0x52,
0x8A,0xAD,0xB6,0x0E,0x42,0x6A,0x29,0x95,0xD2,0x52,0x6B,0xAD,0x66,0xCE,0x41,0x28,0xA5,0xA4,0x96,0x62,0xAC,0x2D,0x73,0x10,0x42,0x29,0x29,0xA5,0xD6,0x6A,0xAD,0x9D,
0x84,0x92,0x52,0x4A,0xB5,0xB5,0x58,0x6B,0x0C,0x21,0x94,0x94,0x52,0x6B,0xAD,0xB6,0x1A,0x6B,0x29,0xA5,0xA5,0x96,0x6A,0xAC,0xB1,0xD6,0x58,0x43,0x29,0xA9,0xA5,0xD8,
0x62,0xAC,0xB5,0xC6,0x5A,0x62,0x6C,0x2D,0xB5,0x1A,0x6B,0xAC,0xAD,0xC6,0x92,0x52,0x4B,0xAD,0xD5,0x5A,0x63,0xAD,0xB5,0x16,0x00,0x60,0xF2,0xE0,0x00,0x00,0x95,0x60,
0xE3,0x0C,0x2B,0x49,0x67,0x85,0xA3,0xC1,0x85,0x86,0xAC,0x04,0x00,0x72,0x03,0x00,0x08,0x84,0x18,0x73,0xCE,0x39,0x08,0x25,0x94,0x10,0x42,0x29,0xA5,0x44,0x4A,0x31,
0xE6,0x1C,0x84,0x10,0x4A,0x28,0xA5,0x94,0x52,0x52,0x89,0x94,0x62,0xCC,0x39,0x07,0xA1,0x94,0x52,0x4A,0x29,0xA5,0x94,0x92,0x31,0xE6,0x1C,0x74,0x10,0x4A,0x28,0xA5,
0x94,0x52,0x52,0x49,0x25,0x63,0xCC,0x39,0x07,0x21,0x94,0x50,0x4A,0x29,0xA5,0x94,0x52,0x4A,0xE7,0x1C,0x84,0x10,0x4A,0x28,0xA5,0x94,0x52,0x4A,0x2A,0x25,0x95,0xCE,
0x39,0x07,0x21,0x84,0x52,0x4A,0x29,0xA5,0x94,0x92,0x52,0x29,0x1D,0x84,0x10,0x42,0x28,0xA5,0x94,0x52,0x52,0x49,0x25,0x95,0x54,0x3A,0x08,0x21,0x84,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x52,0x2A,0xA5,0x84,0x12,0x42,0x29,0x25,0x95,0x52,0x4A,0x29,0xA5,0xA4,0x94,0x52,0x0A,0x21,0x94,0x50,0x4A,0x29,0xA5,0xA4,0x92,0x4A,0x4A,0x29,0x95,
0x12,0x4A,0x28,0xA5,0x94,0x54,0x4A,0x29,0x25,0x95,0x54,0x52,0x29,0x29,0x94,0x52,0x4A,0x29,0xA5,0x94,0x54,0x4A,0x4A,0x25,0xA5,0x94,0x52,0x08,0xA5,0x94,0x52,0x52,
0x29,0xA9,0x94,0x54,0x4A,0x4A,0x29,0xA5,0x50,0x4A,0x29,0xA5,0x94,0x54,0x52,0x49,0x25,0xA5,0x94,0x52,0x49,0xA5,0x94,0x52,0x4A,0x29,0x25,0xA5,0x94,0x52,0x4A,0x29,
0x95,0x94,0x4A,0x29,0xA5,0xA4,0x52,0x4A,0x2A,0x29,0xA5,0x54,0x5A,0x4A,0xA9,0x94,0x52,0x4A,0x49,0xA5,0x94,0x94,0x5A,0x4A,0x29,0xA5,0x94,0x52,0x2A,0xA5,0xA4,0x92,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x54,0x4A,0x49,0x25,0x95,0x92,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0xA5,0x94,0x52,0x4A,0x49,0xA9,0xA4,0x54,0x52,0x2A,
0x29,0xA5,0x92,0x52,0x01,0x00,0x40,0x07,0x0E,0x00,0x00,0x01,0x46,0x54,0x5A,0x88,0x9D,0x66,0x5C,0x79,0x04,0x8E,0x28,0x64,0x98,0x80,0x0A,0x0D,0x59,0x09,0x00,0x84,
0x03,0x00,0x00,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x89,0x8C,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,
0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x1A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x54,0x0A,0x49,0x29,0x25,0x84,0x10,0x42,0x08,0x21,0x42,0x02,0x40,0xBA,0x32,0x1C,0x00,0x00,0x02,0xAC,0x49,0x57,0x2F,0x52,0x5D,0xC6,0xE8,0x60,
0x74,0xE9,0xCA,0x2E,0x68,0x74,0x78,0x91,0xA3,0x43,0x00,0x0A,0x00,0x90,0xAE,0x91,0xD5,0x84,0x25,0x34,0x64,0x25,0x00,0x90,0x16,0x00,0x00,0x58,0x69,0xA5,0x95,0x96,
0x5A,0x6B,0xAD,0xB5,0xD6,0x22,0x04,0xA5,0xA5,0xD4,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0x25,0x84,0x14,0x52,0x6A,0xA9,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xCE,0x49,0x0A,
0x2D,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0xE8,0x24,0xB5,0xD4,0x52,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0x83,0x94,0x4A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,
0x16,0x4A,0x6A,0xA9,0xA5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x0B,0x21,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,
0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0xAD,
0xB5,0xD6,0x5A,0x6B,0xAD,0xB5,0xD6,0x5A,0x6B,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,
0x29,0xA5,0x94,0x52,0x8A,0x1C,0x84,0x8E,0x42,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x11,0x32,0xCE,0x39,0x27,0xA1,0x94,0x94,0x52,0x4A,0x29,0xA5,0xC8,0x08,0x00,0x40,0x8C,
0x70,0x00,0x00,0x08,0xB0,0x84,0xD8,0x55,0xB9,0x99,0xA4,0x5E,0x3D,0x1B,0x12,0xC3,0xE4,0x24,0x7D,0x8A,0xE1,0x6A,0x0C,0xDF,0x02,0x00,0x31,0x61,0x8C,0x09,0x0D,0x59,
0x05,0x00,0xC4,0x00,0x00,0x00,0x84,0x18,0xC6,0x98,0x63,0x8C,0x31,0xE7,0x9C,0x63,0xCE,0x39,0xE7,0x9C,0x73,0x8E,0x41,0xE8,0x20,0x84,0xCE,0x39,0xE7,0x9C,0x73,0xCE,
0x39,0x67,0xAD,0xA4,0x02,0x00,0x00,0x13,0x1C,0x00,0x00,0x02,0xAC,0x60,0x57,0x66,0x69,0xD5,0x46,0x71,0x53,0x27,0x79,0xD1,0x07,0x81,0x4F,0xE8,0x88,0xCD,0xC8,0x90,
0x4B,0xA9,0x98,0xC9,0x89,0xA0,0x47,0x6A,0xA8,0xC5,0x4A,0xB0,0x43,0x2B,0xB8,0xC1,0x0B,0xC0,0x42,0x43,0x56,0x02,0x00,0x64,0x00,0x00,0x10,0x93,0x52,0x52,0x8A,0x45,
0x59,0x08,0x29,0xE6,0xA0,0x25,0xE5,0x21,0x63,0x14,0x83,0x98,0x94,0x87,0x8C,0x41,0xCA,0x59,0x50,0x1A,0x42,0xC6,0x20,0x66,0xC5,0x78,0x8C,0x29,0x84,0x94,0x14,0x23,
0x42,0xE8,0x14,0x52,0x50,0x8C,0x8A,0x31,0x76,0x8C,0x41,0x2F,0x32,0x18,0x9F,0x42,0x08,0xC1,0xE8,0x62,0x8C,0x8E,0xB1,0x16,0x23,0x00,0x00,0x00,0x41,0x00,0x80,0x80,
0x90,0x00,0x00,0x03,0x04,0x05,0x33,0x00,0xC0,0xE0,0x00,0x61,0xE4,0x40,0xA0,0x23,0x80,0xC0,0xA1,0x0D,0x00,0x30,0x10,0x21,0x33,0x81,0x41,0x21,0x34,0x38,0xC8,0x04,
0x80,0x07,0x88,0x08,0xA9,0x00,0x20,0x31,0x41,0x51,0xBA,0xD0,0x05,0x21,0x44,0x90,0x2E,0x82,0x2C,0x1E,0xB8,0x70,0xE2,0xC6,0x13,0x37,0x9C,0xD0,0xA1,0x0D,0x02,0x00,
0x00,0x00,0x00,0x00,0x02,0x00,0x3E,0x00,0x00,0x12,0x0A,0x20,0x22,0x9A,0x99,0xB9,0x0A,0x8B,0x0B,0x8C,0x0C,0x8D,0x0D,0x8E,0x0E,0x8F,0x0F,0x90,0x10,0x91,0x91,0x00,
0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x0F,0x00,0x80,0x84,0x04,0x88,0x88,0x66,0x66,0xAE,0xC2,0xE2,0x02,0x23,0x43,0x63,0x83,0xA3,0xC3,0xE3,0x03,0x24,0x44,0x64,0x24,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x08,
};
static const uint8_t vcb_4[] = {
0x29,0x42,0x43,0x56,0x01,0x00,0x08,0x00,0x00,0x80,0x22,0x4C,0x20,0xC3,0x80,0xD0,0x90,0x55,0x00,0x00,0x10,0x00,0x00,0x80,0xA8,0x36,0x14,0x6B,0xA9,0xB1,0xD6,0x1A,
0x63,0xA1,0x28,0x46,0xD4,0x62,0x6A,0x31,0xC6,0x18,0x63,0xE3,0x2C,0x46,0x90,0x62,0x8B,0x31,0xC6,0x18,0x63,0x8C,0x31,0xC6,0x18,0x63,0x8C,0x31,0xC6,0x18,0x63,0x20,
0x34,0x64,0x15,0x00,0x00,0x04,0x00,0x40,0x31,0xEA,0x15,0x93,0x9E,0x42,0xCC,0x39,0xE7,0xDC,0x18,0xA6,0x8D,0x51,0xDA,0x29,0xC7,0x39,0xE7,0xDC,0x18,0xC5,0x89,0x30,
0x58,0x21,0xA5,0xB9,0xA5,0x9A,0x52,0xCC,0xA1,0x93,0x9C,0x4A,0xCA,0x39,0xE7,0x1C,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x40,0x48,0x21,0x85,0x14,0x52,0x48,0x21,
0x85,0x14,0x52,0x48,0x21,0x85,0x14,0x52,0x4A,0x29,0xA5,0x94,0x62,0x8A,0x29,0xA6,0x98,0x62,0x8A,0x29,0xA6,0x98,0x72,0xCC,0x31,0xC7,0x1C,0x83,0x0C,0x32,0xE8,0xA4,
0x93,0x4E,0x3A,0xE9,0x24,0xA4,0x90,0x42,0x09,0xA5,0xA4,0x92,0x52,0x4A,0xAD,0xC5,0x1A,0x6B,0xEF,0xBD,0xF7,0x9E,0x7B,0xEF,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,0xDE,
0x7B,0xEF,0xBD,0xF7,0xDE,0x7B,0xCF,0x39,0x07,0x42,0x43,0x56,0x01,0x00,0x20,0x00,0x00,0x04,0x42,0x06,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x14,0x52,0x48,0x21,0xA6,
0x98,0x62,0xCA,0x29,0xA7,0x80,0xD0,0x90,0x55,0x00,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x00,0x4B,0xB1,0x14,0x4D,0xD1,0x1C,0xCF,0xF1,0x1C,0xCF,0x11,0x1D,0x53,0x12,
0x25,0x53,0x32,0x25,0x53,0x72,0x2D,0xD7,0x32,0x2D,0x53,0x33,0x3D,0xD3,0x33,0x45,0x55,0x74,0x55,0x53,0x55,0x65,0xD7,0x75,0x65,0x53,0x36,0x65,0x53,0x36,0x65,0x55,
0x36,0x65,0x53,0x36,0x65,0x53,0x36,0x65,0xD5,0x95,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x20,0x34,0x64,0x15,0x00,0x20,
0x01,0x00,0xA0,0x23,0x39,0x92,0x23,0x29,0x8E,0xE2,0x38,0x8E,0xE3,0x48,0x92,0x04,0x84,0x86,0xAC,0x02,0x00,0x64,0x00,0x00,0x04,0x00,0x60,0x28,0x8A,0xA3,0x48,0x8E,
0x24,0x59,0x92,0x65,0x59,0x96,0x67,0x99,0x9A,0xE9,0x99,0x9E,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x09,0x84,0x86,0xAC,0x02,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,
0x00,0xA0,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0xA6,0x69,0x9A,0x66,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,
0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x96,0x65,0x59,0x40,0x68,0xC8,0x2A,
0x00,0x40,0x02,0x00,0x40,0xC7,0x71,0x1C,0xC7,0x71,0x1C,0xC7,0x71,0x1C,0x47,0x72,0x24,0x07,0x08,0x0D,0x59,0x05,0x00,0xC8,0x00,0x00,0x08,0x00,0x40,0x52,0x24,0xC5,
0x72,0x34,0x47,0x73,0x34,0xC7,0x73,0x3C,0x47,0x74,0x44,0x47,0x94,0x4C,0x49,0x95,0x5C,0x4B,0xB6,0x64,0x0D,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x08,0x00,0x00,
0x00,0x00,0x00,0x40,0x33,0x2C,0x43,0x53,0x3C,0x47,0xB3,0x44,0x4D,0xD4,0x44,0x51,0xF4,0x44,0x4F,0x14,0x45,0xD1,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,
0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x3C,0xCF,0xF3,0x80,0xD0,
0x90,0x55,0x00,0x00,0x04,0x00,0x00,0x01,0x9D,0x66,0x98,0x6A,0x80,0x08,0x33,0x92,0x59,0x20,0x34,0x64,0x15,0x00,0x80,0x00,0x00,0x00,0x10,0x81,0x0C,0x53,0x0C,0x08,
0x0D,0x59,0x05,0x00,0x00,0x04,0x00,0x00,0x48,0x91,0xE4,0x24,0x89,0x92,0x93,0x52,0x4A,0x39,0x0C,0x92,0xC5,0x24,0xA9,0x94,0x93,0x52,0x4A,0x79,0x14,0x93,0x47,0x35,
0xC9,0x18,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0x0C,0x92,0xE5,0x28,0xA9,0x94,0x93,0x52,0x4A,0x49,0x8C,0x92,0xC5,0x28,0xA9,0x52,
0x93,0x52,0x4A,0x79,0x94,0x93,0x27,0x35,0xC9,0xD8,0x93,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x59,0x90,0x92,0x27,0x2D,0xE9,0x1A,0x94,0x52,
0x4A,0x49,0x8E,0x92,0x06,0x2D,0xD9,0xD4,0x93,0x52,0x4A,0x89,0x52,0x94,0x28,0x39,0xD9,0x9E,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0xF9,
0xA0,0x94,0x0F,0x42,0x29,0xA5,0x94,0x52,0x4A,0xB9,0xDA,0x93,0x6B,0x3D,0x29,0xA5,0x94,0x52,0x4A,0x19,0xA3,0x94,0xF0,0x49,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0xCA,0x08,0x42,0x43,0x56,0x01,0x00,0x40,0x00,0x00,0x80,0x71,0xD6,0x28,0x87,0xA2,0x93,0xE8,0x7C,0x71,0x86,0x72,0xA6,0x29,0x48,0x2A,
0x94,0x26,0x74,0x6F,0x92,0xA3,0xE4,0x39,0xC9,0xAD,0xB4,0xDC,0x9C,0x6E,0xC2,0x39,0xA7,0x9B,0x53,0xCE,0xF9,0xE4,0x9C,0x73,0x82,0xD0,0x90,0x55,0x00,0x00,0x20,0x00,
0x00,0x84,0x10,0x52,0x48,0x21,0x85,0x14,0x52,0x48,0x21,0x85,0x14,0x52,0x88,0x21,0x86,0x18,0x72,0xC8,0x29,0xA7,0xA0,0x82,0x0A,0x2A,0xA9,0xA4,0xA2,0x8A,0x2A,0xAA,
0xAC,0xB2,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x32,0xEB,0xAC,0xA3,0x8E,0x3A,0x0B,0x29,0x84,0x92,0x42,0x0B,0xAD,0xD5,0x18,0x6B,0x8C,0xB1,0xD5,
0xDE,0x9C,0xB4,0x35,0x47,0x29,0x9D,0x94,0x52,0x4A,0x29,0xA5,0x94,0xCE,0x39,0xE7,0x9C,0x20,0x34,0x64,0x15,0x00,0x00,0x02,0x00,0x40,0x20,0x64,0x90,0x41,0x06,0x19,
0x65,0x14,0x52,0x88,0x21,0xA6,0x9C,0x72,0xCA,0x29,0xA8,0xA4,0x92,0x0A,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x08,0x00,0x00,0x00,0x10,0x25,0xD3,0x31,0x1D,0xD1,
0x11,0x15,0xD1,0x11,0x1D,0xD1,0x11,0x1D,0xD1,0x11,0x1D,0xCF,0xF1,0x1C,0x4F,0x12,0x25,0xD1,0xF2,0x2C,0x51,0x33,0x3D,0x53,0x34,0x4D,0xD3,0x55,0x65,0x57,0x96,0x75,
0xD9,0x96,0x6D,0x57,0x97,0x75,0x5B,0x97,0x7D,0xDB,0xB7,0x75,0xDB,0xB6,0x7D,0xDD,0xD8,0x8D,0xDF,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,
0x8E,0x63,0x08,0x42,0x43,0x56,0x01,0x00,0x20,0x00,0x00,0x00,0x42,0x08,0x21,0x84,0x14,0x52,0x48,0x21,0x85,0x94,0x62,0x8A,0x31,0xE7,0xA0,0x83,0x10,0x42,0x29,0x81,
0xD0,0x90,0x55,0x00,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x00,0x45,0x71,0x14,0xC7,0x91,0x1C,0x49,0x92,0x24,0x4B,0xB2,0x2C,0xCD,0xD2,0x34,0x4D,0xD3,0x34,0x4F,0xF4,
0x44,0xCF,0xF4,0x54,0xCF,0x15,0x65,0xD1,0x16,0x6D,0xCF,0xF5,0x6C,0xD1,0xF6,0x5C,0x4F,0xF5,0x54,0x4F,0x15,0x55,0x53,0x35,0x5D,0xD3,0x55,0x5D,0xD7,0x75,0x5D,0xD5,
0x55,0x65,0x55,0x76,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x65,0x20,0x34,0x64,0x15,0x00,0x20,0x01,0x00,0xA0,0x23,0x39,0x92,
0x22,0x29,0x92,0x22,0x39,0x8E,0x23,0x39,0x92,0x04,0x84,0x86,0xAC,0x02,0x00,0x64,0x00,0x00,0x04,0x00,0xA0,0x28,0x8A,0xE2,0x38,0x8E,0xE4,0x58,0x92,0x25,0x69,0x92,
0x28,0x99,0x96,0x6A,0xB9,0x9A,0xEC,0xE9,0x9E,0x2E,0xEA,0xA2,0x0E,0x84,0x86,0xAC,0x02,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x60,0x88,0x86,0x68,0x88,
0x8E,0x68,0x89,0x9A,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,
0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0x9E,0xE7,0x79,0x9E,0xE7,0x79,0x9E,0xE7,0x79,0x40,0x68,0xC8,0x2A,0x00,0x40,0x02,0x00,0x40,0x47,
0x72,0x24,0xC7,0x52,0x2C,0x45,0x52,0x24,0xC5,0x72,0x2C,0x07,0x08,0x0D,0x59,0x05,0x00,0xC8,0x00,0x00,0x08,0x00,0xC0,0x31,0x1C,0x43,0x52,0x24,0xC7,0xB2,0x2C,0x4B,
0xD3,0x34,0xCF,0xF3,0x3C,0x4F,0xF4,0x44,0x51,0x14,0x45,0xD3,0x54,0x4D,0x15,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x40,0x51,0x14,
0xCB,0xB1,0x1C,0x49,0xD2,0x1C,0x4F,0x12,0x1D,0x51,0x12,0x25,0xD1,0x12,0x25,0x51,0x13,0x35,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,
0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x81,0xD0,0x90,0x95,0x00,0x00,0x19,0x00,
0x00,0x03,0xB1,0xF5,0xD4,0x72,0xEE,0x8D,0xA0,0x48,0x2A,0x47,0xB5,0xC6,0xD4,0x51,0xE6,0x24,0x06,0x61,0x1A,0x8A,0xA0,0x82,0x18,0x84,0x0C,0x15,0x44,0x88,0x51,0x0E,
0x26,0x62,0x0A,0x19,0x26,0x39,0x97,0x0C,0x3A,0xA6,0x98,0xD4,0x18,0x4B,0x2A,0x1D,0x73,0x52,0x6B,0x4B,0x25,0x54,0x48,0x41,0x0C,0x36,0xA6,0x52,0x29,0xE5,0xA8,0x07,
0x42,0x43,0x56,0x08,0x00,0xA1,0x19,0x00,0x0E,0xC7,0x01,0x24,0xCD,0x02,0x24,0x4B,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x49,0xD3,0x00,0xCD,0xF3,0x00,0xCD,0xF3,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xD2,0x34,0xC0,0xF2,0x3C,0x40,0xF3,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x4D,0x03,0x34,0xD1,0x03,0x34,0xCF,0x03,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x4D,0xF4,0x00,0x4F,0x34,0x01,0x4F,0x14,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xF2,0x3C,0xC0,0x33,0x3D,0xC0,0x13,0x4D,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x1C,0x4D,0x03,0x34,0xCF,0x03,0x34,0xCF,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCB,0xF3,0x00,0xCF,0x14,0x01,0xCF,0x33,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x40,
0xF3,0x44,0xC0,0x13,0x45,0xC0,0x33,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x0E,0x00,0x00,0x01,0x16,0x42,0xA1,0x21,0x2B,0x02,0x80,0x38,0x01,
0x00,0x87,0x24,0x41,0x92,0x20,0x49,0xD0,0x34,0x80,0x64,0x59,0xF0,0x34,0x68,0x1A,0x4C,0x13,0x20,0x59,0x16,0x34,0x0D,0x9A,0x06,0xD3,0x04,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x40,0xD2,0x34,0x68,0x1A,0x34,0x0D,0xA2,0x08,0x90,0x34,0x0D,0x9A,0x06,0x4D,0x83,0x28,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,
0x79,0x1A,0x34,0x0D,0x9A,0x06,0x51,0x04,0x48,0x9A,0x07,0x4D,0x83,0xA6,0x41,0x14,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xD0,0x4C,0x13,0xA2,0x08,0x51,
0x84,0x69,0x02,0x34,0xD3,0x84,0x28,0x42,0x14,0x61,0x9A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x80,0x00,0x00,0x80,0x01,0x07,0x00,0x80,0x00,0x13,0xCA,0x40,0xA1,0x21,0x2B,0x02,0x80,0x38,0x01,0x00,0x87,0xE2,0x58,0x16,0x00,0x00,0x38,0x92,0x63,0x59,0x00,
0x00,0xE0,0x38,0x8E,0x65,0x01,0x00,0x80,0x65,0x59,0x9A,0x06,0x00,0x00,0x96,0x65,0x69,0x1A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x80,0x01,0x07,0x00,0x80,0x00,0x13,0xCA,0x40,0xA1,0x21,
0x2B,0x01,0x80,0x28,0x00,0x00,0x87,0xA2,0x58,0x16,0x70,0x1C,0xCB,0x02,0x8E,0x63,0x59,0x40,0x92,0x2C,0x0B,0x60,0x59,0x00,0xCD,0x03,0x68,0x1A,0x40,0x14,0x01,0x80,
0x00,0x00,0x80,0x02,0x07,0x00,0x80,0x00,0x1B,0x34,0x25,0x16,0x07,0x28,0x34,0x64,0x25,0x00,0x10,0x05,0x00,0xE0,0x50,0x14,0xCB,0xD2,0x34,0x51,0xE4,0x38,0x9A,0xA6,
0x69,0xA2,0xC8,0x71,0x34,0x4D,0xD3,0x44,0x91,0x65,0x69,0x9A,0xE7,0x99,0x26,0x34,0xCD,0xF3,0x4C,0x13,0x9E,0xE7,0x79,0xA6,0x09,0xCF,0xF3,0x3C,0xD3,0x84,0x69,0x8A,
0xA2,0xAA,0x02,0x51,0x54,0x55,0x01,0x00,0x00,0x05,0x0E,0x00,0x00,0x01,0x36,0x68,0x4A,0x2C,0x0E,0x50,0x68,0xC8,0x4A,0x00,0x20,0x24,0x00,0xC0,0xE1,0x38,0x96,0xE5,
0x79,0x9E,0x27,0x8A,0xA6,0x68,0x9A,0xAA,0xCA,0x71,0x34,0xCD,0xF3,0x44,0x51,0x14,0x4D,0x53,0x55,0x55,0x95,0xE3,0x58,0x96,0xE7,0x89,0xA2,0x28,0x9A,0xA6,0xAA,0xBA,
0x2E,0xCB,0xD2,0x34,0xCF,0x13,0x45,0x51,0x34,0x4D,0x55,0x75,0x5D,0x68,0x9A,0xE7,0x89,0xA2,0x28,0x9A,0xA6,0xAA,0xBA,0x2E,0x3C,0xCF,0xF3,0x44,0xD1,0x14,0x4D,0x55,
0x55,0x5D,0x17,0x9E,0xE7,0x79,0xA2,0x68,0x9A,0xAA,0xA9,0xAA,0xAE,0x0B,0x51,0x14,0x45,0xD3,0x34,0x4D,0x55,0x55,0x55,0xD7,0x05,0xA2,0x68,0x9A,0xA6,0xA9,0xAA,0xAE,
0xEA,0xBA,0xC0,0xF3,0x44,0xD1,0x34,0x55,0xD5,0x75,0x5D,0x17,0x78,0x9E,0x28,0x9A,0xA6,0xAA,0xBA,0xAE,0xEB,0x02,0x51,0x34,0x4D,0xD5,0x54,0x55,0xD7,0x75,0x5D,0x80,
0x69,0x9A,0xA6,0xAA,0xBA,0xAE,0xEC,0x02,0x54,0x55,0x55,0x55,0xD7,0x75,0x65,0x17,0xA0,0xAA,0xAA,0xAA,0xAA,0xAE,0x2B,0xCB,0x00,0x55,0x75,0x5D,0xD7,0x75,0x5D,0x59,
0x06,0xA0,0xAA,0xAE,0xEB,0xBA,0xB2,0x2C,0x00,0x00,0xE0,0xC0,0x01,0x00,0x20,0xC0,0x08,0x3A,0xC9,0xA8,0xB2,0x08,0x1B,0x4D,0xB8,0xF0,0x00,0x14,0x1A,0xB2,0x22,0x00,
0x88,0x02,0x00,0x00,0x8C,0x51,0x4A,0x31,0xA5,0x0C,0x63,0x12,0x42,0x09,0x21,0x62,0x4C,0x42,0x28,0x21,0x54,0x52,0x4A,0x29,0xA9,0x94,0x0A,0x42,0x29,0xA5,0x94,0x50,
0x41,0x28,0xA1,0xA4,0x10,0x32,0x29,0x29,0xA5,0x54,0x4A,0x05,0xA1,0x84,0x50,0x4A,0xA8,0x20,0x94,0x52,0x4A,0x29,0x05,0x00,0x80,0x1D,0x38,0x00,0x80,0x1D,0x58,0x08,
0x85,0x86,0xAC,0x04,0x00,0xF2,0x00,0x00,0x08,0x63,0x94,0x62,0xCC,0x39,0xE7,0x24,0x42,0x4A,0x31,0xE6,0x9C,0x73,0x12,0x21,0xA5,0x18,0x73,0xCE,0x39,0xA9,0x14,0x63,
0xCE,0x39,0xE7,0x9C,0x94,0x92,0x31,0xE7,0x9C,0x73,0x4E,0x4A,0xC9,0x98,0x73,0xCE,0x39,0x27,0xA5,0x64,0xCC,0x39,0xE7,0x9C,0x93,0x52,0x3A,0xE7,0x9C,0x73,0xCE,0x49,
0x29,0xA5,0x74,0xCE,0x39,0xE7,0xA4,0x94,0x52,0x42,0xE8,0x9C,0x83,0x52,0x4A,0x29,0x9D,0x73,0xCE,0x39,0x01,0x00,0x40,0x05,0x0E,0x00,0x00,0x01,0x36,0x8A,0x6C,0x4E,
0x30,0x12,0x54,0x68,0xC8,0x4A,0x00,0x20,0x15,0x00,0xC0,0xE0,0x38,0x96,0xE5,0x79,0x9E,0x27,0x8A,0xA6,0x69,0x49,0x92,0xA6,0x79,0x9E,0x28,0x9A,0xA6,0xAA,0x6A,0x92,
0xA4,0x69,0x9E,0x27,0x8A,0xA6,0xA9,0xAA,0x3C,0xCF,0xF3,0x44,0x51,0x14,0x4D,0x53,0x55,0x79,0x9E,0xE7,0x89,0xA2,0x28,0x9A,0xA6,0xAA,0x72,0x5D,0x51,0x14,0x45,0xD3,
0x34,0x4D,0x55,0xE5,0xBA,0xA2,0x27,0x8A,0xA6,0xA9,0xAA,0xAE,0x0A,0xD1,0x14,0x45,0xD3,0x54,0x55,0xD7,0x85,0x69,0x8A,0xA2,0x69,0xAA,0xAA,0xEB,0x42,0x96,0x4D,0xD3,
0x54,0x5D,0xD7,0x75,0x61,0xDB,0xA6,0xA9,0xAA,0xAA,0xEA,0xBA,0x40,0x75,0x55,0xD5,0x75,0x5D,0x19,0xB8,0xAE,0xAA,0xBA,0xAE,0x2C,0x0B,0x00,0x00,0x4F,0x70,0x00,0x00,
0x2A,0xB0,0x61,0x75,0x84,0x93,0xA2,0xB1,0xC0,0x42,0x43,0x56,0x02,0x00,0x19,0x00,0x00,0x84,0x31,0x08,0x29,0x84,0x10,0x52,0x06,0x21,0xA4,0x10,0x42,0x48,0x29,0x85,
0x90,0x00,0x00,0x80,0x01,0x07,0x00,0x80,0x00,0x13,0xCA,0x40,0xA1,0x21,0x2B,0x01,0x80,0x54,0x00,0x00,0x80,0x10,0x29,0xA5,0x94,0x52,0x4A,0x29,0x11,0x63,0x52,0x4A,
0x29,0xA5,0x94,0x52,0x22,0xE6,0xA4,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,
0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0x21,0x84,0x50,0x00,0x20,
0x76,0x85,0x03,0xC0,0x4E,0x84,0x0D,0xAB,0x23,0x9C,0x14,0x8D,0x05,0x16,0x1A,0xB2,0x12,0x00,0x08,0x07,0x00,0x00,0x8C,0x41,0x8A,0x31,0x08,0x29,0xB5,0xD6,0x62,0x85,
0x90,0x62,0xCE,0x49,0x49,0x29,0xC6,0x18,0x2B,0x84,0x18,0x73,0x8E,0x4A,0x4A,0x2D,0xB6,0x18,0x34,0xE6,0x1C,0x84,0x94,0x5A,0x6B,0x31,0xD7,0xA0,0x31,0xE7,0x20,0xA4,
0xD2,0x5A,0x8C,0x35,0x06,0xD5,0x42,0x28,0xA5,0xB5,0x18,0x6B,0xAD,0x35,0xB8,0x14,0x3A,0x2A,0xA9,0xC5,0x18,0x6B,0xAD,0x41,0x08,0x95,0x52,0x8A,0x31,0xC6,0x1A,0x73,
0x0D,0x42,0xA8,0x92,0x42,0x6C,0xB1,0xE6,0x9A,0x6B,0x10,0xC2,0xD6,0xD4,0x5A,0xAC,0xB5,0xE7,0x9C,0x83,0x10,0x3A,0xB7,0x14,0x53,0x8C,0x31,0xF7,0x1A,0x84,0x10,0x42,
0xC6,0x1A,0x6B,0xCD,0xB9,0xE7,0x20,0x84,0x10,0xB6,0xD6,0x56,0x5B,0xAF,0xB9,0x06,0x21,0x84,0xF0,0x41,0xD6,0x9A,0x73,0x0E,0x3A,0x08,0x21,0x84,0x0F,0xB2,0xD6,0x9A,
0x83,0xCE,0x05,0x00,0x98,0x3C,0x38,0x00,0x40,0x25,0xD8,0x38,0xC3,0x4A,0xD2,0x59,0xE1,0x68,0x70,0xA1,0x21,0x2B,0x01,0x80,0xDC,0x00,0x00,0x04,0x21,0xA5,0x18,0x73,
0xCE,0x39,0x07,0x21,0x84,0x10,0x42,0x08,0x29,0x42,0x8C,0x31,0xE6,0x9C,0x73,0x10,0x42,0x08,0x21,0x84,0x52,0x52,0x84,0x18,0x63,0xCC,0x39,0xE7,0x20,0x84,0x10,0x42,
0x08,0x21,0xA4,0x8C,0x31,0xE6,0x9C,0x73,0x10,0x42,0x08,0xA1,0x94,0x52,0x4A,0x49,0x29,0x65,0xCC,0x39,0xE7,0x20,0x84,0x10,0x42,0x29,0xA5,0x94,0x92,0x52,0xEA,0x9C,
0x73,0x10,0x42,0x08,0xA1,0x94,0x52,0x4A,0x29,0x25,0xA5,0xD4,0x39,0xE7,0x20,0x84,0x10,0x42,0x09,0xA5,0x94,0x52,0x4A,0x4A,0xA9,0x73,0x0E,0x42,0x08,0x21,0x84,0x52,
0x4A,0x29,0xA5,0x94,0x94,0x52,0x4A,0x9D,0x83,0x10,0x42,0x28,0xA5,0x94,0x52,0x4A,0x29,0x29,0xA5,0x94,0x42,0x08,0x21,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x52,0x4A,
0x29,0x85,0x10,0x42,0x28,0xA5,0x94,0x52,0x4A,0x29,0xA5,0xA4,0x94,0x52,0x0A,0x21,0x84,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x49,0x29,0xA5,0x94,0x52,0x08,0xA1,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x92,0x52,0x4A,0x29,0xA5,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0x25,0xA5,0x94,0x52,0x4A,0xA5,0x84,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,
0x4A,0x29,0xA5,0x94,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x94,0x52,0x4A,0x29,0xA5,0x54,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0x29,0xA5,0x94,0x52,0x4A,0xA9,
0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x52,0x4A,0x29,0xA5,0x96,0x52,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0xB4,0xD4,0x5A,0x4A,0x29,0xA5,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x4A,0x49,0x29,0xA5,0x94,0x52,0x4A,0x29,0x95,0x52,0x4A,0x29,0xA5,0x94,0x52,0x00,0x00,0xD0,0x81,0x03,0x00,0x40,0x80,0x11,0x95,0x16,0x62,0xA7,0x19,0x57,0x1E,0x81,
0x23,0x0A,0x19,0x26,0xA0,0x42,0x43,0x56,0x02,0x00,0x64,0x00,0x00,0x08,0xA2,0x14,0x53,0x4A,0xAD,0x45,0x82,0x2A,0xC9,0x9C,0xC4,0x5E,0x42,0x25,0x15,0x73,0x90,0x5A,
0x8A,0x28,0x93,0x4E,0x5A,0x0E,0xAE,0x43,0xD0,0x20,0xE6,0xA4,0x95,0x8A,0x39,0x84,0x94,0x93,0x54,0x3A,0x07,0x95,0x52,0x0C,0x4A,0x2A,0x21,0x75,0x4C,0x29,0x06,0x29,
0x96,0x1C,0x42,0xC6,0x98,0x93,0x9C,0x82,0x4A,0xA1,0x63,0x0E,0x00,0x00,0x00,0x41,0x00,0x00,0x81,0x90,0x09,0x04,0x0A,0xA0,0xC0,0x40,0x06,0x00,0x1C,0x20,0x24,0x48,
0x01,0x00,0x85,0x05,0x86,0x0E,0x11,0x22,0x40,0x8C,0x02,0x03,0xE3,0xE2,0xD2,0x06,0x00,0x20,0x08,0x91,0x19,0x22,0x11,0xB1,0x18,0x24,0x26,0x54,0x03,0x45,0xC5,0x74,
0x00,0xB0,0xB8,0xC0,0x90,0x0F,0x00,0x19,0x1A,0x1B,0x69,0x17,0x17,0xD0,0x65,0x80,0x0B,0xBA,0xB8,0xEB,0x40,0x08,0x41,0x08,0x42,0x10,0x8B,0x03,0x28,0x20,0x01,0x07,
0x27,0xDC,0xF0,0xC4,0x1B,0x9E,0x70,0x83,0x13,0x74,0x8A,0x4A,0x1D,0x08,0x00,0x00,0x00,0x00,0xC0,0x03,0x00,0x3C,0x00,0x00,0x24,0x1B,0x40,0x44,0x44,0x34,0x73,0x1C,
0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x02,0x00,0x00,0x00,0x00,0x80,0x07,0x00,0x1F,0x00,0x00,0x49,0x0A,0x10,0x11,0x11,0xCD,0x1C,0x47,0x87,
0xC7,0x07,0x48,0x88,0xC8,0x08,0x49,0x89,0xC9,0x09,0x4A,0x00,0x00,0x20,0x80,0x00,0x00,0x00,0x00,0x00,0x08,0x20,0x00,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x80,0x00,
0x00,0x00,0x00,0x01,0x01,
};
static const uint8_t vcb_5[] = {
0x22,0x42,0x43,0x56,0x01,0x00,0x40,0x00,0x00,0x24,0x73,0x5A,0x32,0x66,0xA9,0x73,0xD8,0x7B,0xEF,0x1D,0x42,0x92,0x19,0xE3,0x1C,0x42,0xD0,0x7B,0xEF,0x99,0x41,0x4C,
0x11,0xA2,0x1C,0x42,0xCC,0x6B,0xEC,0x21,0x63,0x92,0x19,0xC3,0xA0,0x42,0x8A,0x63,0xAA,0x81,0xD0,0x90,0x55,0x00,0x00,0x40,0x00,0x00,0x67,0xBD,0x97,0xDA,0x7B,0xCB,
0xBD,0xF7,0xDE,0x7B,0x46,0xB9,0x67,0xD4,0x7B,0x69,0xBD,0xF7,0xDE,0x7B,0xC8,0xBD,0x87,0xD6,0x7B,0xCA,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,
0xDE,0x7B,0x25,0xB1,0x67,0x92,0x7B,0x48,0xBD,0xF7,0xDE,0x7B,0xE3,0xB0,0x47,0x8E,0x7B,0x06,0xB9,0xF7,0xDE,0x7B,0x65,0xBD,0x57,0x92,0x7B,0x28,0xB5,0xF7,0xDE,0x7B,
0xED,0xBD,0xB7,0xDA,0x7B,0xEE,0xBD,0xF7,0xDE,0x7B,0x03,0xA9,0x47,0x10,0x7B,0x06,0xB9,0xF7,0xDE,0x7B,0xC1,0xA8,0x27,0x8A,0x7A,0xC4,0xAC,0xF7,0xDE,0x7B,0x03,0xB5,
0x37,0x0C,0x7B,0xE5,0xB0,0xF7,0xDE,0x7B,0xAA,0xBD,0x97,0x5E,0x7B,0xEA,0xBD,0xF7,0xDE,0x7B,0x86,0xBD,0x87,0x98,0x7B,0x8A,0xBD,0xF7,0xDE,0x7B,0x24,0xB5,0x57,0x92,
0x7B,0x28,0xBD,0xF7,0xDE,0x7B,0x86,0xBD,0x57,0xD2,0x7B,0x68,0xBD,0xF7,0xDE,0x7B,0xEA,0xBD,0x97,0xDE,0x7B,0xEC,0xBD,0xF7,0xDE,0x7B,0x20,0x34,0x64,0x15,0x00,0x90,
0x00,0x00,0xA0,0xA2,0x28,0x8A,0xA2,0x28,0x0A,0x10,0x1A,0xB2,0x0A,0x00,0xC8,0x00,0x00,0x10,0x40,0x51,0x1C,0xC5,0x71,0x1C,0xC9,0x91,0x1C,0xC9,0xB1,0x1C,0x0B,0x08,
0x0D,0x59,0x05,0x00,0x00,0x01,0x00,0x08,0x00,0x00,0xA0,0x48,0x8A,0xA4,0x58,0x8E,0xE5,0x58,0x8E,0x25,0x59,0x92,0x25,0x59,0x92,0x25,0x49,0x92,0xA5,0x79,0xA6,0xEB,
0xBA,0xAE,0xEB,0xBA,0xAE,0xEB,0xBA,0x2E,0x10,0x1A,0xB2,0x0A,0x00,0x48,0x00,0x00,0x50,0x51,0x14,0xC5,0x70,0x14,0x07,0x08,0x0D,0x59,0x05,0x00,0x64,0x00,0x00,0x08,
0xA0,0x48,0x8A,0xA5,0x68,0x8A,0xA7,0x88,0x8A,0xA9,0xA8,0x8E,0x0A,0x84,0x86,0xAC,0x02,0x00,0x80,0x00,0x00,0x04,0x00,0x00,0x10,0x5C,0x43,0x54,0x4C,0xC7,0x95,0x5C,
0xCB,0x35,0x5D,0xD5,0x75,0x5D,0xD7,0x75,0x5D,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x15,0x08,0x0D,0x59,0x05,0x00,0x40,0x00,0x00,0x10,0xD0,
0x69,0x86,0xA9,0x06,0x88,0x30,0x23,0x99,0x05,0x42,0x43,0x56,0x01,0x00,0x08,0x00,0x00,0x00,0x11,0xC8,0x30,0xC5,0x80,0xD0,0x90,0x55,0x00,0x00,0x40,0x00,0x00,0x80,
0x14,0x49,0x4E,0x92,0x28,0x39,0x29,0xA5,0x94,0xC3,0x20,0x59,0x4C,0x92,0x4A,0x39,0x29,0xA5,0x94,0x47,0x31,0x79,0x54,0x93,0x8C,0x41,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0xC2,0x20,0x59,0x8E,0x92,0x4A,0x39,0x29,0xA5,0x94,0xC4,0x28,0x59,0x8C,0x92,0x2A,0x35,0x29,0xA5,0x94,0x47,0x39,0x79,0x52,0x93,
0x8C,0x3D,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x05,0x29,0x79,0xD2,0x92,0xAE,0x41,0x29,0xA5,0x94,0xE4,0x28,0x69,0xD0,0x92,0x4D,0x3D,
0x29,0xA5,0x94,0x28,0x45,0x89,0x92,0x93,0xED,0x49,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x0F,0x4A,0xF9,0x20,0x94,0x52,0x4A,0x29,0xA5,
0x94,0xAB,0x3D,0xB9,0xD6,0x93,0x52,0x4A,0x29,0xA5,0x94,0x31,0x4A,0x09,0x9F,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x8C,0x20,
0x34,0x64,0x15,0x00,0x00,0x04,0x00,0x00,0x18,0x67,0x8D,0x72,0x28,0x3A,0x89,0xCE,0x17,0x67,0x28,0x67,0x9A,0x82,0xA4,0x42,0x69,0x42,0xF7,0x26,0x39,0x4A,0x9E,0x93,
0xDC,0x4A,0xCB,0xCD,0xE9,0x26,0x9C,0x73,0xBA,0x39,0xE5,0x9C,0x4F,0xCE,0x39,0x27,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x40,0x08,0x21,0x85,0x14,0x52,0x48,0x21,
0x85,0x14,0x52,0x48,0x21,0x85,0x18,0x62,0x88,0x21,0x87,0x9C,0x72,0x0A,0x2A,0xA8,0xA0,0x92,0x4A,0x2A,0xAA,0xA8,0xA2,0xCA,0x2A,0xCB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,
0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCE,0x3A,0xEA,0xA8,0xB3,0x90,0x42,0x28,0x29,0xB4,0xD0,0x5A,0x8D,0xB1,0xC6,0x18,0x5B,0xED,0xCD,0x49,0x5B,0x73,0x94,0xD2,0x49,0x29,
0xA5,0x94,0x52,0x4A,0xE9,0x9C,0x73,0xCE,0x09,0x42,0x43,0x56,0x01,0x00,0x20,0x00,0x00,0x04,0x42,0x06,0x19,0x64,0x90,0x51,0x46,0x21,0x85,0x18,0x62,0xCA,0x29,0xA7,
0x9C,0x82,0x4A,0x2A,0xA9,0x80,0xD0,0x90,0x55,0x00,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x00,0x51,0x32,0x1D,0xD3,0x11,0x1D,0x51,0x11,0x1D,0xD1,0x11,0x1D,0xD1,0x11,
0x1D,0xD1,0xF1,0x1C,0xCF,0xF1,0x24,0x51,0x12,0x2D,0xCF,0x12,0x35,0xD3,0x33,0x45,0xD3,0x34,0x5D,0x55,0x76,0x65,0x59,0x97,0x6D,0xD9,0x76,0x75,0x59,0xB7,0x75,0xD9,
0xB7,0x7D,0x5B,0xB7,0x6D,0xDB,0xD7,0x8D,0xDD,0xF8,0x8D,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x86,0x20,0x34,0x64,0x15,0x00,0x00,
0x02,0x00,0x00,0x20,0x84,0x10,0x42,0x48,0x21,0x85,0x14,0x52,0x48,0x29,0xA6,0x18,0x73,0x0E,0x3A,0x08,0x21,0x94,0x12,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x08,
0x00,0x00,0x00,0x50,0x14,0x47,0x71,0x1C,0xC9,0x91,0x24,0x49,0xB2,0x24,0xCB,0xD2,0x2C,0x4D,0xD3,0x34,0x4D,0xF3,0x44,0x4F,0xF4,0x4C,0x4F,0xF5,0x5C,0x51,0x16,0x6D,
0xD1,0xF6,0x5C,0xCF,0x16,0x6D,0xCF,0xF5,0x54,0x4F,0xF5,0x54,0x51,0x35,0x55,0xD3,0x35,0x5D,0xD5,0x75,0x5D,0xD7,0x55,0x5D,0x55,0x56,0x65,0xD7,0xB6,0x6D,0xDB,0xB6,
0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0x5B,0x06,0x42,0x43,0x56,0x01,0x00,0x12,0x00,0x00,0x3A,0x92,0x23,0x29,0x92,0x22,0x29,0x92,0xE3,0x38,0x92,0x23,
0x49,0x40,0x68,0xC8,0x2A,0x00,0x40,0x06,0x00,0x40,0x00,0x00,0x8A,0xA2,0x28,0x8E,0xE3,0x48,0x8E,0x25,0x59,0x92,0x26,0x89,0x92,0x69,0xA9,0x96,0xAB,0xC9,0x9E,0xEE,
0xE9,0xA2,0x2E,0xEA,0x40,0x68,0xC8,0x2A,0x00,0x00,0x10,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x68,0x88,0x86,0xE8,0x88,0x96,0xA8,0x89,0xA2,0x28,0x8A,0xA2,
0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,
0xA2,0x28,0x8A,0xA2,0xE8,0x79,0x9E,0xE7,0x79,0x9E,0xE7,0x79,0x9E,0x07,0x84,0x86,0xAC,0x02,0x00,0x24,0x00,0x00,0x74,0x24,0x47,0x72,0x2C,0xC5,0x52,0x24,0x45,0x52,
0x2C,0xC7,0x72,0x80,0xD0,0x90,0x55,0x00,0x80,0x0C,0x00,0x80,0x00,0x00,0x1C,0xC3,0x31,0x24,0x45,0x72,0x2C,0xCB,0xB2,0x34,0x4D,0xF3,0x3C,0xCF,0xF3,0x44,0x4F,0x14,
0x45,0x51,0x34,0x4D,0xD5,0x54,0x81,0xD0,0x90,0x55,0x00,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x45,0xB1,0x1C,0xCB,0x91,0x24,0xCD,0xF1,0x24,0xD1,
0x11,0x25,0x51,0x12,0x2D,0x51,0x12,0x35,0x51,0x13,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,
0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x11,0x08,0x0D,0x59,0x09,0x00,0x00,0x01,0x00,0xF0,0x9C,0x7B,0xED,0xBD,0xF7,0xD0,0x51,
0x29,0x25,0xF7,0x8A,0x30,0xC4,0xA0,0xF7,0x94,0x51,0x28,0xAD,0xF7,0xD0,0x38,0x82,0x9C,0xF7,0x54,0x41,0x63,0x98,0xF7,0x14,0x41,0x42,0x90,0xF5,0x5C,0x51,0x84,0x94,
0x06,0x42,0x43,0x56,0x04,0x00,0x51,0x00,0x00,0x80,0x31,0xC8,0x31,0xC4,0x1C,0x72,0xCE,0x51,0xEA,0x24,0x45,0xCE,0x39,0x2A,0x1D,0xA5,0xC6,0x39,0x47,0xA9,0xA3,0xD4,
0x51,0x4A,0xB1,0xA6,0x18,0x3B,0x4A,0x25,0xB6,0x14,0x6B,0xE3,0x9C,0xA3,0xD4,0x51,0xCA,0x28,0xA5,0x1A,0x4B,0x8B,0x1D,0xA5,0x54,0x63,0x8A,0xB1,0x00,0x00,0x80,0x00,
0x07,0x00,0x80,0x00,0x0B,0xA1,0xD0,0x90,0x15,0x01,0x40,0x14,0x00,0x00,0x62,0x0C,0x52,0x0A,0x29,0x85,0x94,0x52,0xCE,0x29,0xE6,0x90,0x52,0xCA,0x31,0xE5,0x1C,0x52,
0x4A,0x39,0xA6,0x98,0x53,0xCE,0x39,0x08,0x1D,0x84,0xCA,0x39,0x06,0x9D,0x83,0x10,0x29,0xA5,0x9C,0x53,0xCC,0x29,0xE7,0x1C,0x84,0xCC,0x41,0xE5,0x9C,0x83,0xD0,0x41,
0x28,0x00,0x00,0x20,0xC0,0x01,0x00,0x20,0xC0,0x42,0x28,0x34,0x64,0x45,0x00,0x10,0x27,0x00,0xE0,0x70,0x1C,0xCF,0x93,0x34,0x4D,0x14,0x25,0x4D,0x13,0x45,0x4F,0x14,
0x5D,0xD7,0x13,0x4D,0xD5,0x95,0x34,0xCD,0x34,0x35,0x51,0x54,0x4D,0xCD,0x13,0x4D,0xD5,0x54,0x4D,0x5B,0x16,0x4D,0xD3,0x95,0x25,0x4D,0x33,0x4D,0x4D,0xF4,0x54,0x53,
0x13,0x45,0x55,0x15,0x4D,0x53,0x76,0x4D,0x53,0x95,0x65,0xCF,0x34,0x75,0xD9,0x54,0x55,0x5D,0x16,0x55,0xD5,0x96,0x65,0x5B,0x16,0x76,0x57,0x96,0x75,0xDD,0x33,0x4D,
0xD9,0x16,0x55,0x55,0xB6,0x4D,0xD5,0x95,0x7D,0x57,0x96,0x75,0x5D,0x96,0x6D,0x5D,0x98,0x34,0xCD,0x34,0x35,0x51,0x54,0x55,0x4D,0x14,0x55,0xD7,0x54,0x55,0xDB,0x36,
0x55,0xD7,0xB6,0x35,0x51,0x74,0x5D,0x51,0x55,0x65,0x57,0x54,0x55,0x59,0x76,0x65,0xD7,0xB6,0x55,0xD7,0xD5,0x6D,0x4D,0x14,0x5D,0x55,0x54,0x4D,0x59,0x15,0x55,0xD5,
0x95,0x55,0x57,0xB5,0x65,0xD5,0x75,0x75,0xDD,0x74,0x5D,0x5F,0x57,0x65,0xD9,0xF7,0x4D,0xD7,0xF5,0x7D,0xDB,0xB6,0x85,0x5F,0xB6,0x6D,0xE1,0x18,0x55,0xD5,0xD6,0x4D,
0x57,0xD5,0x75,0xD3,0x75,0x75,0x61,0xD6,0x65,0xE1,0x97,0x6D,0x5D,0x58,0x26,0x4D,0x33,0x4D,0x4D,0x14,0x5D,0x55,0x13,0x45,0x55,0x35,0x55,0x55,0xB7,0x4D,0xD5,0x95,
0x6D,0x4D,0x14,0x5D,0x57,0x54,0x55,0xD9,0xF5,0x4C,0xD5,0x75,0x55,0xD7,0xD5,0x75,0x55,0x75,0x6D,0x5B,0x13,0x45,0xD7,0x15,0x55,0x55,0x96,0x45,0x55,0x75,0x5D,0xD5,
0x75,0x7D,0x5D,0x75,0x65,0xDB,0x16,0x55,0xD5,0xD7,0x4D,0xD7,0xF5,0x75,0x53,0x75,0x6D,0x5B,0xB6,0x75,0x63,0x98,0x65,0xDB,0xF7,0x4D,0xD7,0xD5,0x75,0x53,0x76,0x75,
0x61,0x95,0x5D,0xDD,0x97,0x75,0x5B,0x38,0x6E,0xDD,0xD6,0x85,0xCF,0x34,0x75,0xDD,0x74,0x5D,0x61,0x37,0x5D,0x57,0xF8,0x6D,0x5F,0x17,0x86,0xD9,0xD6,0x7D,0x5F,0x54,
0x5D,0xDF,0x57,0x65,0xD9,0x17,0x56,0x59,0xF6,0x7D,0xDD,0xF7,0xB1,0x75,0x5D,0x19,0x46,0x55,0x15,0x7E,0x53,0x56,0x7D,0x5F,0x75,0x5D,0x5F,0xD8,0x7D,0x5D,0x59,0x6E,
0x5F,0x67,0xBC,0xB6,0x8E,0xAD,0xFB,0xC6,0x31,0xDB,0xBA,0x30,0xFC,0xC6,0x91,0xEE,0xFB,0xCA,0xB1,0xDA,0x32,0x63,0xF6,0x65,0x61,0x98,0x75,0x1B,0x61,0xD8,0x95,0xE3,
0xF6,0x7D,0xA5,0x67,0x9A,0xBA,0x6E,0xBA,0xAA,0xEF,0x9B,0xAA,0x2B,0xFC,0xB6,0xAE,0x0B,0xC7,0xAE,0xFB,0x88,0xAA,0xAA,0xEB,0xAA,0xEC,0xFA,0xC6,0xE9,0xCA,0xC2,0x30,
0xEB,0xBA,0xB0,0xEC,0xBA,0xAF,0x1C,0xA3,0xAB,0xF2,0x55,0xD9,0xF5,0x7D,0x55,0x96,0x7D,0xE1,0xF6,0x75,0x65,0xD9,0x75,0xDF,0x38,0x5E,0xDB,0x16,0x8E,0xD9,0xD6,0x8D,
0xB2,0xAD,0x1B,0xCB,0x2E,0xFC,0x94,0x5F,0x37,0x86,0xE5,0xB5,0x6D,0x65,0x99,0x75,0x9D,0x31,0x0B,0xBB,0x71,0xEC,0xBE,0x50,0x19,0x96,0xE3,0x28,0x00,0x00,0x60,0xC0,
0x01,0x00,0x20,0xC0,0x84,0x32,0x50,0x68,0xC8,0x8A,0x00,0x20,0x4E,0x00,0x80,0x41,0x08,0x42,0xC5,0x14,0x84,0x4A,0x31,0x08,0xA1,0x84,0x96,0x42,0x28,0xA9,0x55,0x8C,
0x49,0xC9,0x1C,0x93,0x92,0x31,0x27,0xA5,0x94,0xD2,0x5A,0x28,0x25,0xB5,0x8A,0x31,0x29,0x99,0x63,0x52,0x32,0xC6,0xA4,0x84,0x52,0x5A,0x2A,0xA5,0xB4,0x16,0x4A,0x89,
0xAD,0x94,0x12,0x63,0x29,0x25,0xB6,0xD6,0x5A,0xAD,0xAD,0xB5,0x5A,0x43,0x29,0x2D,0x86,0x52,0x62,0x2C,0xA5,0xC4,0xD8,0x5A,0xCB,0xB5,0xC5,0x56,0x6B,0xC4,0x98,0x94,
0xCC,0x31,0x29,0x19,0x73,0x52,0x4A,0x29,0xAD,0x95,0x52,0x5A,0xCB,0x9C,0x93,0xD2,0x39,0x27,0xA9,0x73,0x8E,0x4A,0x29,0x29,0xC5,0x52,0x52,0x8B,0x15,0x63,0x52,0x32,
0xC7,0xA8,0x74,0xCE,0x49,0x2A,0xA9,0xC4,0x54,0x4A,0x89,0xAD,0xA4,0x12,0x63,0x29,0xA5,0xC5,0x92,0x52,0x8C,0x2D,0xC5,0x54,0x5B,0x8C,0xB5,0x86,0x52,0x5A,0x2C,0xA5,
0xC4,0x56,0x4A,0x8A,0xB1,0xC5,0x54,0x5B,0x8C,0x31,0xD7,0x88,0x31,0x29,0x19,0x63,0x52,0x32,0xE6,0xA4,0x94,0x52,0x5A,0x2B,0xA5,0xB4,0x58,0x31,0x26,0xA5,0x73,0x8E,
0x4A,0xC6,0x9C,0xA4,0x52,0x4A,0x6B,0xA5,0xA4,0x14,0x33,0xE7,0xA4,0x64,0xCE,0x49,0xEA,0x9C,0xA3,0x52,0x52,0x89,0xAD,0xA4,0x12,0x53,0x28,0x25,0xC6,0x92,0x52,0x8C,
0xA5,0x94,0x16,0x63,0x8C,0xB5,0xB6,0x14,0x5B,0x2D,0x25,0xC5,0x58,0x52,0x8A,0xB1,0x94,0x12,0x5B,0x8B,0xB1,0xD6,0x16,0x53,0x6E,0xA1,0x94,0x18,0x4B,0x29,0x31,0x96,
0x52,0x62,0x8C,0x31,0xE6,0xDC,0x62,0xAC,0x35,0x94,0x12,0x63,0x29,0x29,0xC6,0x92,0x4A,0x6C,0xB1,0xC5,0x9A,0x63,0x8C,0xB9,0x86,0x52,0x62,0x2C,0xA5,0xC4,0x56,0x4A,
0x6A,0x31,0xC6,0x96,0x6B,0x8C,0xB1,0xD6,0x16,0x5B,0xAE,0x2D,0xB5,0x5A,0x5B,0x6C,0xB9,0xD6,0x96,0x5B,0xAF,0x35,0xF7,0xDE,0x5A,0xAB,0x39,0xB5,0x94,0x6B,0x8B,0xB1,
0xE6,0x5A,0x5B,0x8F,0xB5,0xE6,0xDE,0x43,0x29,0x31,0x96,0x52,0x62,0x2C,0xA5,0xC4,0xD8,0x62,0xAB,0x35,0xC6,0x98,0x73,0x28,0x25,0xC6,0x92,0x4A,0x6C,0xA5,0x94,0x16,
0x63,0x8C,0xB5,0xB6,0x16,0x6B,0x0E,0xA5,0xC4,0x58,0x4A,0x6A,0xB1,0xA4,0x12,0x63,0x8C,0xB1,0xE6,0x18,0x63,0xAE,0xAD,0xB5,0x5C,0x5B,0x6C,0xB9,0xA6,0xD4,0x6A,0xAE,
0xB5,0x06,0x5F,0x5B,0x8D,0xC1,0xB5,0x58,0x7B,0x8C,0x31,0xE6,0xD6,0x52,0xAD,0x35,0xD7,0xDE,0x6B,0x6D,0xBD,0x15,0x00,0x00,0x30,0xE0,0x00,0x00,0x10,0x60,0x42,0x19,
0x28,0x34,0x64,0x25,0x00,0x10,0x05,0x00,0x40,0x18,0xA3,0x14,0x63,0x10,0x1A,0x64,0x18,0x73,0x0C,0x42,0x63,0x0C,0x63,0xCC,0x41,0xA8,0x18,0x73,0xCE,0x41,0x29,0x15,
0x63,0xCE,0x41,0x27,0x25,0x73,0xCC,0x41,0x28,0x29,0x65,0xCC,0x41,0x28,0x25,0xA5,0x10,0x42,0x29,0x29,0xB5,0x16,0x42,0x28,0x25,0xA5,0xD6,0x0A,0x00,0x00,0x28,0x70,
0x00,0x00,0x08,0xB0,0x41,0x53,0x62,0x71,0x80,0x42,0x43,0x56,0x02,0x00,0xA9,0x00,0x00,0x06,0xC7,0xB1,0x2C,0xCF,0x13,0x4D,0x55,0xB5,0x6D,0xC7,0x92,0x3C,0x4F,0x14,
0x55,0x55,0x55,0x6D,0xDB,0x91,0x24,0xCF,0x13,0x45,0x53,0x55,0x5D,0xDB,0xD6,0x3C,0x4F,0x14,0x55,0x53,0x55,0x5D,0x57,0xD7,0x35,0xCF,0x13,0x45,0x55,0x55,0x55,0xD7,
0xD5,0x6D,0xD1,0x34,0x55,0x55,0x55,0x5D,0x57,0x76,0x7D,0x5F,0x34,0x4D,0x55,0x55,0x55,0xD7,0x95,0x65,0xDD,0x37,0x55,0x55,0x55,0x5D,0x57,0x96,0x65,0x59,0xF8,0x4D,
0x55,0x75,0x5D,0xD7,0x75,0x65,0xDB,0xF6,0x7D,0xD5,0x75,0x5D,0x57,0x96,0x6D,0xDB,0xB6,0x85,0x61,0x75,0x5D,0xD7,0x95,0x65,0xDB,0xD6,0x6D,0x63,0xD8,0x6D,0x5D,0xD7,
0x7D,0x5F,0x38,0x96,0x61,0xA9,0xEB,0xBA,0xAE,0xFB,0xC2,0xEF,0x1B,0x43,0x02,0x00,0xC0,0x13,0x1C,0x00,0x80,0x0A,0x6C,0x58,0x1D,0xE1,0xA4,0x68,0x2C,0xB0,0xD0,0x90,
0x95,0x00,0x40,0x06,0x00,0x00,0x61,0x0C,0x42,0x06,0x21,0x85,0x0C,0x42,0x08,0x21,0xA5,0x94,0x42,0x48,0x29,0x25,0x00,0x00,0x60,0xC0,0x01,0x00,0x20,0xC0,0x84,0x32,
0x50,0x68,0xC8,0x4A,0x00,0x20,0x0A,0x00,0x00,0x20,0x44,0x4A,0x29,0xA5,0x34,0x52,0x4A,0x29,0xA5,0x94,0x46,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x08,0x21,0x84,0x10,0x42,
0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x14,0x00,0x20,0x35,0xE1,
0x00,0x20,0xF5,0x60,0x83,0xA6,0xC4,0xE2,0x00,0x85,0x86,0xAC,0x04,0x00,0x52,0x01,0x00,0x00,0x63,0x94,0x62,0xCC,0x31,0x08,0xA5,0x34,0x4C,0x39,0xE7,0x9C,0x84,0x54,
0x5A,0x6B,0x14,0x73,0xCE,0x39,0x29,0x29,0xB5,0x96,0x39,0x27,0xA1,0x94,0x96,0x62,0x8B,0x31,0x73,0x0E,0x42,0x29,0x29,0xC5,0x58,0x73,0xE6,0xA0,0x94,0x96,0x6A,0x8C,
0xB5,0xE6,0xCC,0x41,0x29,0xA9,0xC5,0x98,0x6B,0xCD,0x9D,0x94,0x96,0x62,0xCC,0x39,0x07,0x9D,0x3B,0x29,0xA9,0xD5,0x58,0x73,0xD0,0x39,0x97,0x94,0x6A,0xAC,0x35,0xE7,
0x20,0x7C,0x30,0xA9,0xC5,0x58,0x6B,0xCD,0x3D,0xE7,0xA0,0x5A,0xAC,0xB1,0xF7,0x5E,0x83,0x0F,0x42,0xB5,0x98,0x73,0xCE,0x3D,0xE7,0x9C,0x83,0x01,0x00,0x38,0x0D,0x0E,
0x00,0xA0,0x07,0x36,0xAC,0x8E,0x70,0x52,0x34,0x16,0x58,0x68,0xC8,0x4A,0x00,0x20,0x15,0x00,0x80,0x40,0x48,0x29,0xC6,0x9C,0x73,0xCE,0x39,0xA4,0x14,0x63,0xCE,0x39,
0xE7,0x1C,0x84,0x48,0x29,0xC6,0x1C,0x73,0xCE,0x39,0xE7,0x14,0x63,0x8C,0x39,0xE7,0x1C,0x84,0x10,0x2A,0xC6,0x18,0x73,0xCE,0x39,0x08,0x21,0x64,0xCE,0x39,0xE7,0x9C,
0x83,0x10,0x42,0xC8,0x9C,0x73,0xCE,0x39,0x08,0x21,0x84,0xD0,0x39,0x07,0x1D,0x84,0x10,0x42,0x08,0xA1,0x73,0x0E,0x42,0x08,0x21,0x84,0x10,0x42,0x07,0x21,0x84,0x10,
0x42,0x08,0x21,0x84,0x0E,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x14,0x00,0x00,0x58,
0xE0,0x00,0x00,0x10,0x60,0xC3,0xEA,0x08,0x27,0x45,0x63,0x81,0x85,0x86,0xAC,0x04,0x00,0x80,0x00,0x00,0x38,0xCD,0x39,0xE8,0x16,0x63,0x62,0x98,0x63,0x8E,0x9A,0x43,
0x14,0x62,0xD0,0x73,0x85,0x94,0x52,0x8E,0x9B,0x66,0x94,0x41,0x4E,0x7C,0xA6,0x14,0x42,0x4A,0x53,0xE6,0x18,0x43,0x46,0x4A,0xCC,0x3D,0x99,0x4A,0x02,0x00,0x00,0x20,
0x08,0x00,0x10,0x10,0x12,0x00,0x60,0x80,0xA0,0x60,0x06,0x00,0x18,0x1C,0x20,0x7C,0x0E,0x82,0x4E,0x80,0xE0,0x68,0x03,0x00,0x10,0x84,0xC8,0x0C,0x91,0x68,0x58,0x08,
0x0E,0x0F,0x2A,0x01,0x22,0x62,0x2A,0x00,0x48,0x4C,0x50,0xC8,0x05,0x80,0x0A,0x8B,0x8B,0xB4,0x8B,0x0B,0xE8,0x32,0xC0,0x05,0x5D,0xDC,0x75,0x20,0x84,0x20,0x04,0x21,
0x88,0xC5,0x01,0x14,0x90,0x80,0x83,0x13,0x6E,0x78,0xE2,0x0D,0x4F,0xB8,0xC1,0x09,0x3A,0x45,0xA5,0x0E,0x02,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x1E,0x00,0x00,0x8E,
0x0B,0x20,0x22,0xA2,0x39,0x8C,0x0C,0x8D,0x0D,0x8E,0x0E,0x8F,0x0F,0x90,0x90,0x00,0x00,0x00,0x00,0x00,0x90,0x01,0x80,0x0F,0x00,0x80,0x43,0x04,0x88,0x88,0x68,0x0E,
0x23,0x43,0x63,0x83,0xA3,0xC3,0xE3,0x03,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,
0x08,
};
static const uint8_t vcb_6[] = {
0x22,0x42,0x43,0x56,0x01,0x00,0x40,0x00,0x00,0x24,0x73,0x5A,0x32,0x66,0xA9,0x73,0xD8,0x7B,0xEF,0x1D,0x42,0x92,0x19,0xE3,0x1C,0x42,0xD0,0x7B,0xEF,0x99,0x41,0x4C,
0x11,0xA2,0x1C,0x42,0xCC,0x6B,0xEC,0x21,0x63,0x92,0x19,0xC3,0xA0,0x42,0x8A,0x63,0xAA,0x81,0xD0,0x90,0x55,0x00,0x00,0x40,0x00,0x00,0x67,0xBD,0x97,0xDA,0x7B,0xCB,
0xBD,0xF7,0xDE,0x7B,0x46,0xB9,0x67,0xD4,0x7B,0x69,0xBD,0xF7,0xDE,0x7B,0xC8,0xBD,0x87,0xD6,0x7B,0xCA,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,
0xDE,0x7B,0x25,0xB1,0x67,0x92,0x7B,0x48,0xBD,0xF7,0xDE,0x7B,0xE3,0xB0,0x47,0x8E,0x7B,0x06,0xB9,0xF7,0xDE,0x7B,0x65,0xBD,0x57,0x92,0x7B,0x28,0xB5,0xF7,0xDE,0x7B,
0xED,0xBD,0xB7,0xDA,0x7B,0xEE,0xBD,0xF7,0xDE,0x7B,0x03,0xA9,0x47,0x10,0x7B,0x06,0xB9,0xF7,0xDE,0x7B,0xC1,0xA8,0x27,0x8A,0x7A,0xC4,0xAC,0xF7,0xDE,0x7B,0x03,0xB5,
0x37,0x0C,0x7B,0xE5,0xB0,0xF7,0xDE,0x7B,0xAA,0xBD,0x97,0x5E,0x7B,0xEA,0xBD,0xF7,0xDE,0x7B,0x86,0xBD,0x87,0x98,0x7B,0x8A,0xBD,0xF7,0xDE,0x7B,0x24,0xB5,0x57,0x92,
0x7B,0x28,0xBD,0xF7,0xDE,0x7B,0x86,0xBD,0x57,0xD2,0x7B,0x68,0xBD,0xF7,0xDE,0x7B,0xEA,0xBD,0x97,0xDE,0x7B,0xEC,0xBD,0xF7,0xDE,0x7B,0x20,0x34,0x64,0x15,0x00,0x90,
0x00,0x00,0xA0,0xA2,0x28,0x8A,0xA2,0x28,0x0A,0x10,0x1A,0xB2,0x0A,0x00,0xC8,0x00,0x00,0x10,0x40,0x51,0x1C,0xC5,0x71,0x1C,0xC9,0x91,0x1C,0xC9,0xB1,0x1C,0x0B,0x08,
0x0D,0x59,0x05,0x00,0x00,0x01,0x00,0x08,0x00,0x00,0xA0,0x48,0x8A,0xA4,0x58,0x8E,0xE5,0x58,0x8E,0x25,0x59,0x92,0x25,0x59,0x92,0x25,0x49,0x92,0xA5,0x79,0xA6,0xEB,
0xBA,0xAE,0xEB,0xBA,0xAE,0xEB,0xBA,0x2E,0x10,0x1A,0xB2,0x0A,0x00,0x48,0x00,0x00,0x50,0x51,0x14,0xC5,0x70,0x14,0x07,0x08,0x0D,0x59,0x05,0x00,0x64,0x00,0x00,0x08,
0xA0,0x48,0x8A,0xA5,0x68,0x8A,0xA7,0x88,0x8A,0xA9,0xA8,0x8E,0x0A,0x84,0x86,0xAC,0x02,0x00,0x80,0x00,0x00,0x04,0x00,0x00,0x10,0x5C,0x43,0x54,0x4C,0xC7,0x95,0x5C,
0xCB,0x35,0x5D,0xD5,0x75,0x5D,0xD7,0x75,0x5D,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x15,0x08,0x0D,0x59,0x05,0x00,0x40,0x00,0x00,0x10,0xD0,
0x69,0x86,0xA9,0x06,0x88,0x30,0x23,0x99,0x05,0x42,0x43,0x56,0x01,0x00,0x08,0x00,0x00,0x00,0x11,0xC8,0x30,0xC5,0x80,0xD0,0x90,0x55,0x00,0x00,0x40,0x00,0x00,0x80,
0x14,0x49,0x4E,0x92,0x28,0x39,0x29,0xA5,0x94,0xC3,0x20,0x59,0x4C,0x92,0x4A,0x39,0x29,0xA5,0x94,0x47,0x31,0x79,0x54,0x93,0x8C,0x41,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0xC2,0x20,0x59,0x8E,0x92,0x4A,0x39,0x29,0xA5,0x94,0xC4,0x28,0x59,0x8C,0x92,0x2A,0x35,0x29,0xA5,0x94,0x47,0x39,0x79,0x52,0x93,
0x8C,0x3D,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x05,0x29,0x79,0xD2,0x92,0xAE,0x41,0x29,0xA5,0x94,0xE4,0x28,0x69,0xD0,0x92,0x4D,0x3D,
0x29,0xA5,0x94,0x28,0x45,0x89,0x92,0x93,0xED,0x49,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x0F,0x4A,0xF9,0x20,0x94,0x52,0x4A,0x29,0xA5,
0x94,0xAB,0x3D,0xB9,0xD6,0x93,0x52,0x4A,0x29,0xA5,0x94,0x31,0x4A,0x09,0x9F,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x8C,0x20,
0x34,0x64,0x15,0x00,0x00,0x04,0x00,0x00,0x18,0x67,0x8D,0x72,0x28,0x3A,0x89,0xCE,0x17,0x67,0x28,0x67,0x9A,0x82,0xA4,0x42,0x69,0x42,0xF7,0x26,0x39,0x4A,0x9E,0x93,
0xDC,0x4A,0xCB,0xCD,0xE9,0x26,0x9C,0x73,0xBA,0x39,0xE5,0x9C,0x4F,0xCE,0x39,0x27,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x40,0x08,0x21,0x85,0x14,0x52,0x48,0x21,
0x85,0x14,0x52,0x48,0x21,0x85,0x18,0x62,0x88,0x21,0x87,0x9C,0x72,0x0A,0x2A,0xA8,0xA0,0x92,0x4A,0x2A,0xAA,0xA8,0xA2,0xCA,0x2A,0xCB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,
0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCE,0x3A,0xEA,0xA8,0xB3,0x90,0x42,0x28,0x29,0xB4,0xD0,0x5A,0x8D,0xB1,0xC6,0x18,0x5B,0xED,0xCD,0x49,0x5B,0x73,0x94,0xD2,0x49,0x29,
0xA5,0x94,0x52,0x4A,0xE9,0x9C,0x73,0xCE,0x09,0x42,0x43,0x56,0x01,0x00,0x20,0x00,0x00,0x04,0x42,0x06,0x19,0x64,0x90,0x51,0x46,0x21,0x85,0x18,0x62,0xCA,0x29,0xA7,
0x9C,0x82,0x4A,0x2A,0xA9,0x80,0xD0,0x90,0x55,0x00,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x00,0x51,0x32,0x1D,0xD3,0x11,0x1D,0x51,0x11,0x1D,0xD1,0x11,0x1D,0xD1,0x11,
0x1D,0xD1,0xF1,0x1C,0xCF,0xF1,0x24,0x51,0x12,0x2D,0xCF,0x12,0x35,0xD3,0x33,0x45,0xD3,0x34,0x5D,0x55,0x76,0x65,0x59,0x97,0x6D,0xD9,0x76,0x75,0x59,0xB7,0x75,0xD9,
0xB7,0x7D,0x5B,0xB7,0x6D,0xDB,0xD7,0x8D,0xDD,0xF8,0x8D,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x86,0x20,0x34,0x64,0x15,0x00,0x00,
0x02,0x00,0x00,0x20,0x84,0x10,0x42,0x48,0x21,0x85,0x14,0x52,0x48,0x29,0xA6,0x18,0x73,0x0E,0x3A,0x08,0x21,0x94,0x12,0x08,0x0D,0x59,0x05,0x00,0x00,0x02,0x00,0x08,
0x00,0x00,0x00,0x50,0x14,0x47,0x71,0x1C,0xC9,0x91,0x24,0x49,0xB2,0x24,0xCB,0xD2,0x2C,0x4D,0xD3,0x34,0x4D,0xF3,0x44,0x4F,0xF4,0x4C,0x4F,0xF5,0x5C,0x51,0x16,0x6D,
0xD1,0xF6,0x5C,0xCF,0x16,0x6D,0xCF,0xF5,0x54,0x4F,0xF5,0x54,0x51,0x35,0x55,0xD3,0x35,0x5D,0xD5,0x75,0x5D,0xD7,0x55,0x5D,0x55,0x56,0x65,0xD7,0xB6,0x6D,0xDB,0xB6,
0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0x5B,0x06,0x42,0x43,0x56,0x01,0x00,0x12,0x00,0x00,0x3A,0x92,0x23,0x29,0x92,0x22,0x29,0x92,0xE3,0x38,0x92,0x23,
0x49,0x40,0x68,0xC8,0x2A,0x00,0x40,0x06,0x00,0x40,0x00,0x00,0x8A,0xA2,0x28,0x8E,0xE3,0x48,0x8E,0x25,0x59,0x92,0x26,0x89,0x92,0x69,0xA9,0x96,0xAB,0xC9,0x9E,0xEE,
0xE9,0xA2,0x2E,0xEA,0x40,0x68,0xC8,0x2A,0x00,0x00,0x10,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x68,0x88,0x86,0xE8,0x88,0x96,0xA8,0x89,0xA2,0x28,0x8A,0xA2,
0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,
0xA2,0x28,0x8A,0xA2,0xE8,0x79,0x9E,0xE7,0x79,0x9E,0xE7,0x79,0x9E,0x07,0x84,0x86,0xAC,0x02,0x00,0x24,0x00,0x00,0x74,0x24,0x47,0x72,0x2C,0xC5,0x52,0x24,0x45,0x52,
0x2C,0xC7,0x72,0x80,0xD0,0x90,0x55,0x00,0x80,0x0C,0x00,0x80,0x00,0x00,0x1C,0xC3,0x31,0x24,0x45,0x72,0x2C,0xCB,0xB2,0x34,0x4D,0xF3,0x3C,0xCF,0xF3,0x44,0x4F,0x14,
0x45,0x51,0x34,0x4D,0xD5,0x54,0x81,0xD0,0x90,0x55,0x00,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x45,0xB1,0x1C,0xCB,0x91,0x24,0xCD,0xF1,0x24,0xD1,
0x11,0x25,0x51,0x12,0x2D,0x51,0x12,0x35,0x51,0x13,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,
0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x11,0x08,0x0D,0x59,0x09,0x00,0x00,0x01,0x00,0xF0,0x9C,0x7B,0xED,0xBD,0xF7,0xD0,0x51,
0x29,0x25,0xF7,0x8A,0x30,0xC4,0xA0,0xF7,0x94,0x51,0x28,0xAD,0xF7,0xD0,0x38,0x82,0x9C,0xF7,0x54,0x41,0x63,0x98,0xF7,0x14,0x41,0x42,0x90,0xF5,0x5C,0x51,0x84,0x94,
0x06,0x42,0x43,0x56,0x04,0x00,0x51,0x00,0x00,0x80,0x31,0xC8,0x31,0xC4,0x1C,0x72,0xCE,0x51,0xEA,0x24,0x45,0xCE,0x39,0x2A,0x1D,0xA5,0xC6,0x39,0x47,0xA9,0xA3,0xD4,
0x51,0x4A,0xB1,0xA6,0x18,0x3B,0x4A,0x25,0xB6,0x14,0x6B,0xE3,0x9C,0xA3,0xD4,0x51,0xCA,0x28,0xA5,0x1A,0x4B,0x8B,0x1D,0xA5,0x54,0x63,0x8A,0xB1,0x00,0x00,0x80,0x00,
0x07,0x00,0x80,0x00,0x0B,0xA1,0xD0,0x90,0x15,0x01,0x40,0x14,0x00,0x00,0x62,0x0C,0x52,0x0A,0x29,0x85,0x94,0x52,0xCE,0x29,0xE6,0x90,0x52,0xCA,0x31,0xE5,0x1C,0x52,
0x4A,0x39,0xA6,0x98,0x53,0xCE,0x39,0x08,0x1D,0x84,0xCA,0x39,0x06,0x9D,0x83,0x10,0x29,0xA5,0x9C,0x53,0xCC,0x29,0xE7,0x1C,0x84,0xCC,0x41,0xE5,0x9C,0x83,0xD0,0x41,
0x28,0x00,0x00,0x20,0xC0,0x01,0x00,0x20,0xC0,0x42,0x28,0x34,0x64,0x45,0x00,0x10,0x27,0x00,0xE0,0x70,0x1C,0xCF,0x93,0x34,0x4D,0x14,0x25,0x4D,0x13,0x45,0x4F,0x14,
0x5D,0xD7,0x13,0x4D,0xD5,0x95,0x34,0xCD,0x34,0x35,0x51,0x54,0x4D,0xCD,0x13,0x4D,0xD5,0x54,0x4D,0x5B,0x16,0x4D,0xD3,0x95,0x25,0x4D,0x33,0x4D,0x4D,0xF4,0x54,0x53,
0x13,0x45,0x55,0x15,0x4D,0x53,0x76,0x4D,0x53,0x95,0x65,0xCF,0x34,0x75,0xD9,0x54,0x55,0x5D,0x16,0x55,0xD5,0x96,0x65,0x5B,0x16,0x76,0x57,0x96,0x75,0xDD,0x33,0x4D,
0xD9,0x16,0x55,0x55,0xB6,0x4D,0xD5,0x95,0x7D,0x57,0x96,0x75,0x5D,0x96,0x6D,0x5D,0x98,0x34,0xCD,0x34,0x35,0x51,0x54,0x55,0x4D,0x14,0x55,0xD7,0x54,0x55,0xDB,0x36,
0x55,0xD7,0xB6,0x35,0x51,0x74,0x5D,0x51,0x55,0x65,0x57,0x54,0x55,0x59,0x76,0x65,0xD7,0xB6,0x55,0xD7,0xD5,0x6D,0x4D,0x14,0x5D,0x55,0x54,0x4D,0x59,0x15,0x55,0xD5,
0x95,0x55,0x57,0xB5,0x65,0xD5,0x75,0x75,0xDD,0x74,0x5D,0x5F,0x57,0x65,0xD9,0xF7,0x4D,0xD7,0xF5,0x7D,0xDB,0xB6,0x85,0x5F,0xB6,0x6D,0xE1,0x18,0x55,0xD5,0xD6,0x4D,
0x57,0xD5,0x75,0xD3,0x75,0x75,0x61,0xD6,0x65,0xE1,0x97,0x6D,0x5D,0x58,0x26,0x4D,0x33,0x4D,0x4D,0x14,0x5D,0x55,0x13,0x45,0x55,0x35,0x55,0x55,0xB7,0x4D,0xD5,0x95,
0x6D,0x4D,0x14,0x5D,0x57,0x54,0x55,0xD9,0xF5,0x4C,0xD5,0x75,0x55,0xD7,0xD5,0x75,0x55,0x75,0x6D,0x5B,0x13,0x45,0xD7,0x15,0x55,0x55,0x96,0x45,0x55,0x75,0x5D,0xD5,
0x75,0x7D,0x5D,0x75,0x65,0xDB,0x16,0x55,0xD5,0xD7,0x4D,0xD7,0xF5,0x75,0x53,0x75,0x6D,0x5B,0xB6,0x75,0x63,0x98,0x65,0xDB,0xF7,0x4D,0xD7,0xD5,0x75,0x53,0x76,0x75,
0x61,0x95,0x5D,0xDD,0x97,0x75,0x5B,0x38,0x6E,0xDD,0xD6,0x85,0xCF,0x34,0x75,0xDD,0x74,0x5D,0x61,0x37,0x5D,0x57,0xF8,0x6D,0x5F,0x17,0x86,0xD9,0xD6,0x7D,0x5F,0x54,
0x5D,0xDF,0x57,0x65,0xD9,0x17,0x56,0x59,0xF6,0x7D,0xDD,0xF7,0xB1,0x75,0x5D,0x19,0x46,0x55,0x15,0x7E,0x53,0x56,0x7D,0x5F,0x75,0x5D,0x5F,0xD8,0x7D,0x5D,0x59,0x6E,
0x5F,0x67,0xBC,0xB6,0x8E,0xAD,0xFB,0xC6,0x31,0xDB,0xBA,0x30,0xFC,0xC6,0x91,0xEE,0xFB,0xCA,0xB1,0xDA,0x32,0x63,0xF6,0x65,0x61,0x98,0x75,0x1B,0x61,0xD8,0x95,0xE3,
0xF6,0x7D,0xA5,0x67,0x9A,0xBA,0x6E,0xBA,0xAA,0xEF,0x9B,0xAA,0x2B,0xFC,0xB6,0xAE,0x0B,0xC7,0xAE,0xFB,0x88,0xAA,0xAA,0xEB,0xAA,0xEC,0xFA,0xC6,0xE9,0xCA,0xC2,0x30,
0xEB,0xBA,0xB0,0xEC,0xBA,0xAF,0x1C,0xA3,0xAB,0xF2,0x55,0xD9,0xF5,0x7D,0x55,0x96,0x7D,0xE1,0xF6,0x75,0x65,0xD9,0x75,0xDF,0x38,0x5E,0xDB,0x16,0x8E,0xD9,0xD6,0x8D,
0xB2,0xAD,0x1B,0xCB,0x2E,0xFC,0x94,0x5F,0x37,0x86,0xE5,0xB5,0x6D,0x65,0x99,0x75,0x9D,0x31,0x0B,0xBB,0x71,0xEC,0xBE,0x50,0x19,0x96,0xE3,0x28,0x00,0x00,0x60,0xC0,
0x01,0x00,0x20,0xC0,0x84,0x32,0x50,0x68,0xC8,0x8A,0x00,0x20,0x4E,0x00,0x80,0x41,0x08,0x42,0xC5,0x14,0x84,0x4A,0x31,0x08,0xA1,0x84,0x96,0x42,0x28,0xA9,0x55,0x8C,
0x49,0xC9,0x1C,0x93,0x92,0x31,0x27,0xA5,0x94,0xD2,0x5A,0x28,0x25,0xB5,0x8A,0x31,0x29,0x99,0x63,0x52,0x32,0xC6,0xA4,0x84,0x52,0x5A,0x2A,0xA5,0xB4,0x16,0x4A,0x89,
0xAD,0x94,0x12,0x63,0x29,0x25,0xB6,0xD6,0x5A,0xAD,0xAD,0xB5,0x5A,0x43,0x29,0x2D,0x86,0x52,0x62,0x2C,0xA5,0xC4,0xD8,0x5A,0xCB,0xB5,0xC5,0x56,0x6B,0xC4,0x98,0x94,
0xCC,0x31,0x29,0x19,0x73,0x52,0x4A,0x29,0xAD,0x95,0x52,0x5A,0xCB,0x9C,0x93,0xD2,0x39,0x27,0xA9,0x73,0x8E,0x4A,0x29,0x29,0xC5,0x52,0x52,0x8B,0x15,0x63,0x52,0x32,
0xC7,0xA8,0x74,0xCE,0x49,0x2A,0xA9,0xC4,0x54,0x4A,0x89,0xAD,0xA4,0x12,0x63,0x29,0xA5,0xC5,0x92,0x52,0x8C,0x2D,0xC5,0x54,0x5B,0x8C,0xB5,0x86,0x52,0x5A,0x2C,0xA5,
0xC4,0x56,0x4A,0x8A,0xB1,0xC5,0x54,0x5B,0x8C,0x31,0xD7,0x88,0x31,0x29,0x19,0x63,0x52,0x32,0xE6,0xA4,0x94,0x52,0x5A,0x2B,0xA5,0xB4,0x58,0x31,0x26,0xA5,0x73,0x8E,
0x4A,0xC6,0x9C,0xA4,0x52,0x4A,0x6B,0xA5,0xA4,0x14,0x33,0xE7,0xA4,0x64,0xCE,0x49,0xEA,0x9C,0xA3,0x52,0x52,0x89,0xAD,0xA4,0x12,0x53,0x28,0x25,0xC6,0x92,0x52,0x8C,
0xA5,0x94,0x16,0x63,0x8C,0xB5,0xB6,0x14,0x5B,0x2D,0x25,0xC5,0x58,0x52,0x8A,0xB1,0x94,0x12,0x5B,0x8B,0xB1,0xD6,0x16,0x53,0x6E,0xA1,0x94,0x18,0x4B,0x29,0x31,0x96,
0x52,0x62,0x8C,0x31,0xE6,0xDC,0x62,0xAC,0x35,0x94,0x12,0x63,0x29,0x29,0xC6,0x92,0x4A,0x6C,0xB1,0xC5,0x9A,0x63,0x8C,0xB9,0x86,0x52,0x62,0x2C,0xA5,0xC4,0x56,0x4A,
0x6A,0x31,0xC6,0x96,0x6B,0x8C,0xB1,0xD6,0x16,0x5B,0xAE,0x2D,0xB5,0x5A,0x5B,0x6C,0xB9,0xD6,0x96,0x5B,0xAF,0x35,0xF7,0xDE,0x5A,0xAB,0x39,0xB5,0x94,0x6B,0x8B,0xB1,
0xE6,0x5A,0x5B,0x8F,0xB5,0xE6,0xDE,0x43,0x29,0x31,0x96,0x52,0x62,0x2C,0xA5,0xC4,0xD8,0x62,0xAB,0x35,0xC6,0x98,0x73,0x28,0x25,0xC6,0x92,0x4A,0x6C,0xA5,0x94,0x16,
0x63,0x8C,0xB5,0xB6,0x16,0x6B,0x0E,0xA5,0xC4,0x58,0x4A,0x6A,0xB1,0xA4,0x12,0x63,0x8C,0xB1,0xE6,0x18,0x63,0xAE,0xAD,0xB5,0x5C,0x5B,0x6C,0xB9,0xA6,0xD4,0x6A,0xAE,
0xB5,0x06,0x5F,0x5B,0x8D,0xC1,0xB5,0x58,0x7B,0x8C,0x31,0xE6,0xD6,0x52,0xAD,0x35,0xD7,0xDE,0x6B,0x6D,0xBD,0x15,0x00,0x00,0x30,0xE0,0x00,0x00,0x10,0x60,0x42,0x19,
0x28,0x34,0x64,0x25,0x00,0x10,0x05,0x00,0x40,0x18,0xA3,0x14,0x63,0x10,0x1A,0x64,0x18,0x73,0x0C,0x42,0x63,0x0C,0x63,0xCC,0x41,0xA8,0x18,0x73,0xCE,0x41,0x29,0x15,
0x63,0xCE,0x41,0x27,0x25,0x73,0xCC,0x41,0x28,0x29,0x65,0xCC,0x41,0x28,0x25,0xA5,0x10,0x42,0x29,0x29,0xB5,0x16,0x42,0x28,0x25,0xA5,0xD6,0x0A,0x00,0x00,0x28,0x70,
0x00,0x00,0x08,0xB0,0x41,0x53,0x62,0x71,0x80,0x42,0x43,0x56,0x02,0x00,0xA9,0x00,0x00,0x06,0xC7,0xB1,0x2C,0xCF,0x13,0x4D,0x55,0xB5,0x6D,0xC7,0x92,0x3C,0x4F,0x14,
0x55,0x55,0x55,0x6D,0xDB,0x91,0x24,0xCF,0x13,0x45,0x53,0x55,0x5D,0xDB,0xD6,0x3C,0x4F,0x14,0x55,0x53,0x55,0x5D,0x57,0xD7,0x35,0xCF,0x13,0x45,0x55,0x55,0x55,0xD7,
0xD5,0x6D,0xD1,0x34,0x55,0x55,0x55,0x5D,0x57,0x76,0x7D,0x5F,0x34,0x4D,0x55,0x55,0x55,0xD7,0x95,0x65,0xDD,0x37,0x55,0x55,0x55,0x5D,0x57,0x96,0x65,0x59,0xF8,0x4D,
0x55,0x75,0x5D,0xD7,0x75,0x65,0xDB,0xF6,0x7D,0xD5,0x75,0x5D,0x57,0x96,0x6D,0xDB,0xB6,0x85,0x61,0x75,0x5D,0xD7,0x95,0x65,0xDB,0xD6,0x6D,0x63,0xD8,0x6D,0x5D,0xD7,
0x7D,0x5F,0x38,0x96,0x61,0xA9,0xEB,0xBA,0xAE,0xFB,0xC2,0xEF,0x1B,0x43,0x02,0x00,0xC0,0x13,0x1C,0x00,0x80,0x0A,0x6C,0x58,0x1D,0xE1,0xA4,0x68,0x2C,0xB0,0xD0,0x90,
0x95,0x00,0x40,0x06,0x00,0x00,0x61,0x0C,0x42,0x06,0x21,0x85,0x0C,0x42,0x08,0x21,0xA5,0x94,0x42,0x48,0x29,0x25,0x00,0x00,0x60,0xC0,0x01,0x00,0x20,0xC0,0x84,0x32,
0x50,0x68,0xC8,0x4A,0x00,0x20,0x0A,0x00,0x00,0x20,0x44,0x4A,0x29,0xA5,0x34,0x52,0x4A,0x29,0xA5,0x94,0x46,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x08,0x21,0x84,0x10,0x42,
0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x14,0x00,0x20,0x35,0xE1,
0x00,0x20,0xF5,0x60,0x83,0xA6,0xC4,0xE2,0x00,0x85,0x86,0xAC,0x04,0x00,0x52,0x01,0x00,0x00,0x63,0x94,0x62,0xCC,0x31,0x08,0xA5,0x34,0x4C,0x39,0xE7,0x9C,0x84,0x54,
0x5A,0x6B,0x14,0x73,0xCE,0x39,0x29,0x29,0xB5,0x96,0x39,0x27,0xA1,0x94,0x96,0x62,0x8B,0x31,0x73,0x0E,0x42,0x29,0x29,0xC5,0x58,0x73,0xE6,0xA0,0x94,0x96,0x6A,0x8C,
0xB5,0xE6,0xCC,0x41,0x29,0xA9,0xC5,0x98,0x6B,0xCD,0x9D,0x94,0x96,0x62,0xCC,0x39,0x07,0x9D,0x3B,0x29,0xA9,0xD5,0x58,0x73,0xD0,0x39,0x97,0x94,0x6A,0xAC,0x35,0xE7,
0x20,0x7C,0x30,0xA9,0xC5,0x58,0x6B,0xCD,0x3D,0xE7,0xA0,0x5A,0xAC,0xB1,0xF7,0x5E,0x83,0x0F,0x42,0xB5,0x98,0x73,0xCE,0x3D,0xE7,0x9C,0x83,0x01,0x00,0x38,0x0D,0x0E,
0x00,0xA0,0x07,0x36,0xAC,0x8E,0x70,0x52,0x34,0x16,0x58,0x68,0xC8,0x4A,0x00,0x20,0x15,0x00,0x80,0x40,0x48,0x29,0xC6,0x9C,0x73,0xCE,0x39,0xA4,0x14,0x63,0xCE,0x39,
0xE7,0x1C,0x84,0x48,0x29,0xC6,0x1C,0x73,0xCE,0x39,0xE7,0x14,0x63,0x8C,0x39,0xE7,0x1C,0x84,0x10,0x2A,0xC6,0x18,0x73,0xCE,0x39,0x08,0x21,0x64,0xCE,0x39,0xE7,0x9C,
0x83,0x10,0x42,0xC8,0x9C,0x73,0xCE,0x39,0x08,0x21,0x84,0xD0,0x39,0x07,0x1D,0x84,0x10,0x42,0x08,0xA1,0x73,0x0E,0x42,0x08,0x21,0x84,0x10,0x42,0x07,0x21,0x84,0x10,
0x42,0x08,0x21,0x84,0x0E,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x14,0x00,0x00,0x58,
0xE0,0x00,0x00,0x10,0x60,0xC3,0xEA,0x08,0x27,0x45,0x63,0x81,0x85,0x86,0xAC,0x04,0x00,0x80,0x00,0x00,0x38,0xCD,0x39,0xE8,0x16,0x63,0x62,0x98,0x63,0x8E,0x9A,0x43,
0x14,0x62,0xD0,0x73,0x85,0x94,0x52,0x8E,0x9B,0x66,0x94,0x41,0x4E,0x7C,0xA6,0x14,0x42,0x4A,0x53,0xE6,0x18,0x43,0x46,0x4A,0xCC,0x3D,0x99,0x4A,0x02,0x00,0x00,0x20,
0x08,0x00,0x10,0x10,0x12,0x00,0x60,0x80,0xA0,0x60,0x06,0x00,0x18,0x1C,0x20,0x7C,0x0E,0x82,0x4E,0x80,0xE0,0x68,0x03,0x00,0x10,0x84,0xC8,0x0C,0x91,0x68,0x58,0x08,
0x0E,0x0F,0x2A,0x01,0x22,0x62,0x2A,0x00,0x48,0x4C,0x50,0xC8,0x05,0x80,0x0A,0x8B,0x8B,0xB4,0x8B,0x0B,0xE8,0x32,0xC0,0x05,0x5D,0xDC,0x75,0x20,0x84,0x20,0x04,0x21,
0x88,0xC5,0x01,0x14,0x90,0x80,0x83,0x13,0x6E,0x78,0xE2,0x0D,0x4F,0xB8,0xC1,0x09,0x3A,0x45,0xA5,0x0E,0x02,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x1E,0x00,0x00,0x8E,
0x0B,0x20,0x22,0xA2,0x39,0x8C,0x0C,0x8D,0x0D,0x8E,0x0E,0x8F,0x0F,0x90,0x90,0x00,0x00,0x00,0x00,0x00,0x70,0x01,0x80,0x0F,0x00,0x80,0x43,0x04,0x88,0x88,0x68,0x0E,
0x23,0x43,0x63,0x83,0xA3,0xC3,0xE3,0x03,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,
0x08,
};
static const uint8_t vcb_7[] = {
0x1F,0x42,0x43,0x56,0x01,0x00,0x00,0x01,0x00,0x9C,0x73,0x9A,0x31,0x87,0x99,0x62,0x94,0x52,0x89,0x21,0x94,0xDE,0x39,0x68,0x19,0x63,0x94,0x52,0x69,0x29,0xA5,0x5A,
0x4A,0xA9,0xA1,0x83,0x16,0x6B,0xAB,0xBD,0xF7,0xDE,0x7B,0xEF,0xBD,0xF7,0xDE,0x7B,0xEF,0x1D,0x73,0x94,0x31,0x46,0x95,0x52,0x52,0x4A,0xA9,0x9D,0x73,0x96,0x31,0x47,
0x15,0x63,0x52,0x4A,0x89,0xA5,0x94,0x56,0x42,0x68,0x21,0x84,0xD6,0x62,0xAB,0xBD,0xF7,0xDE,0x6B,0xEF,0xB5,0xF6,0xDE,0x7B,0xEF,0x99,0x42,0x4C,0x29,0xA4,0x14,0x42,
0x08,0x4A,0x28,0x1D,0x53,0x8C,0x29,0xA4,0x94,0x42,0x4A,0x4A,0x08,0x25,0x64,0x0E,0x3A,0xC6,0x1C,0x53,0x8C,0x52,0x09,0x3D,0xD6,0x5E,0x6B,0xCC,0xBD,0xB6,0xD8,0x7B,
0xED,0xA1,0x63,0xCE,0x39,0xE6,0x1C,0x53,0x4C,0x4A,0x68,0x21,0x74,0x0E,0x3A,0xE6,0x9C,0x53,0x4C,0x4A,0x68,0xA9,0x84,0x52,0x42,0x06,0xA1,0x53,0xD0,0x52,0x89,0xAD,
0xF7,0xDE,0x62,0xEB,0xB9,0xA5,0xDA,0x7B,0xEF,0x81,0xD0,0x90,0x55,0x00,0x00,0x01,0x00,0xC0,0x40,0x10,0x1A,0xB2,0x0A,0x00,0x50,0x00,0x00,0x10,0x8A,0xA1,0x18,0x8A,
0x02,0x84,0x86,0xAC,0x02,0x00,0x32,0x00,0x00,0x04,0xE0,0x28,0x8E,0xE3,0x38,0x8E,0xE2,0x38,0x92,0x62,0x39,0x16,0x10,0x1A,0xB2,0x0A,0x00,0x00,0x02,0x00,0x10,0x00,
0x00,0xC0,0x90,0x0C,0x4B,0xB1,0x14,0xCD,0xD1,0x24,0x4D,0xD2,0x2C,0xCF,0x13,0x4D,0xD3,0x37,0x7D,0xD3,0x36,0x6D,0x55,0xD7,0x75,0x5D,0xD7,0x75,0x5D,0xD7,0x75,0x20,
0x34,0x64,0x15,0x00,0x00,0x01,0x00,0x40,0x40,0xA7,0x19,0xA6,0x1A,0x20,0xC2,0x8C,0x64,0x16,0x08,0x0D,0x59,0x05,0x00,0x20,0x00,0x00,0x00,0x44,0x20,0xC3,0x14,0x03,
0x42,0x43,0x56,0x01,0x00,0x00,0x01,0x00,0x00,0x52,0x24,0x39,0x49,0xA2,0xE4,0xA4,0x94,0x52,0x0E,0x83,0x64,0x31,0x49,0x2A,0xE5,0xA4,0x94,0x52,0x1E,0xC5,0xE4,0x51,
0x4D,0x32,0x06,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x0A,0x83,0x64,0x39,0x4A,0x2A,0xE5,0xA4,0x94,0x52,0x12,0xA3,0x64,0x31,0x4A,0xAA,
0xD4,0xA4,0x94,0x52,0x1E,0xE5,0xE4,0x49,0x4D,0x32,0xF6,0xA4,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x16,0xA4,0xE4,0x49,0x4B,0xBA,0x06,0xA5,
0x94,0x52,0x92,0xA3,0xA4,0x41,0x4B,0x36,0xF5,0xA4,0x94,0x52,0xA2,0x14,0x25,0x4A,0x4E,0xB6,0x27,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x3E,0x28,0xE5,0x83,0x50,0x4A,0x29,0xA5,0x94,0x52,0xAE,0xF6,0xE4,0x5A,0x4F,0x4A,0x29,0xA5,0x94,0x52,0xC6,0x28,0x25,0x7C,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x32,0x82,0xD0,0x90,0x55,0x00,0x00,0x10,0x00,0x00,0x60,0x9C,0x35,0xCA,0xA1,0xE8,0x24,0x3A,0x5F,0x9C,0xA1,0x9C,0x69,0x0A,0x92,
0x0A,0xA5,0x09,0xDD,0x9B,0xE4,0x28,0x79,0x4E,0x72,0x2B,0x2D,0x37,0xA7,0x9B,0x70,0xCE,0xE9,0xE6,0x94,0x73,0x3E,0x39,0xE7,0x9C,0x20,0x34,0x64,0x15,0x00,0x00,0x08,
0x00,0x00,0x21,0x84,0x14,0x52,0x48,0x21,0x85,0x14,0x52,0x48,0x21,0x85,0x14,0x62,0x88,0x21,0x86,0x1C,0x72,0xCA,0x29,0xA8,0xA0,0x82,0x4A,0x2A,0xA9,0xA8,0xA2,0x8A,
0x2A,0xAB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x32,0xCB,0x2C,0xB3,0xCC,0x3A,0xEB,0xA8,0xA3,0xCE,0x42,0x0A,0xA1,0xA4,0xD0,0x42,0x6B,0x35,0xC6,0x1A,0x63,0x6C,
0xB5,0x37,0x27,0x6D,0xCD,0x51,0x4A,0x27,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x73,0xCE,0x39,0x27,0x08,0x0D,0x59,0x05,0x00,0x80,0x00,0x00,0x10,0x08,0x19,0x64,0x90,0x41,
0x46,0x19,0x85,0x14,0x62,0x88,0x29,0xA7,0x9C,0x72,0x0A,0x2A,0xA9,0xA4,0x02,0x42,0x43,0x56,0x01,0x00,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x44,0xC9,0x74,0x4C,0x47,
0x74,0x44,0x45,0x74,0x44,0x47,0x74,0x44,0x47,0x74,0x44,0xC7,0x73,0x3C,0xC7,0x93,0x44,0x49,0xB4,0x3C,0x4B,0xD4,0x4C,0xCF,0x14,0x4D,0xD3,0x74,0x55,0xD9,0x95,0x65,
0x5D,0xB6,0x65,0xDB,0xD5,0x65,0xDD,0xD6,0x65,0xDF,0xF6,0x6D,0xDD,0xB6,0x6D,0x5F,0x37,0x76,0xE3,0x37,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,0x8E,0xE3,0x38,
0x8E,0xE3,0x18,0x82,0xD0,0x90,0x55,0x00,0x00,0x08,0x00,0x00,0x80,0x10,0x42,0x08,0x21,0x85,0x14,0x52,0x48,0x21,0xA5,0x98,0x62,0xCC,0x39,0xE8,0x20,0x84,0x50,0x4A,
0x20,0x34,0x64,0x15,0x00,0x00,0x08,0x00,0x20,0x00,0x00,0x00,0x40,0x51,0x1C,0xC5,0x71,0x24,0x47,0x92,0x24,0xC9,0x92,0x2C,0x4B,0xB3,0x34,0x4D,0xD3,0x34,0xCD,0x13,
0x3D,0xD1,0x33,0x3D,0xD5,0x73,0x45,0x59,0xB4,0x45,0xDB,0x73,0x3D,0x5B,0xB4,0x3D,0xD7,0x53,0x3D,0xD5,0x53,0x45,0xD5,0x54,0x4D,0xD7,0x74,0x55,0xD7,0x75,0x5D,0x57,
0x75,0x55,0x59,0x95,0x5D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0x19,0x08,0x0D,0x59,0x05,0x00,0x48,0x00,0x00,0xE8,0x48,0x8E,
0xA4,0x48,0x8A,0xA4,0x48,0x8E,0xE3,0x48,0x8E,0x24,0x01,0xA1,0x21,0xAB,0x00,0x00,0x19,0x00,0x00,0x01,0x00,0x28,0x8A,0xA2,0x38,0x8E,0x23,0x39,0x96,0x64,0x49,0x9A,
0x24,0x4A,0xA6,0xA5,0x5A,0xAE,0x26,0x7B,0xBA,0xA7,0x8B,0xBA,0xA8,0x03,0xA1,0x21,0xAB,0x00,0x00,0x40,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x18,0xA2,0x21,0x1A,
0xA2,0x23,0x5A,0xA2,0x26,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,
0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0x28,0x8A,0xA2,0xE7,0x79,0x9E,0xE7,0x79,0x9E,0xE7,0x79,0x1E,0x10,0x1A,0xB2,0x0A,0x00,0x90,0x00,0x00,0xD0,
0x91,0x1C,0xC9,0xB1,0x14,0x4B,0x91,0x14,0x49,0xB1,0x1C,0xCB,0x01,0x42,0x43,0x56,0x01,0x00,0x32,0x00,0x00,0x02,0x00,0x70,0x0C,0xC7,0x90,0x14,0xC9,0xB1,0x2C,0xCB,
0xD2,0x34,0xCD,0xF3,0x3C,0xCF,0x13,0x3D,0x51,0x14,0x45,0xD1,0x34,0x55,0x53,0x05,0x42,0x43,0x56,0x01,0x00,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x50,0x14,
0xC5,0x72,0x2C,0x47,0x92,0x34,0xC7,0x93,0x44,0x47,0x94,0x44,0x49,0xB4,0x44,0x49,0xD4,0x44,0x4D,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,
0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x51,0x14,0x45,0x20,0x34,0x64,0x25,0x00,0x00,0x04,
0x00,0x40,0x49,0x6A,0xB1,0xB5,0xD6,0x28,0x05,0xA1,0xA4,0x98,0x18,0xC2,0x94,0x93,0x1C,0x31,0x06,0x1D,0xA4,0x5E,0x31,0xE4,0x10,0x93,0x9E,0x39,0x06,0x15,0x93,0x5E,
0x2A,0x82,0x0C,0x62,0x1E,0x3B,0xC4,0x14,0x93,0x1C,0x08,0x0D,0x59,0x11,0x00,0x44,0x01,0x00,0x00,0xC6,0x20,0xC7,0x10,0x73,0xC8,0x39,0x47,0xA9,0x93,0x14,0x39,0xE7,
0xA4,0x74,0x94,0x1A,0xE7,0x1C,0xA5,0x8E,0x52,0x47,0x29,0xC5,0x9A,0x62,0xCD,0x28,0x95,0xDA,0x52,0xAC,0x8D,0x73,0x8E,0x52,0x47,0xA9,0xA3,0x94,0x6A,0x2C,0x2D,0x76,
0xD4,0x52,0xAD,0xA9,0xC6,0x02,0x00,0x00,0x02,0x1C,0x00,0x00,0x02,0x2C,0x84,0x42,0x43,0x56,0x04,0x00,0x51,0x00,0x00,0x84,0x31,0x48,0x29,0xA4,0x14,0x62,0x8A,0x39,
0xA7,0x98,0x43,0x8A,0x29,0xC7,0x98,0x73,0x88,0x31,0xE6,0x1C,0x73,0x8E,0x39,0xE7,0xA0,0x74,0x52,0x2A,0xE7,0x98,0x74,0x4E,0x4A,0xC4,0x18,0x73,0x8E,0x39,0xA7,0x9C,
0x73,0x52,0x32,0x27,0x95,0x73,0x4E,0x4A,0x27,0xA1,0x00,0x00,0x80,0x00,0x07,0x00,0x80,0x00,0x0B,0xA1,0xD0,0x90,0x15,0x01,0x40,0x9C,0x00,0x80,0x41,0x92,0x3C,0x4F,
0xD2,0x34,0x51,0x94,0x34,0x4F,0x14,0x3D,0x53,0x74,0x55,0x4F,0x34,0x55,0xD7,0xF2,0x3C,0xD3,0xF4,0x4C,0x53,0x55,0x3D,0xD1,0x54,0x55,0xD3,0x55,0x65,0xD9,0x54,0x55,
0x59,0xB6,0x3C,0xCF,0x34,0x3D,0x53,0x54,0x55,0xCF,0x34,0x55,0xD5,0x54,0x55,0x59,0x36,0x55,0x55,0x96,0x45,0x55,0xD5,0x6D,0xD3,0x55,0x75,0xDB,0x74,0x55,0xDD,0x76,
0x6D,0xD9,0xD7,0x5D,0x59,0x16,0x76,0x51,0x55,0x6D,0xDB,0x54,0x5D,0x5B,0x37,0x55,0xD7,0x16,0x5E,0xD9,0xD6,0x7D,0x59,0xB6,0x75,0x61,0xF2,0x3C,0x55,0xF5,0x4C,0xD3,
0x75,0x3D,0xD3,0x74,0x5D,0xD5,0x75,0x75,0x5B,0x75,0x5D,0x5B,0xF7,0x4C,0x53,0x76,0x4D,0xD7,0x95,0x65,0xD3,0x75,0x6D,0xDB,0x95,0x65,0x5D,0x57,0x65,0x59,0xF7,0x35,
0xD3,0x74,0x5D,0xD1,0x55,0x6D,0xD9,0x74,0x5D,0xD9,0x76,0x65,0x57,0xD7,0x5D,0x59,0xF6,0x85,0xD3,0x75,0x75,0xDF,0x95,0x65,0x61,0x57,0x65,0x59,0xF8,0x75,0x5D,0x17,
0x86,0x59,0xF7,0x8D,0x63,0x74,0x5D,0x5D,0x58,0x65,0xD7,0xF7,0x55,0x59,0xF6,0x8D,0x5B,0xB7,0x7D,0x5F,0xD6,0x75,0xE1,0x98,0x3C,0x4F,0x55,0x3D,0xD3,0x74,0x5D,0xCF,
0x34,0x5D,0xD7,0x74,0x5D,0x5D,0x57,0x5D,0xD7,0xD6,0x35,0xD3,0x74,0x5D,0xD3,0x75,0x6D,0x5B,0x54,0x5D,0x59,0x76,0x65,0xD9,0xF7,0x5D,0x57,0xD6,0x75,0xCF,0x34,0x5D,
0xD9,0x74,0x5D,0xD9,0x36,0x5D,0x57,0x96,0x5D,0x59,0xF6,0x7D,0x57,0x96,0x75,0xDD,0x74,0x5D,0xDD,0x57,0x65,0x59,0xF8,0x55,0x57,0x16,0x7E,0x59,0xD7,0x8D,0xE5,0xB6,
0x6D,0xE1,0x37,0x5D,0x57,0xD7,0x55,0x59,0xD6,0x7D,0x55,0x96,0x75,0x61,0xD6,0x75,0xE3,0xB9,0x75,0x5D,0x18,0x3E,0x55,0xD5,0x7D,0x53,0x76,0x85,0xDF,0x74,0x65,0x5F,
0xD8,0x7D,0xDD,0x59,0x6E,0xDD,0x37,0x96,0xD1,0x75,0x75,0x61,0x95,0x6D,0xE3,0x58,0x65,0x5B,0x18,0x7E,0xE1,0x58,0x96,0xDD,0x37,0x96,0x67,0x74,0x5D,0xDF,0x57,0x6D,
0x57,0x18,0x56,0x59,0xF6,0x95,0xDD,0xD7,0x9D,0x65,0xD7,0x75,0x65,0x78,0x6D,0xDB,0x58,0x6E,0x5D,0x57,0x8E,0x59,0xD7,0x8D,0x61,0x38,0x96,0xA7,0xEE,0x0B,0x4F,0x57,
0xB7,0x85,0x63,0xF6,0x6D,0xE7,0x99,0x7D,0x5D,0x39,0x7E,0x67,0x78,0x96,0x5F,0xF8,0x29,0x9F,0xAA,0xEA,0xBA,0xE9,0xBA,0xC2,0x70,0xBA,0xB2,0xEF,0xCB,0xB6,0x2E,0x0C,
0xBB,0x2F,0x2C,0xCB,0xE8,0xBA,0xBE,0xB0,0xCA,0xB2,0xF1,0xAB,0xB2,0xEC,0x0B,0xB7,0xEE,0x2B,0xC7,0xEE,0x0B,0xC3,0x31,0xBA,0xAE,0xF0,0xAB,0xB6,0xEC,0xFB,0xAE,0x2D,
0x0B,0xC7,0xED,0xEB,0xC6,0x32,0x0C,0xC3,0x72,0xBC,0xB6,0xAD,0x0C,0xB3,0xAE,0x0B,0x65,0xDB,0x47,0xF7,0x7D,0xA5,0xEF,0x2B,0x4B,0x57,0xB7,0x95,0x63,0xD6,0x75,0xA5,
0xED,0xEB,0x94,0x5D,0x18,0x2A,0xC3,0x31,0x54,0x06,0x00,0x00,0x0C,0x38,0x00,0x00,0x04,0x98,0x50,0x06,0x0A,0x0D,0x59,0x11,0x00,0xC4,0x09,0x00,0x30,0x08,0x39,0x87,
0x98,0x82,0x10,0x29,0x06,0x21,0x84,0x90,0x52,0x08,0x21,0xA5,0x88,0x31,0x08,0x99,0x73,0x52,0x2A,0xE6,0xA0,0x94,0x52,0x52,0x0B,0xA5,0xA4,0x16,0x31,0x06,0xA1,0x72,
0x4C,0x4A,0xE6,0x9C,0x94,0x50,0x4A,0x4B,0xA5,0x94,0x96,0x42,0x29,0xAD,0x95,0x54,0x62,0x0C,0xA5,0xC4,0xD8,0x5A,0xAB,0x35,0xB5,0x56,0x6B,0x28,0xA5,0xB5,0x50,0x4A,
0x8C,0xA5,0x94,0x16,0x53,0x6B,0xB5,0xB6,0xD8,0x6A,0x8D,0x18,0x93,0x92,0x39,0x27,0x25,0x73,0x4E,0x4A,0x29,0x25,0xB6,0x52,0x4A,0x6B,0x99,0x73,0x54,0x3A,0x07,0x25,
0x75,0x10,0x52,0x2A,0x25,0xB5,0x58,0x52,0x8A,0xB5,0x72,0x4E,0x4A,0x06,0x1D,0x95,0x0E,0x42,0x4A,0x25,0x95,0x98,0x4A,0x4A,0x31,0x96,0x54,0x62,0x2C,0x25,0xC5,0x5A,
0x52,0xAA,0xB1,0xA5,0xD8,0x6A,0x8B,0x31,0xE7,0x50,0x4A,0x8C,0x25,0x95,0x18,0x4B,0x4A,0xB1,0xB6,0x98,0x72,0x6B,0x31,0xD6,0x1C,0x31,0x26,0x21,0x73,0x4E,0x4A,0xE6,
0x9C,0x94,0x52,0x4A,0x6B,0xA5,0x94,0x16,0x2B,0xE7,0xA4,0x74,0x10,0x52,0xCA,0x1C,0x94,0x54,0x52,0x8A,0xB1,0x94,0x94,0x6A,0xE6,0x9C,0x94,0x0E,0x42,0x4A,0x1D,0x74,
0x54,0x4A,0x4A,0x31,0x96,0x54,0x62,0x0A,0xA5,0xC4,0x58,0x52,0xAA,0xB1,0x94,0xD4,0x62,0x8C,0x31,0xD7,0x96,0x62,0xCB,0xA1,0xA4,0x18,0x4B,0x4A,0xB1,0x96,0x54,0x62,
0x6C,0x31,0xE6,0xDC,0x62,0xCA,0xAD,0x93,0x12,0x5B,0x49,0x29,0xC6,0x50,0x52,0x8C,0x31,0xC6,0x9C,0x5B,0x8C,0x39,0x87,0x52,0x62,0x2C,0x29,0xC5,0x5A,0x52,0xAA,0x31,
0xC6,0x5A,0x73,0x8C,0xB1,0xE6,0x50,0x4A,0x8C,0x25,0x95,0x1A,0x4B,0x4A,0xB1,0xC6,0x1A,0x73,0x6D,0x31,0xD6,0x9C,0x62,0xCC,0x35,0xA5,0x58,0x73,0xAB,0x31,0xE7,0xD8,
0x72,0xEB,0xB5,0xE6,0xE0,0x53,0x6B,0x35,0xA7,0x98,0x72,0x6D,0x31,0xE6,0x5C,0x6B,0x0B,0xB2,0xE6,0x5C,0x7C,0x27,0x25,0xB6,0x50,0x4A,0x8C,0xA5,0xA4,0x18,0x5B,0x8C,
0xB5,0xB6,0x18,0x73,0x0E,0xA5,0xC4,0x58,0x52,0xAA,0xB1,0x94,0x14,0x6B,0x8B,0x31,0xE8,0xD6,0x62,0xED,0xA1,0x94,0x18,0x4B,0x4A,0x31,0x96,0x54,0x6A,0x8C,0x31,0xD6,
0x1C,0x6B,0xCC,0x39,0xC5,0x56,0x6B,0x8B,0xB1,0xD7,0xD4,0x62,0xCE,0x35,0xF7,0x60,0x6C,0xCB,0xB5,0xA7,0x16,0x6B,0x6E,0x31,0xE6,0x9E,0x62,0xCA,0xB5,0xF6,0xDA,0x83,
0xCD,0xAD,0xB7,0x02,0x00,0x00,0x06,0x1C,0x00,0x00,0x02,0x4C,0x28,0x03,0x85,0x86,0xAC,0x04,0x00,0xA2,0x00,0x00,0x00,0x63,0x18,0x73,0x0E,0x42,0xA3,0x90,0x73,0xCE,
0x49,0x69,0x90,0x72,0xCE,0x39,0x29,0x99,0x73,0x10,0x42,0x48,0x29,0x73,0x0E,0x42,0x08,0x29,0x75,0xCE,0x49,0x28,0xA9,0xB5,0xCE,0x39,0x08,0x29,0xB5,0x16,0x4A,0x49,
0xA9,0xB5,0x18,0x43,0x29,0x29,0xB5,0x16,0x63,0x01,0x00,0x00,0x05,0x0E,0x00,0x00,0x01,0x36,0x68,0x4A,0x2C,0x0E,0x50,0x68,0xC8,0x4A,0x00,0x20,0x15,0x00,0xC0,0xE0,
0x38,0x96,0xE5,0x79,0xA6,0x68,0x9A,0xB6,0xED,0x58,0x92,0xE7,0x89,0xA2,0x69,0xAA,0xAA,0x6D,0x3B,0x92,0xE5,0x79,0xA2,0x68,0x9A,0xAA,0x6A,0xDB,0x9A,0xE7,0x89,0xA2,
0x69,0xAA,0xAA,0xEB,0xEA,0xBA,0xE6,0x79,0xA2,0x68,0x9A,0xAA,0xEA,0xBA,0xB6,0x2E,0x8A,0xA2,0x69,0xAA,0xAA,0xAB,0xBA,0xAE,0xEE,0x8B,0xA2,0x68,0x9A,0xAA,0xAA,0xAA,
0xAE,0xAB,0xEB,0xA6,0x69,0xAA,0xAA,0xAB,0xBA,0xAE,0x2C,0xFB,0xBE,0x69,0x9A,0xAA,0xEA,0xBA,0xAE,0x2B,0xCB,0xBE,0xB0,0xAA,0xAE,0xEB,0xCA,0xB2,0x2D,0xDB,0xB6,0x31,
0xAC,0xAA,0xEA,0xBA,0xAE,0x2B,0xDB,0xB6,0x6D,0x1C,0xB7,0x6D,0xEB,0xBA,0xEE,0xFB,0xBE,0x30,0x54,0x6E,0xDB,0xD6,0x75,0x5F,0xF8,0x85,0x61,0x58,0x0A,0x00,0x00,0x4F,
0x70,0x00,0x00,0x2A,0xB0,0x61,0x75,0x84,0x93,0xA2,0xB1,0xC0,0x42,0x43,0x56,0x02,0x00,0x19,0x00,0x00,0x84,0x31,0x08,0x19,0x84,0x10,0x32,0x08,0x21,0x84,0x94,0x52,
0x0A,0x29,0xA5,0x94,0x00,0x00,0x80,0x01,0x07,0x00,0x80,0x00,0x13,0xCA,0x40,0xA1,0x21,0x2B,0x02,0x80,0x38,0x01,0x00,0x00,0x21,0x4A,0x21,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0xD4,0x51,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x42,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,
0x29,0xA5,0x94,0x52,0x4A,0x1D,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,
0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x4A,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x2A,
0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,
0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,
0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,
0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,
0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x4A,0x29,0xA5,0x94,0x52,0x00,0x80,
0x54,0x84,0x03,0x80,0xD4,0x83,0x09,0x65,0xA0,0xD0,0x90,0x95,0x00,0x40,0x2A,0x00,0x00,0x60,0x8C,0x52,0x8C,0x39,0x07,0xA1,0x94,0x86,0x31,0xE7,0x9C,0x83,0x90,0x4A,
0x4B,0x8D,0x62,0xCE,0x31,0x07,0xA1,0xA4,0x96,0x32,0xE7,0x20,0x94,0x92,0x52,0x4B,0x31,0x66,0xCE,0x41,0x29,0x25,0xA5,0xD6,0x5A,0xCC,0x9C,0x93,0xD2,0x5A,0x6C,0x3D,
0xC6,0x9A,0x39,0x27,0xA9,0xB5,0xD8,0x62,0xAC,0xB5,0x83,0xD2,0x5A,0x8D,0x3D,0xF7,0xDE,0x73,0x27,0xA5,0xB5,0x1A,0x6B,0xEE,0x3D,0xF7,0x92,0x5A,0xAD,0xB5,0xF6,0xD8,
0x73,0xEF,0x25,0xB5,0x18,0x73,0xAD,0xB9,0xF7,0x5A,0x63,0x8D,0xB9,0xF7,0x9E,0x73,0xEF,0xBD,0xA7,0x5C,0x7B,0xAF,0xB5,0xE7,0x5E,0x7B,0x2E,0x00,0x00,0xA7,0xC1,0x01,
0x00,0xF4,0xC0,0x86,0xD5,0x11,0x4E,0x8A,0xC6,0x02,0x0B,0x0D,0x59,0x09,0x00,0xA4,0x02,0x00,0x10,0x08,0x29,0xC5,0x98,0x73,0xCE,0x39,0x87,0x90,0x62,0xCC,0x39,0xE7,
0x20,0x84,0x10,0x21,0xC4,0x98,0x73,0xCE,0x41,0x08,0xA1,0x62,0x8C,0x39,0xE7,0x20,0x84,0x10,0x42,0xC5,0x98,0x63,0xCE,0x41,0x08,0x21,0x84,0xCE,0x39,0xE7,0x9C,0x83,
0x10,0x42,0x08,0x9D,0x73,0xCE,0x39,0x07,0x21,0x84,0x10,0x3A,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x74,0x0E,0x42,0x08,0x1D,0x84,0x10,0x42,0xE8,0x20,0x84,0x10,0x42,
0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0xA1,0x83,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x02,0x00,0x00,0x0B,
0x1C,0x00,0x00,0x02,0x6C,0x58,0x1D,0xE1,0xA4,0x68,0x2C,0xB0,0xD0,0x90,0x95,0x00,0x00,0x10,0x00,0x00,0xC2,0xAC,0xE4,0x12,0x8A,0x24,0x90,0x72,0x0C,0x9A,0x69,0x8C,
0x52,0x8E,0x9A,0x88,0x14,0x62,0x0A,0x9A,0xCA,0x10,0x43,0x4C,0x9A,0xA9,0x98,0x52,0xCA,0x81,0xE8,0x24,0x63,0x08,0x81,0x2A,0xCA,0xC6,0xD0,0x91,0x00,0x00,0x00,0x04,
0x01,0x00,0x01,0x26,0x80,0xC0,0x00,0x41,0xC1,0x17,0x42,0x40,0x8C,0x01,0x00,0x08,0x42,0x64,0x86,0x48,0x28,0xAC,0x82,0x05,0x06,0x65,0xD0,0xE0,0x30,0x0F,0x00,0x1E,
0x20,0x22,0x24,0x02,0x80,0xC4,0x04,0x45,0xDA,0xC5,0x05,0x74,0x19,0xE0,0x82,0x2E,0xEE,0x3A,0x10,0x42,0x10,0x82,0x10,0xC4,0xE2,0x00,0x0A,0x48,0xC0,0xC1,0x09,0x37,
0x3C,0xF1,0x86,0x27,0xDC,0xE0,0x04,0x9D,0xA2,0x52,0x07,0x01,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x00,0x00,0x07,0x05,0x10,0x11,0xD1,0x5C,0x85,0xC5,0x05,0x46,
0x86,0xC6,0x06,0x47,0x87,0x47,0x00,0x00,0x00,0x00,0x00,0xA8,0x00,0xC0,0x07,0x00,0xC0,0xF1,0x01,0x44,0x44,0x34,0x57,0x61,0x71,0x81,0x91,0xA1,0xB1,0xC1,0xD1,0xE1,
0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x04,
};
static const vcb_info_t vcb_list[] = {
{0x01,0x0CD8,vcb_1},
{0x02,0x0B72,vcb_2},
{0x03,0x0DF7,vcb_3},
{0x04,0x1025,vcb_4},
{0x05,0x0C01,vcb_5},
{0x06,0x0C01,vcb_6},
{0x07,0x0CD8,vcb_7},
};
static const int vcb_list_count = sizeof(vcb_list) / sizeof(vcb_list[0]);
#endif

View file

@ -0,0 +1,181 @@
#include "coding.h"
#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"
/* opaque struct */
typedef struct {
MIOFile* miofile;
MIODecoder* miodec;
MIOContext* mioctx;
/* current buf */
void* sbuf;
int samples;
int channels;
int fmtsize;
io_callback_t cb;
io_priv_t io_priv;
int start_offset;
} mio_codec_data;
static void free_mio(void* priv_data) {
mio_codec_data* data = priv_data;
if (!data) return;
MIOFile_Close(data->miofile);
MIODecoder_Close(data->miodec);
MIOContext_Close(data->mioctx);
ERI_eriCloseLibrary();
free(data);
}
void* init_mio(STREAMFILE* sf, int* p_loop_start) {
ERI_eriInitializeLibrary();
mio_codec_data* data = calloc(1, sizeof(mio_codec_data));
if (!data) return NULL;
io_callbacks_set_sf(&data->cb, &data->io_priv);
data->io_priv.offset = 0;
data->io_priv.sf = sf; //temp, will be updated later
data->miofile = MIOFile_Open();
if (!data->miofile) goto fail;
if (MIOFile_Initialize(data->miofile, &data->cb))
goto fail;
data->miodec = MIODecoder_Open();
if (!data->miodec) goto fail;
if (MIODecoder_Initialize(data->miodec, &data->miofile->mioih))
goto fail;
data->mioctx = MIOContext_Open();
if (!data->mioctx) goto fail;
data->start_offset = data->io_priv.offset;
//TODO: lowest quality files allow 8-bit PCM
if (data->miofile->mioih.dwBitsPerSample == 8) {
goto fail;
}
//TODO: improve get info from libs
if (p_loop_start) {
*p_loop_start = data->miofile->mioih.rewindPoint;
}
return data;
fail:
free_mio(data);
return NULL;
}
static bool read_frame(mio_codec_data* data, STREAMFILE* sf) {
data->io_priv.sf = sf;
//data->io_priv.offset = ...; // persists between calls
// read new packet into buffer
int err = MIOFile_NextPacket(data->miofile, &data->cb);
if (err == eslErrEof)
return false;
if (err) {
VGM_LOG("MIO: decode packet error\n");
return false;
}
// current block is keyframe and can be used to seek/decode start
// number depends on coding mode but usually 1 keyframe per 3-7 non-keyframe blocks (~32768 samples per block)
//if (data->miofile->miodh.bytFlags & MIO_LEAD_BLOCK) {
// ...
//}
return true;
}
static bool decode_frame(mio_codec_data* data, sbuf_t* sbuf) {
// calculate current buffer size
void* ptrWaveBuf = MIOFile_GetCurrentWaveBuffer(data->miofile);
if (!ptrWaveBuf) {
VGM_LOG("MIO: buffer error\n");
return false;
}
// pass buffer to context (bitreader)
MIOContext_AttachInputFile(data->mioctx, data->miofile->packet, data->miofile->packet_size);
// convert data into samples
if (MIODecoder_DecodeSound(data->miodec, data->mioctx, &data->miofile->miodh, ptrWaveBuf)) {
VGM_LOG("MIO: decode error\n");
return false;
}
//int bufferCount = MIOFile_GetCurrentWaveBufferCount(hnd->miofile);
int samples = data->miofile->miodh.dwSampleCount;
int channels = data->miofile->mioih.dwChannelCount;
sfmt_t format = SFMT_S16;
//int fmtsize = data->miofile->mioih.dwBitsPerSample / 8;
//if (fmtsize == 8)
// format = SFMT_S8;
sbuf_init(sbuf, format, ptrWaveBuf, samples, channels);
sbuf->filled = samples;
return true;
}
bool decode_frame_mio(VGMSTREAM* v) {
VGMSTREAMCHANNEL* vs = &v->ch[0];
mio_codec_data* data = v->codec_data;
decode_state_t* ds = v->decode_state;
bool ok = read_frame(data, vs->streamfile);
if (!ok)
return false;
ok = decode_frame(data, &ds->sbuf);
if (!ok)
return false;
return true;
}
static void reset_mio(void* priv_data) {
mio_codec_data* data = priv_data;
if (!data) return;
data->io_priv.offset = data->start_offset;
MIOContext_FlushBuffer(data->mioctx);
MIOFile_Reset(data->miofile, &data->cb);
}
static void seek_mio(VGMSTREAM* v, int32_t num_sample) {
mio_codec_data* data = v->codec_data;
decode_state_t* ds = v->decode_state;
if (!data) return;
reset_mio(data);
// (due to implicit encode delay the above is byte-exact equivalent vs a discard loop)
ds->discard = num_sample;
}
const codec_info_t mio_decoder = {
.sample_type = SFMT_S16,
.decode_frame = decode_frame_mio,
.free = free_mio,
.reset = reset_mio,
.seek = seek_mio,
};

View file

@ -1,82 +1,92 @@
#include "coding.h" #include "coding.h"
#include "coding_utils_samples.h" #include "../base/decode_state.h"
#include "../base/codec_info.h"
#ifdef VGM_USE_SPEEX #ifdef VGM_USE_SPEEX
#include "speex/speex.h" #include "speex/speex.h"
#define SPEEX_MAX_FRAME_SIZE 0x100 /* frame sizes are stored in a byte */ #define SPEEX_MAX_FRAME_SIZE 0x100 /* frame sizes are stored in a byte */
#define SPEEX_MAX_FRAME_SAMPLES 640 /* nb=160, wb/uwb=320*2 */ #define SPEEX_MAX_FRAME_SAMPLES 640 /* nb=160, wb/uwb=320*2 */
#define SPEEX_MAX_CHANNELS 1 /* nb=160, wb/uwb=320*2 */
#define SPEEX_CTL_OK 0 /* -1=request unknown, -2=invalid param */ #define SPEEX_CTL_OK 0 /* -1=request unknown, -2=invalid param */
#define SPEEX_DECODE_OK 0 /* -1 for end of stream, -2 corrupt stream */ #define SPEEX_DECODE_OK 0 /* -1 for end of stream, -2 corrupt stream */
typedef enum { EA, TORUS } type_t; typedef enum { EA, TORUS } speex_type_t;
/* opaque struct */ /* opaque struct */
struct speex_codec_data { typedef struct {
type_t type; speex_type_t type;
/* config */ /* config */
int channels; int channels;
int samples_discard;
int encoder_delay; int encoder_delay;
int samples_discard;
uint8_t buf[SPEEX_MAX_FRAME_SIZE]; uint8_t buf[SPEEX_MAX_FRAME_SIZE];
int frame_size; int frame_size;
int16_t* samples; short pbuf[SPEEX_MAX_FRAME_SAMPLES * SPEEX_MAX_CHANNELS];
int frame_samples; int frame_samples;
/* frame state */ /* frame state */
s16buf_t sbuf; void* handle;
void* state;
SpeexBits bits; SpeexBits bits;
}; } speex_codec_data;
/* raw SPEEX */ static void free_speex(void* priv_data) {
static speex_codec_data* init_speex(type_t type, int channels) { speex_codec_data* data = priv_data;
if (!data)
return;
if (data->handle) {
speex_decoder_destroy(data->handle);
speex_bits_destroy(&data->bits);
}
free(data);
}
// raw-ish SPEEX (without Ogg)
static speex_codec_data* init_speex(speex_type_t type, int channels) {
int res, sample_rate; int res, sample_rate;
speex_codec_data* data = NULL; speex_codec_data* data = NULL;
// not seen, unknown layout (known cases use xN mono decoders)
if (channels > SPEEX_MAX_CHANNELS)
return NULL;
data = calloc(1, sizeof(speex_codec_data)); data = calloc(1, sizeof(speex_codec_data));
if (!data) goto fail; if (!data) goto fail;
data->type = type; data->type = type;
//TODO: unknown layout (known samples are mono, EA: N decoders, Torus: N too?)
data->channels = channels; data->channels = channels;
if (channels != 1)
goto fail;
/* Modes: narrowband=nb, wideband=wb, ultrawideband=uwb modes. // Modes: narrowband=nb, wideband=wb, ultrawideband=uwb modes.
* EASpeex seem to always use uwb so use that for now until config is needed. // Known decoders seem to always use uwb so use that for now until config is needed.
* Examples normally use &speex_*_mode but export seem problematic? */ // Examples normally use &speex_*_mode but exports seem problematic?
data->state = speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_UWB)); data->handle = speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_UWB));
if (!data->state) goto fail; if (!data->handle) goto fail;
speex_bits_init(&data->bits); speex_bits_init(&data->bits);
res = speex_decoder_ctl(data->state, SPEEX_GET_FRAME_SIZE, &data->frame_samples); res = speex_decoder_ctl(data->handle, SPEEX_GET_FRAME_SIZE, &data->frame_samples);
if (res != SPEEX_CTL_OK) goto fail; if (res != SPEEX_CTL_OK) goto fail;
if (data->frame_samples > SPEEX_MAX_FRAME_SAMPLES) if (data->frame_samples > SPEEX_MAX_FRAME_SAMPLES)
goto fail; goto fail;
/* forced in EA's code, doesn't seem to affect decoding (all EAAC headers use this rate too) */ // forced in EA's code, doesn't seem to affect decoding (all EAAC headers use this rate too)
sample_rate = 32000; sample_rate = 32000;
res = speex_decoder_ctl(data->state, SPEEX_SET_SAMPLING_RATE, &sample_rate); res = speex_decoder_ctl(data->handle, SPEEX_SET_SAMPLING_RATE, &sample_rate);
if (res != SPEEX_CTL_OK) goto fail; if (res != SPEEX_CTL_OK) goto fail;
/* default "latency" for EASpeex */ /* default "latency" for EASpeex */
data->encoder_delay = 509; data->encoder_delay = 509;
data->samples_discard = data->encoder_delay; data->samples_discard = data->encoder_delay;
data->samples = malloc(channels * data->frame_samples * sizeof(int16_t));
if (!data->samples) goto fail;
return data; return data;
fail: fail:
@ -84,38 +94,27 @@ fail:
return NULL; return NULL;
} }
speex_codec_data* init_speex_ea(int channels) { void* init_speex_ea(int channels) {
return init_speex(EA, channels); return init_speex(EA, channels);
} }
speex_codec_data* init_speex_torus(int channels) { void* init_speex_torus(int channels) {
return init_speex(TORUS, channels); return init_speex(TORUS, channels);
} }
static int decode_frame(speex_codec_data* data) { static int decode_frame(speex_codec_data* data) {
int res;
data->sbuf.samples = data->samples;
data->sbuf.channels = 1;
data->sbuf.filled = 0;
speex_bits_read_from(&data->bits, (const char*)data->buf, data->frame_size); speex_bits_read_from(&data->bits, (const char*)data->buf, data->frame_size);
res = speex_decode_int(data->state, &data->bits, data->sbuf.samples); // speex_decode() returns samples (F32), but internally speex decodes into pcm16
if (res != SPEEX_DECODE_OK) goto fail; int res = speex_decode_int(data->handle, &data->bits, data->pbuf);
if (res != SPEEX_DECODE_OK) return -1;
data->sbuf.filled = data->frame_samples; return data->frame_samples;
return 1;
fail:
return 0;
} }
/* for simple style speex (seen in EA-Speex and libspeex's sampledec.c) */ // for simple style speex (seen in EA-Speex and libspeex's sampledec.c)
static int read_frame(speex_codec_data* data, VGMSTREAMCHANNEL* stream) { static bool read_frame(speex_codec_data* data, VGMSTREAMCHANNEL* stream) {
size_t bytes;
switch(data->type) { switch(data->type) {
case EA: case EA:
data->frame_size = read_u8(stream->offset, stream->streamfile); data->frame_size = read_u8(stream->offset, stream->streamfile);
@ -128,87 +127,71 @@ static int read_frame(speex_codec_data* data, VGMSTREAMCHANNEL* stream) {
default: default:
break; break;
} }
if (data->frame_size == 0) goto fail; if (data->frame_size == 0)
return false;
bytes = read_streamfile(data->buf, stream->offset, data->frame_size, stream->streamfile); size_t bytes = read_streamfile(data->buf, stream->offset, data->frame_size, stream->streamfile);
stream->offset += data->frame_size; stream->offset += data->frame_size;
if (bytes != data->frame_size) goto fail;
return 1; if (bytes != data->frame_size)
fail: return false;
return 0;
return true;
} }
void decode_speex(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do) { static bool decode_frame_speex(VGMSTREAM* v) {
VGMSTREAMCHANNEL* stream = &vgmstream->ch[0]; VGMSTREAMCHANNEL* stream = &v->ch[0];
speex_codec_data* data = vgmstream->codec_data; speex_codec_data* data = v->codec_data;
int ok; decode_state_t* ds = v->decode_state;
bool ok = read_frame(data, stream);
if (!ok) return false;
while (samples_to_do > 0) { int samples = decode_frame(data);
s16buf_t* sbuf = &data->sbuf; if (samples < 0) return false;
if (sbuf->filled <= 0) { sbuf_init_s16(&ds->sbuf, data->pbuf, samples, data->channels);
ok = read_frame(data, stream); ds->sbuf.filled = ds->sbuf.samples;
if (!ok) goto fail;
ok = decode_frame(data); if (data->samples_discard) {
if (!ok) goto fail; ds->discard += data->samples_discard;
data->samples_discard = 0;
} }
if (data->samples_discard) return true;
s16buf_discard(&outbuf, sbuf, &data->samples_discard);
else
s16buf_consume(&outbuf, sbuf, &samples_to_do);
}
return;
fail:
/* on error just put some 0 samples */
VGM_LOG("SPEEX: decode fail at %x, missing %i samples\n", (uint32_t)stream->offset, samples_to_do);
s16buf_silence(&outbuf, &samples_to_do, data->channels);
} }
static void reset_speex(void* priv_data) {
void reset_speex(speex_codec_data* data) { speex_codec_data* data = priv_data;
int res;
if (!data) return;
res = speex_decoder_ctl(data->state, SPEEX_RESET_STATE, NULL);
if (res != SPEEX_CTL_OK) goto fail;
data->sbuf.filled = 0;
data->samples_discard = data->encoder_delay;
return;
fail:
return; /* ? */
}
void seek_speex(VGMSTREAM* vgmstream, int32_t num_sample) {
speex_codec_data* data = vgmstream->codec_data;
if (!data) return;
reset_speex(data);
data->samples_discard += num_sample;
/* loop offsets are set during decode; force them to stream start so discard works */
if (vgmstream->loop_ch)
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset;
}
void free_speex(speex_codec_data* data) {
if (!data) if (!data)
return; return;
if (data->state) { int res = speex_decoder_ctl(data->handle, SPEEX_RESET_STATE, NULL);
speex_decoder_destroy(data->state); if (res != SPEEX_CTL_OK)
speex_bits_destroy(&data->bits); return; //???
}
free(data->samples); data->samples_discard = data->encoder_delay;
free(data);
} }
static void seek_speex(VGMSTREAM* v, int32_t num_sample) {
decode_state_t* ds = v->decode_state;
speex_codec_data* data = v->codec_data;
if (!data) return;
reset_speex(data);
ds->discard = num_sample;
// loop offsets are set during decode; force them to stream start so discard works
if (v->loop_ch)
v->loop_ch[0].offset = v->loop_ch[0].channel_start_offset;
}
const codec_info_t speex_decoder = {
.sample_type = SFMT_S16,
.decode_frame = decode_frame_speex,
.free = free_speex,
.reset = reset_speex,
.seek = seek_speex,
};
#endif #endif

View file

@ -1,34 +1,31 @@
#include "coding.h" #include "coding.h"
#include "coding_utils_samples.h" #include "../base/codec_info.h"
#if VGM_TEST_DECODER
#include "../base/decode_state.h" #include "../base/decode_state.h"
#endif
#include "libs/tac_lib.h" #include "libs/tac_lib.h"
/* opaque struct */ /* opaque struct */
struct tac_codec_data { typedef struct {
/* config */
int channels;
int samples_discard;
int encoder_delay;
uint8_t buf[TAC_BLOCK_SIZE]; uint8_t buf[TAC_BLOCK_SIZE];
bool feed_block; bool feed_block;
off_t offset; off_t offset;
int16_t samples[TAC_FRAME_SAMPLES * TAC_CHANNELS]; float fbuf[TAC_FRAME_SAMPLES * TAC_CHANNELS];
int frame_samples; int discard;
/* frame state */
s16buf_t sbuf;
void* handle; void* handle;
}; } tac_codec_data;
static void free_tac(void* priv_data) {
tac_codec_data* data = priv_data;
if (!data)
return;
/* raw SPEEX */ tac_free(data->handle);
tac_codec_data* init_tac(STREAMFILE* sf) { free(data);
}
void* init_tac(STREAMFILE* sf) {
tac_codec_data* data = NULL; tac_codec_data* data = NULL;
int bytes; int bytes;
@ -40,13 +37,8 @@ tac_codec_data* init_tac(STREAMFILE* sf) {
data->handle = tac_init(data->buf, bytes); data->handle = tac_init(data->buf, bytes);
if (!data->handle) goto fail; if (!data->handle) goto fail;
data->feed_block = false; /* ok to use current block */ data->feed_block = false; // ok to use first block
data->offset = bytes; data->offset = bytes;
data->channels = TAC_CHANNELS;
data->frame_samples = TAC_FRAME_SAMPLES;
data->encoder_delay = 0;
data->samples_discard = data->encoder_delay;
return data; return data;
fail: fail:
@ -55,130 +47,86 @@ fail:
} }
static bool decode_frame(tac_codec_data* data) { static int decode_frame(tac_codec_data* data) {
int err; int err = tac_decode_frame(data->handle, data->buf);
data->sbuf.samples = data->samples;
data->sbuf.channels = data->channels;
data->sbuf.filled = 0;
err = tac_decode_frame(data->handle, data->buf);
if (err == TAC_PROCESS_NEXT_BLOCK) { if (err == TAC_PROCESS_NEXT_BLOCK) {
data->feed_block = true; data->feed_block = true;
return true; return 0;
} }
if (err == TAC_PROCESS_DONE) { if (err == TAC_PROCESS_DONE) {
VGM_LOG("TAC: process done (EOF) %i\n", err); VGM_LOG("TAC: process done (EOF) %i\n", err);
return false; /* shouldn't reach this */ return -1; // shouldn't reach this
} }
if (err != TAC_PROCESS_OK) { if (err != TAC_PROCESS_OK) {
VGM_LOG("TAC: process error %i\n", err); VGM_LOG("TAC: process error %i\n", err);
return false; return -1;
} }
tac_get_samples_float(data->handle, data->fbuf);
tac_get_samples_pcm16(data->handle, data->sbuf.samples); return TAC_FRAME_SAMPLES;
data->sbuf.filled = data->frame_samples;
return true;
} }
static bool read_frame(tac_codec_data* data, STREAMFILE* sf) { static bool read_frame(tac_codec_data* data, STREAMFILE* sf) {
/* new block must be read only when signaled by lib */ // new block must be read only when signaled by lib (a single block has N frames)
if (!data->feed_block) if (!data->feed_block)
return true; return true;
int bytes = read_streamfile(data->buf, data->offset, sizeof(data->buf), sf); int bytes = read_streamfile(data->buf, data->offset, sizeof(data->buf), sf);
data->offset += bytes; data->offset += bytes;
data->feed_block = 0; data->feed_block = 0;
if (bytes <= 0) return false; /* can read less that buf near EOF */ if (bytes <= 0) return false; // will read less that buf near EOF
return true; return true;
} }
void decode_tac(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do) { bool decode_frame_tac(VGMSTREAM* v) {
VGMSTREAMCHANNEL* stream = &vgmstream->ch[0]; VGMSTREAMCHANNEL* stream = &v->ch[0];
tac_codec_data* data = vgmstream->codec_data; tac_codec_data* data = v->codec_data;
bool ok;
bool ok = read_frame(data, stream->streamfile);
if (!ok)
return false;
while (samples_to_do > 0) { decode_state_t* ds = v->decode_state;
s16buf_t* sbuf = &data->sbuf;
if (sbuf->filled <= 0) { int samples = decode_frame(data);
ok = read_frame(data, stream->streamfile); if (samples < 0)
if (!ok) goto fail; return false;
ok = decode_frame(data); sbuf_init_f32(&ds->sbuf, data->fbuf, samples, v->channels);
if (!ok) goto fail; ds->sbuf.filled = samples;
}
if (data->samples_discard)
s16buf_discard(&outbuf, sbuf, &data->samples_discard);
else
s16buf_consume(&outbuf, sbuf, &samples_to_do);
}
return;
fail:
/* on error just put some 0 samples */
VGM_LOG("TAC: decode fail at %x, missing %i samples\n", (uint32_t)data->offset, samples_to_do);
s16buf_silence(&outbuf, &samples_to_do, data->sbuf.channels);
}
#if VGM_TEST_DECODER
bool decode_tac_frame(VGMSTREAM* vgmstream) {
VGMSTREAMCHANNEL* stream = &vgmstream->ch[0];
tac_codec_data* data = vgmstream->codec_data;
decode_state_t* ds = vgmstream->decode_state;
sbuf_init_s16(&ds->sbuf, data->samples, TAC_FRAME_SAMPLES, vgmstream->channels);
bool ok;
ok = read_frame(data, stream->streamfile);
if (!ok) return false;
ok = decode_frame(data);
if (!ok) return false;
ds->sbuf.filled = TAC_FRAME_SAMPLES; //TODO call sbuf_fill(samples);
// copy and let decoder handle // copy and let decoder handle
if (data->samples_discard) { if (data->discard) {
ds->discard = data->samples_discard; ds->discard += data->discard;
data->samples_discard = 0; data->discard = 0;
} }
return true; return true;
} }
#endif
static void reset_tac(void* priv_data) {
void reset_tac(tac_codec_data* data) { tac_codec_data* data = priv_data;
if (!data) return; if (!data) return;
tac_reset(data->handle); tac_reset(data->handle);
data->feed_block = true; data->feed_block = true;
data->offset = 0x00; data->offset = 0x00;
data->sbuf.filled = 0;
data->samples_discard = data->encoder_delay;
} }
void seek_tac(tac_codec_data* data, int32_t num_sample) { static void seek_tac(VGMSTREAM* v, int32_t num_sample) {
tac_codec_data* data = v->codec_data;
int32_t loop_sample; int32_t loop_sample;
const tac_header_t* hdr;
if (!data) if (!data)
return; return;
hdr = tac_get_header(data->handle); const tac_header_t* hdr = tac_get_header(data->handle);
loop_sample = (hdr->loop_frame - 1) * TAC_FRAME_SAMPLES + hdr->loop_discard; loop_sample = (hdr->loop_frame - 1) * TAC_FRAME_SAMPLES + hdr->loop_discard;
if (loop_sample == num_sample) { if (loop_sample == num_sample) {
@ -186,23 +134,22 @@ void seek_tac(tac_codec_data* data, int32_t num_sample) {
data->feed_block = true; data->feed_block = true;
data->offset = hdr->loop_offset; data->offset = hdr->loop_offset;
data->sbuf.filled = 0; data->discard = hdr->loop_discard;
data->samples_discard = hdr->loop_discard;
} }
else { else {
tac_reset(data->handle); tac_reset(data->handle);
data->feed_block = true; data->feed_block = true;
data->offset = 0x00; data->offset = 0x00;
data->sbuf.filled = 0; data->discard = num_sample;
data->samples_discard = num_sample;
} }
} }
void free_tac(tac_codec_data* data) { const codec_info_t tac_decoder = {
if (!data) .sample_type = SFMT_F32,
return; .decode_frame = decode_frame_tac,
.free = free_tac,
tac_free(data->handle); .reset = reset_tac,
free(data); .seek = seek_tac,
} //frame_samples = 1024,
};

View file

@ -0,0 +1,207 @@
#include "coding.h"
#include "../base/decode_state.h"
#include "../base/codec_info.h"
#include "libs/ubi_mpeg_helpers.h"
#define MINIMP3_FLOAT_OUTPUT
//#define MINIMP3_NO_SIMD
#define MINIMP3_IMPLEMENTATION
#include "libs/minimp3.h"
//TODO: needed for smoother segments, but not sure if block samples counts this
// (usually blocks' frames have more samples than defined but not always; maybe should output delay's samples at EOF)
#define UBIMPEG_INITIAL_DISCARD 480 //observed
#define UBIMPEG_SAMPLES_PER_FRAME 1152
#define UBIMPEG_MAX_CHANNELS 2
#define UBIMPEG_INPUT_LIMIT 0x400 //enough for 2 stereo + mono frames
/* opaque struct */
typedef struct {
bool is_sur2;
bool is_sur1;
bitstream_t is;
mp3dec_t mp3d;
mp3dec_frame_info_t info;
uint8_t ibuf[0x2000]; // big enough to limit re-reading
uint8_t obuf[0x400]; // at least ~300
uint8_t rbuf[0x400]; // at least 300 * 2
float fbuf[UBIMPEG_SAMPLES_PER_FRAME * UBIMPEG_MAX_CHANNELS];
int initial_discard;
} ubimpeg_codec_data;
static void free_ubimpeg(void* priv_data) {
ubimpeg_codec_data* data = priv_data;
if (!data) return;
free(data);
}
void* init_ubimpeg(uint32_t mode) {
ubimpeg_codec_data* data = NULL;
data = calloc(1, sizeof(ubimpeg_codec_data));
if (!data) goto fail;
// data may start with 'surround mode' flag, otherwise a regular frame with a Ubi-MPEG sync
if (mode == get_id32be("2RUS")) {
data->is_sur2 = true;
}
else if (mode == get_id32be("1RUS")) {
data->is_sur1 = true;
VGM_LOG("UBI-MPEG: 1RUS found\n");
goto fail;
}
else if ((mode >> 20) != 0xFFF) {
VGM_LOG("UBI-MPEG: unknown format %x\n", mode);
goto fail;
}
data->initial_discard = UBIMPEG_INITIAL_DISCARD;
bm_setup(&data->is, data->ibuf, 0);
mp3dec_init(&data->mp3d);
return data;
fail:
free_ubimpeg(data);
return NULL;
}
// Ubi-MPEG is made to keep all data in memory, since frames go one after another.
// Here we ensure that buf is filled enough for the reader, and move data around if needed
// (maybe should make a circular buf bitreader but seems a bit too particular).
static bool setup_input_bitstream(VGMSTREAM* v) {
ubimpeg_codec_data* data = v->codec_data;
VGMSTREAMCHANNEL* vs = &v->ch[0];
//TODO maybe should clamp to block size, but overreads should result in sync error as new blocks start with samples (technically could match)
// on init should read buf size
int read_size = sizeof(data->ibuf);
int pos = 0;
if (data->is.bufsize > 0) {
uint32_t ibuf_offset = bm_pos(&data->is) / 8;
uint32_t ibuf_left = read_size - ibuf_offset;
// move buf to beginning + setup to fill it fully
if (ibuf_left < UBIMPEG_INPUT_LIMIT) {
int ibuf_bitpos = bm_pos(&data->is) % 8;
memmove(data->ibuf, data->ibuf + ibuf_offset, ibuf_left);
bm_setup(&data->is, data->ibuf, ibuf_left);
bm_skip(&data->is, ibuf_bitpos);
pos = ibuf_left;
read_size -= ibuf_left;
}
else {
// enough data in buf
return true;
}
}
int bytes = read_streamfile(data->ibuf + pos, vs->offset, read_size, vs->streamfile);
bm_fill(&data->is, bytes);
vs->offset += bytes;
return true;
}
static int read_frame_ubimpeg(VGMSTREAM* v) {
ubimpeg_codec_data* data = v->codec_data;
// prepare and read data for the bitstream, if needed
setup_input_bitstream(v) ;
// convert input data into 1 regular mpeg frame
bitstream_t os = {0};
bm_setup(&os, data->obuf, sizeof(data->obuf));
int obuf_size = ubimpeg_transform_frame(&data->is, &os);
if (!obuf_size) return 0;
// TODO: handle correctly
// Ubi-MPEG (MP2) mixes 1 stereo frame + 1 mono frame coefs before synth to (presumably) emulate M/S stereo from MP3.
// Ignoring the mono frame usually sounds ok enough (as good as 160kbps JS MP2 by 1998 encoders can sound) but
// sometimes stereo frames only have data for left channel and need the mono frame to complete R.
if (data->is_sur1 || data->is_sur2) {
// consume next frame (should be mono) in a separate buffer as otherwise confuses minimp3
bm_setup(&os, data->rbuf, sizeof(data->rbuf));
ubimpeg_transform_frame(&data->is, &os);
}
return obuf_size;
}
bool decode_frame_ubimpeg(VGMSTREAM* v) {
int obuf_size = read_frame_ubimpeg(v);
if (!obuf_size) {
return false;
}
decode_state_t* ds = v->decode_state;
ubimpeg_codec_data* data = v->codec_data;
int samples = mp3dec_decode_frame(&data->mp3d, data->obuf, obuf_size, data->fbuf, &data->info);
if (samples < 0) {
return false;
}
// TODO: voice .bnm + Ubi-MPEG sets 2 channels but uses mono frames (no xRUS). Possibly the MPEG engine
// only handle stereo, maybe should dupe L>R. sbuf copying handles this correctly.
// todo fix
if (data->info.channels != v->channels) {
VGM_LOG_ONCE("UBI MPEG: mismatched channels %i vs %i\n", data->info.channels, v->channels);
//return false;
}
sbuf_init_flt(&ds->sbuf, data->fbuf, samples, data->info.channels);
ds->sbuf.filled = samples;
if (data->initial_discard) {
ds->discard += data->initial_discard;
data->initial_discard = 0;
}
return true;
}
static void reset_ubimpeg(void* priv_data) {
ubimpeg_codec_data* data = priv_data;
if (!data) return;
data->initial_discard = UBIMPEG_INITIAL_DISCARD;
bm_setup(&data->is, data->ibuf, 0);
mp3dec_init(&data->mp3d);
}
static void seek_ubimpeg(VGMSTREAM* v, int32_t num_sample) {
ubimpeg_codec_data* data = v->codec_data;
decode_state_t* ds = v->decode_state;
if (!data) return;
reset_ubimpeg(data);
ds->discard = num_sample;
if (v->loop_ch) {
v->loop_ch[0].offset = v->loop_ch[0].channel_start_offset;
}
}
const codec_info_t ubimpeg_decoder = {
.sample_type = SFMT_FLT,
.decode_frame = decode_frame_ubimpeg,
.free = free_ubimpeg,
.reset = reset_ubimpeg,
.seek = seek_ubimpeg,
};

View file

@ -1,12 +1,31 @@
#include <math.h> #include <math.h>
#include "../base/decode_state.h"
#include "../base/sbuf.h"
#include "../base/codec_info.h"
#include "coding.h" #include "coding.h"
#include "vorbis_custom_decoder.h" #include "vorbis_custom_decoder.h"
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
#define VORBIS_DEFAULT_BUFFER_SIZE 0x8000 /* should be at least the size of the setup header, ~0x2000 */ #define VORBIS_CALL_SAMPLES 1024 // allowed frame 'blocksizes' range from 2^6 ~ 2^13 (64 ~ 8192) but we can return partial samples
#define VORBIS_DEFAULT_BUFFER_SIZE 0x8000 // at least the size of the setup header, ~0x2000
static void pcm_convert_float_to_16(sample_t* outbuf, int samples_to_do, float** pcm, int channels);
void free_vorbis_custom(void* priv_data) {
vorbis_custom_codec_data* data = priv_data;
if (!data)
return;
/* internal decoder cleanup */
vorbis_block_clear(&data->vb);
vorbis_dsp_clear(&data->vd);
vorbis_comment_clear(&data->vc);
vorbis_info_clear(&data->vi);
free(data->buffer);
free(data->fbuf);
free(data);
}
/** /**
* Inits a vorbis stream of some custom variety. * Inits a vorbis stream of some custom variety.
@ -51,9 +70,11 @@ vorbis_custom_codec_data* init_vorbis_custom(STREAMFILE* sf, off_t start_offset,
case VORBIS_SK: ok = vorbis_custom_setup_init_sk(sf, start_offset, data); break; case VORBIS_SK: ok = vorbis_custom_setup_init_sk(sf, start_offset, data); break;
case VORBIS_VID1: ok = vorbis_custom_setup_init_vid1(sf, start_offset, data); break; case VORBIS_VID1: ok = vorbis_custom_setup_init_vid1(sf, start_offset, data); break;
case VORBIS_AWC: ok = vorbis_custom_setup_init_awc(sf, start_offset, data); break; case VORBIS_AWC: ok = vorbis_custom_setup_init_awc(sf, start_offset, data); break;
default: goto fail; case VORBIS_OOR: ok = vorbis_custom_setup_init_oor(sf, start_offset, data); break;
default: ok = false; break;
} }
if(!ok) goto fail; if(!ok)
goto fail;
data->op.b_o_s = 0; /* end of fake headers */ data->op.b_o_s = 0; /* end of fake headers */
@ -63,6 +84,9 @@ vorbis_custom_codec_data* init_vorbis_custom(STREAMFILE* sf, off_t start_offset,
/* write output */ /* write output */
config->channels = data->config.channels;
config->sample_rate = data->config.sample_rate;
config->last_granule = data->config.last_granule;
config->data_start_offset = data->config.data_start_offset; config->data_start_offset = data->config.data_start_offset;
if (!data->config.stream_end) { if (!data->config.stream_end) {
@ -77,58 +101,17 @@ fail:
return NULL; return NULL;
} }
/* Decodes Vorbis packets into a libvorbis sample buffer, and copies them to outbuf */ static bool read_packet(VGMSTREAM* v) {
void decode_vorbis_custom(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do, int channels) { VGMSTREAMCHANNEL* stream = &v->ch[0];
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0]; vorbis_custom_codec_data* data = v->codec_data;
vorbis_custom_codec_data* data = vgmstream->codec_data;
//data->op.packet = data->buffer;/* implicit from init */
int samples_done = 0;
while (samples_done < samples_to_do) { // extra EOF check
// (may need to drain samples? not a thing in vorbis due to packet types?)
if (stream->offset >= data->config.stream_end)
return false;
if (data->samples_full) { /* read more samples */ // read/transform data into the ogg_packet buffer and advance offsets
int samples_to_get; bool ok;
float **pcm;
/* get PCM samples from libvorbis buffers */
samples_to_get = vorbis_synthesis_pcmout(&data->vd, &pcm);
if (!samples_to_get) {
data->samples_full = 0; /* request more if empty*/
continue;
}
if (data->samples_to_discard) {
/* discard samples for looping */
if (samples_to_get > data->samples_to_discard)
samples_to_get = data->samples_to_discard;
data->samples_to_discard -= samples_to_get;
}
else {
/* get max samples and convert from Vorbis float pcm to 16bit pcm */
if (samples_to_get > samples_to_do - samples_done)
samples_to_get = samples_to_do - samples_done;
pcm_convert_float_to_16(outbuf + samples_done * channels, samples_to_get, pcm, data->vi.channels);
samples_done += samples_to_get;
}
/* mark consumed samples from the buffer
* (non-consumed samples are returned in next vorbis_synthesis_pcmout calls) */
vorbis_synthesis_read(&data->vd, samples_to_get);
}
else { /* read more data */
int ok, rc;
/* extra EOF check */
if (stream->offset >= data->config.stream_end) {
/* may need to drain samples? (not a thing in vorbis due to packet types?) */
goto decode_fail;
}
/* not actually needed, but feels nicer */
data->op.granulepos += samples_to_do; /* can be changed next if desired */
data->op.packetno++;
/* read/transform data into the ogg_packet buffer and advance offsets */
switch(data->type) { switch(data->type) {
case VORBIS_FSB: ok = vorbis_custom_parse_packet_fsb(stream, data); break; case VORBIS_FSB: ok = vorbis_custom_parse_packet_fsb(stream, data); break;
case VORBIS_WWISE: ok = vorbis_custom_parse_packet_wwise(stream, data); break; case VORBIS_WWISE: ok = vorbis_custom_parse_packet_wwise(stream, data); break;
@ -136,95 +119,157 @@ void decode_vorbis_custom(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t sample
case VORBIS_SK: ok = vorbis_custom_parse_packet_sk(stream, data); break; case VORBIS_SK: ok = vorbis_custom_parse_packet_sk(stream, data); break;
case VORBIS_VID1: ok = vorbis_custom_parse_packet_vid1(stream, data); break; case VORBIS_VID1: ok = vorbis_custom_parse_packet_vid1(stream, data); break;
case VORBIS_AWC: ok = vorbis_custom_parse_packet_awc(stream, data); break; case VORBIS_AWC: ok = vorbis_custom_parse_packet_awc(stream, data); break;
default: goto decode_fail; case VORBIS_OOR: ok = vorbis_custom_parse_packet_oor(stream, data); break;
} default: ok = false; break;
if(!ok) {
goto decode_fail;
} }
return ok;
}
/* parse the fake ogg packet into a logical vorbis block */ static bool decode_frame(VGMSTREAM* v) {
rc = vorbis_synthesis(&data->vb,&data->op); decode_state_t* ds = v->decode_state;
vorbis_custom_codec_data* data = v->codec_data;
int rc;
// parse the fake ogg packet into a logical vorbis block
rc = vorbis_synthesis(&data->vb, &data->op);
if (rc == OV_ENOTAUDIO) { if (rc == OV_ENOTAUDIO) {
VGM_LOG("Vorbis: not an audio packet (size=0x%x) @ %x\n",(size_t)data->op.bytes,(uint32_t)stream->offset); // rarely happens, seems ok?
//VGM_LOGB(data->op.packet, (size_t)data->op.bytes,0); VGM_LOG("Vorbis: not an audio packet (size=0x%x) @ %x\n", (size_t)data->op.bytes, (uint32_t)v->ch[0].offset);
continue; /* rarely happens, seems ok? */ ds->sbuf.filled = 0;
} else if (rc != 0) goto decode_fail; return true;
}
else if (rc != 0) {
return false;
}
/* finally decode the logical block into samples */ // finally decode the logical vorbis block into samples
rc = vorbis_synthesis_blockin(&data->vd,&data->vb); rc = vorbis_synthesis_blockin(&data->vd,&data->vb);
if (rc != 0) goto decode_fail; /* ? */ if (rc != 0) return false; /* ? */
data->op.packetno++;
data->samples_full = 1; return true;
}
}
return;
decode_fail:
/* on error just put some 0 samples */
VGM_LOG("VORBIS: decode fail at %x, missing %i samples\n", (uint32_t)stream->offset, (samples_to_do - samples_done));
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample_t));
} }
/* converts from internal Vorbis format to standard PCM (mostly from Xiph's decoder_example.c) */ static int copy_samples(VGMSTREAM* v) {
static void pcm_convert_float_to_16(sample_t* outbuf, int samples_to_do, float** pcm, int channels) { decode_state_t* ds = v->decode_state;
int ch, s; vorbis_custom_codec_data* data = v->codec_data;
sample_t* ptr;
float* channel;
/* convert float PCM (multichannel float array, with pcm[0]=ch0, pcm[1]=ch1, pcm[2]=ch0, etc) //TODO: helper?
* to 16 bit signed PCM ints (host order) and interleave + fix clipping */ //TODO: maybe should init in init_vorbis_custom but right now not all vorbises pass channels
for (ch = 0; ch < channels; ch++) { if (data->fbuf == NULL) {
/* channels should be in standard order unlike Ogg Vorbis (at least in FSB) */ data->fbuf = malloc(VORBIS_CALL_SAMPLES * sizeof(float) * v->channels);
ptr = outbuf + ch; if (!data->fbuf) return -1;
channel = pcm[ch]; }
for (s = 0; s < samples_to_do; s++) {
int val = (int)floor(channel[s] * 32767.0f + 0.5f);
if (val > 32767) val = 32767;
else if (val < -32768) val = -32768;
*ptr = val; // get PCM samples from libvorbis buffers
ptr += channels; float** pcm;
} int samples = vorbis_synthesis_pcmout(&data->vd, &pcm);
if (samples > VORBIS_CALL_SAMPLES)
samples = VORBIS_CALL_SAMPLES;
// no more samples in vorbis's buffer
if (samples == 0)
return 0;
// vorbis's planar buffer to interleaved buffer
sbuf_init_flt(&ds->sbuf, data->fbuf, samples, v->channels);
ds->sbuf.filled = samples;
sbuf_interleave(&ds->sbuf, pcm);
// mark consumed samples from the buffer
// (non-consumed samples are returned in next vorbis_synthesis_pcmout calls)
vorbis_synthesis_read(&data->vd, samples);
// TODO: useful?
//data->op.granulepos += samples; // not actually needed
if (data->current_discard) {
ds->discard += data->current_discard;
data->current_discard = 0;
} }
return samples;
} }
/* ********************************************** */ static bool decode_frame_vorbis_custom(VGMSTREAM* v) {
// vorbis may hold samples, return them first
int ret = copy_samples(v);
if (ret < 0) return false;
if (ret > 0) return true;
void free_vorbis_custom(vorbis_custom_codec_data* data) { // handle new frame
if (!data) bool read = read_packet(v);
return; if (!read)
return false;
/* internal decoder cleanup */ // decode current frame
vorbis_block_clear(&data->vb); bool decoded = decode_frame(v);
vorbis_dsp_clear(&data->vd); if (!decoded)
vorbis_comment_clear(&data->vc); return false;
vorbis_info_clear(&data->vi);
free(data->buffer); // samples will be copied next call
free(data); return true;
} }
void reset_vorbis_custom(VGMSTREAM* vgmstream) { static void reset_vorbis_custom(void* priv_data) {
vorbis_custom_codec_data *data = vgmstream->codec_data; vorbis_custom_codec_data* data = priv_data;
if (!data) return; if (!data) return;
vorbis_synthesis_restart(&data->vd); vorbis_synthesis_restart(&data->vd);
data->samples_to_discard = 0; data->current_discard = 0;
data->current_packet = 0;
data->packet_count = 0;
data->flags = 0;
} }
void seek_vorbis_custom(VGMSTREAM* vgmstream, int32_t num_sample) { static void seek_vorbis_custom(VGMSTREAM* v, int32_t num_sample) {
vorbis_custom_codec_data *data = vgmstream->codec_data; vorbis_custom_codec_data* data = v->codec_data;
if (!data) return; if (!data) return;
/* Seeking is provided by the Ogg layer, so with custom vorbis we'd need seek tables instead. /* Seeking is provided by the Ogg layer, so with custom vorbis we'd need seek tables instead.
* To avoid having to parse different formats we'll just discard until the expected sample */ * To avoid having to parse different formats we'll just discard until the expected sample */
vorbis_synthesis_restart(&data->vd); reset_vorbis_custom(data);
data->samples_to_discard = num_sample; data->current_discard = num_sample;
if (vgmstream->loop_ch) if (v->loop_ch)
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset; v->loop_ch[0].offset = v->loop_ch[0].channel_start_offset;
} }
int32_t vorbis_custom_get_samples(VGMSTREAM* v) {
vorbis_custom_codec_data* data = v->codec_data;
//TODO improve (would need to change a bunch)
VGMSTREAMCHANNEL* stream = &v->ch[0];
uint32_t temp = stream->offset;
// read packets + sum samples (info from revorb: https://yirkha.fud.cz/progs/foobar2000/revorb.cpp)
int prev_blocksize = 0;
int32_t samples = 0;
while (true) {
bool ok = read_packet(v);
if (!ok || data->op.bytes == 0) //EOF probably
break;
// get blocksize (somewhat similar to samples-per-frame, but must be adjusted)
int blocksize = vorbis_packet_blocksize(&data->vi, &data->op);
if (prev_blocksize)
samples += (prev_blocksize + blocksize) / 4;
prev_blocksize = blocksize;
}
reset_vorbis_custom(data);
stream->offset = temp;
return samples;
}
const codec_info_t vorbis_custom_decoder = {
.sample_type = SFMT_FLT,
.decode_frame = decode_frame_vorbis_custom,
.free = free_vorbis_custom,
.reset = reset_vorbis_custom,
.seek = seek_vorbis_custom,
};
#endif #endif

View file

@ -8,6 +8,8 @@
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
#include <vorbis/codec.h> #include <vorbis/codec.h>
#define MAX_PACKET_SIZES 160 // max 256 in theory, observed max is ~65, rarely ~130 in
/* custom Vorbis without Ogg layer */ /* custom Vorbis without Ogg layer */
struct vorbis_custom_codec_data { struct vorbis_custom_codec_data {
vorbis_info vi; /* stream settings */ vorbis_info vi; /* stream settings */
@ -18,24 +20,28 @@ struct vorbis_custom_codec_data {
uint8_t* buffer; /* internal raw data buffer */ uint8_t* buffer; /* internal raw data buffer */
size_t buffer_size; size_t buffer_size;
float* fbuf;
size_t samples_to_discard; /* for looping purposes */ int current_discard; /* for looping purposes */
int samples_full; /* flag, samples available in vorbis buffers */
vorbis_custom_t type; /* Vorbis subtype */ vorbis_custom_t type; /* Vorbis subtype */
vorbis_custom_config config; /* config depending on the mode */ vorbis_custom_config config; /* config depending on the mode */
/* Wwise Vorbis: saved data to reconstruct modified packets */ /* Wwise Vorbis: saved data to reconstruct modified packets */
uint8_t mode_blockflag[64+1]; /* max 6b+1; flags 'n stuff */ uint8_t mode_blockflag[64+1]; /* max 6b+1; flags 'n stuff */
int mode_bits; /* bits to store mode_number */ int mode_bits; /* bits to store mode_number */
uint8_t prev_blockflag; /* blockflag in the last decoded packet */ uint8_t prev_blockflag; /* blockflag in the last decoded packet */
/* Ogg-style Vorbis: packet within a page */
/* OOR/OggS: current page info (state) */
int current_packet; int current_packet;
int packet_count;
uint16_t packet_size[MAX_PACKET_SIZES];
uint8_t flags;
/* reference for page/blocks */ /* reference for page/blocks */
off_t block_offset; off_t block_offset;
size_t block_size; size_t block_size;
int prev_block_samples; /* count for optimization */
}; };
@ -45,6 +51,7 @@ int vorbis_custom_setup_init_ogl(STREAMFILE* sf, off_t start_offset, vorbis_cust
int vorbis_custom_setup_init_sk(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data); int vorbis_custom_setup_init_sk(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data);
int vorbis_custom_setup_init_vid1(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data); int vorbis_custom_setup_init_vid1(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data);
int vorbis_custom_setup_init_awc(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data); int vorbis_custom_setup_init_awc(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data);
int vorbis_custom_setup_init_oor(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data);
int vorbis_custom_parse_packet_fsb(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data); int vorbis_custom_parse_packet_fsb(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data);
int vorbis_custom_parse_packet_wwise(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data); int vorbis_custom_parse_packet_wwise(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data);
@ -52,12 +59,15 @@ int vorbis_custom_parse_packet_ogl(VGMSTREAMCHANNEL* stream, vorbis_custom_codec
int vorbis_custom_parse_packet_sk(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data); int vorbis_custom_parse_packet_sk(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data);
int vorbis_custom_parse_packet_vid1(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data); int vorbis_custom_parse_packet_vid1(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data);
int vorbis_custom_parse_packet_awc(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data); int vorbis_custom_parse_packet_awc(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data);
int vorbis_custom_parse_packet_oor(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data);
/* other utils to make/parse vorbis stuff */ /* other utils to make/parse vorbis stuff */
int build_header_comment(uint8_t* buf, int bufsize); int build_header_comment(uint8_t* buf, int bufsize);
int build_header_identification(uint8_t* buf, int bufsize, vorbis_custom_config* cfg); int build_header_identification(uint8_t* buf, int bufsize, vorbis_custom_config* cfg);
void load_blocksizes(vorbis_custom_config* cfg, int blocksize_short, int blocksize_long); int vorbis_get_blocksize_exp(int blocksize);
bool load_header_packet(STREAMFILE* sf, vorbis_custom_codec_data* data, uint32_t packet_size, int packet_skip, uint32_t* p_offset); bool load_header_packet(STREAMFILE* sf, vorbis_custom_codec_data* data, uint32_t packet_size, int packet_skip, uint32_t* p_offset);
#endif/* VGM_USE_VORBIS */
#endif/*_VORBIS_CUSTOM_DECODER_H_ */
#endif
#endif

View file

@ -1,6 +1,7 @@
#include "vorbis_custom_decoder.h" #include "vorbis_custom_decoder.h"
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
int build_header_comment(uint8_t* buf, int bufsize) { int build_header_comment(uint8_t* buf, int bufsize) {
int bytes = 0x19; int bytes = 0x19;
@ -22,6 +23,7 @@ int build_header_identification(uint8_t* buf, int bufsize, vorbis_custom_config*
if (bytes > bufsize) if (bytes > bufsize)
return 0; return 0;
// long (bigger frames) + short (smaller frames) blocksizes (samples per frame)
uint8_t blocksizes = (cfg->blocksize_0_exp << 4) | (cfg->blocksize_1_exp); uint8_t blocksizes = (cfg->blocksize_0_exp << 4) | (cfg->blocksize_1_exp);
put_u8 (buf+0x00, 0x01); /* packet_type (id) */ put_u8 (buf+0x00, 0x01); /* packet_type (id) */
@ -46,35 +48,19 @@ bool make_header_identification(vorbis_custom_codec_data* data, vorbis_custom_co
return true; return true;
} }
void load_blocksizes(vorbis_custom_config* cfg, int blocksize_short, int blocksize_long) { // basic log2 for allowed blocksizes (2-exp)
uint8_t exp_blocksize_0, exp_blocksize_1; int vorbis_get_blocksize_exp(int blocksize) {
switch(blocksize) {
/* guetto log2 for allowed blocksizes (2-exp), could be improved */ case 64: return 6;
switch(blocksize_long) { case 128: return 7;
case 64: exp_blocksize_0 = 6; break; case 256: return 8;
case 128: exp_blocksize_0 = 7; break; case 512: return 9;
case 256: exp_blocksize_0 = 8; break; case 1024: return 10;
case 512: exp_blocksize_0 = 9; break; case 2048: return 11;
case 1024: exp_blocksize_0 = 10; break; case 4096: return 12;
case 2048: exp_blocksize_0 = 11; break; case 8192: return 13;
case 4096: exp_blocksize_0 = 12; break; default: return 0;
case 8192: exp_blocksize_0 = 13; break;
default: exp_blocksize_0 = 0;
} }
switch(blocksize_short) {
case 64: exp_blocksize_1 = 6; break;
case 128: exp_blocksize_1 = 7; break;
case 256: exp_blocksize_1 = 8; break;
case 512: exp_blocksize_1 = 9; break;
case 1024: exp_blocksize_1 = 10; break;
case 2048: exp_blocksize_1 = 11; break;
case 4096: exp_blocksize_1 = 12; break;
case 8192: exp_blocksize_1 = 13; break;
default: exp_blocksize_1 = 0;
}
cfg->blocksize_0_exp = exp_blocksize_0;
cfg->blocksize_1_exp = exp_blocksize_1;
} }
bool load_header_packet(STREAMFILE* sf, vorbis_custom_codec_data* data, uint32_t packet_size, int packet_skip, uint32_t* p_offset) { bool load_header_packet(STREAMFILE* sf, vorbis_custom_codec_data* data, uint32_t packet_size, int packet_skip, uint32_t* p_offset) {
@ -90,4 +76,5 @@ bool load_header_packet(STREAMFILE* sf, vorbis_custom_codec_data* data, uint32_t
fail: fail:
return false; return false;
} }
#endif/* VGM_USE_VORBIS */
#endif

View file

@ -3,9 +3,9 @@
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
#include <vorbis/codec.h> #include <vorbis/codec.h>
#define FSB_VORBIS_USE_PRECOMPILED_FVS 1 /* if enabled vgmstream weights ~600kb more but doesn't need external .fvs packets */ // if enabled vgmstream weights ~600kb more but doesn't need external setup packets
#if FSB_VORBIS_USE_PRECOMPILED_FVS #ifndef VGM_DISABLE_CODEBOOKS
#include "vorbis_custom_data_fsb.h" #include "libs/vorbis_codebooks_fsb.h"
#endif #endif
@ -15,11 +15,6 @@
static int build_header_setup(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf); static int build_header_setup(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf);
#if !(FSB_VORBIS_USE_PRECOMPILED_FVS)
static int load_fvs_file(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf);
#endif
static int load_fvs_array(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf);
/* **************************************************************************** */ /* **************************************************************************** */
/* EXTERNAL API */ /* EXTERNAL API */
@ -32,11 +27,13 @@ static int load_fvs_array(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREA
* fsb-vorbis-extractor (https://github.com/tmiasko/fsb-vorbis-extractor). * fsb-vorbis-extractor (https://github.com/tmiasko/fsb-vorbis-extractor).
*/ */
int vorbis_custom_setup_init_fsb(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data) { int vorbis_custom_setup_init_fsb(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data) {
vorbis_custom_config cfg = data->config; vorbis_custom_config* cfg = &data->config;
load_blocksizes(&cfg, 256, 2048); /* FSB default */ // load FSB default blocksizes
cfg->blocksize_0_exp = vorbis_get_blocksize_exp(2048); //long
cfg->blocksize_1_exp = vorbis_get_blocksize_exp(256); //short
data->op.bytes = build_header_identification(data->buffer, data->buffer_size, &cfg); data->op.bytes = build_header_identification(data->buffer, data->buffer_size, cfg);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) /* identification packet */ if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) /* identification packet */
goto fail; goto fail;
@ -44,7 +41,7 @@ int vorbis_custom_setup_init_fsb(STREAMFILE* sf, off_t start_offset, vorbis_cust
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) /* comment packet */ if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) /* comment packet */
goto fail; goto fail;
data->op.bytes = build_header_setup(data->buffer, data->buffer_size, cfg.setup_id, sf); data->op.bytes = build_header_setup(data->buffer, data->buffer_size, cfg->setup_id, sf);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) /* setup packet */ if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) /* setup packet */
goto fail; goto fail;
@ -77,27 +74,7 @@ fail:
/* INTERNAL HELPERS */ /* INTERNAL HELPERS */
/* **************************************************************************** */ /* **************************************************************************** */
static int build_header_setup(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) { #ifdef VGM_DISABLE_CODEBOOKS
int bytes;
/* try to locate from the precompiled list */
bytes = load_fvs_array(buf, bufsize, setup_id, sf);
if (bytes)
return bytes;
#if !(FSB_VORBIS_USE_PRECOMPILED_FVS)
/* try to load from external files */
bytes = load_fvs_file(buf, bufsize, setup_id, sf);
if (bytes)
return bytes;
#endif
/* not found */
VGM_LOG("FSB Vorbis: setup_id %08x not found\n", setup_id);
return 0;
}
#if !(FSB_VORBIS_USE_PRECOMPILED_FVS)
static int load_fvs_file(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) { static int load_fvs_file(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) {
STREAMFILE* sf_setup = NULL; STREAMFILE* sf_setup = NULL;
@ -143,22 +120,22 @@ fail:
} }
#endif #endif
static int load_fvs_array(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) { static int build_header_setup(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) {
#if FSB_VORBIS_USE_PRECOMPILED_FVS int bytes;
int i, list_length;
list_length = sizeof(fvs_list) / sizeof(fvs_info); #ifndef VGM_DISABLE_CODEBOOKS
for (i=0; i < list_length; i++) { // locate from precompiled list
if (fvs_list[i].id == setup_id) { bytes = vcb_load_codebook_array(buf, bufsize, setup_id, vcb_list, vcb_list_count);
if (fvs_list[i].size > bufsize) goto fail; if (bytes)
/* found: copy data as-is */ return bytes;
memcpy(buf,fvs_list[i].setup, fvs_list[i].size); #else
return fvs_list[i].size; // load from external files
} bytes = load_fvs_file(buf, bufsize, setup_id, sf);
} if (bytes)
return bytes;
fail:
#endif #endif
VGM_LOG("FSB Vorbis: setup_id %08x not found\n", setup_id);
return 0; return 0;
} }

View file

@ -0,0 +1,237 @@
#include "vorbis_custom_decoder.h"
#ifdef VGM_USE_VORBIS
#include <vorbis/codec.h>
#include "libs/oor_helpers.h"
// if enabled vgmstream weights ~20kb more
#ifndef VGM_DISABLE_CODEBOOKS
#include "libs/vorbis_codebooks_oor.h"
#endif
// read current page's info and save it to persist between decode calls
static int read_page_info(vorbis_custom_codec_data* data, STREAMFILE* sf, uint32_t page_offset) {
// bitreader data
uint8_t buf[0x200]; // variable but shouldn't need to be bigger than this
int buf_size = sizeof(buf);
//TODO: this will overread a bit; it's possible to load beginning + calc size + load rest, but to simplify...
int bytes = read_streamfile(buf, page_offset, buf_size, sf);
if (bytes != buf_size) return false;
bitstream_t is_tmp;
bitstream_t* is = &is_tmp;
bm_setup(is, buf, bytes);
// oor bitstream info
oor_page_t page = {0};
oor_size_t size = {0};
oor_read_page(is, &page);
oor_read_size(is, &size);
if (!oor_validate_audio_page(&page, &size, NULL))
return 0;
if (size.packet_count >= MAX_PACKET_SIZES) {
VGM_LOG("OOR: packet count %i bigger than observed max (report)\n", size.packet_count);
return 0;
}
//TODO: maybe put into a separate struct
data->flags = page.flags;
data->packet_count = size.packet_count;
for (int i = 0; i < size.packet_count; i++) {
data->packet_size[i] = size.base_packet_size + size.variable_packet_size[i];
}
int page_size = bm_pos(is) / 8; // aligned
return page_size;
}
// Reads a single packet, which may be split into multiple pages (much like OggS).
// returns current packet size but also advances offsets, given it may need to read multiple pages.
static int read_packet(uint8_t* buf, int buf_size, vorbis_custom_codec_data* data, STREAMFILE* sf, uint32_t* p_offset) {
int read_size = 0;
// handle split packets: (similar to vorbis?)
// - OOR_FLAG_CONTINUED and is last packet of a page: packet is joined with next packet
// - OOR_FLAG_PARTIAL and is first packet of a page: packet is joined with prev packet
// - otherwise: read normally
// in OOR, packets may be split like full-size (curr page) + 0-size (next page), or splitsetup packet
while (true) {
// OOR allows 0-sized packets marked as partial, but not sure if prev packet can be 0
//if ((data->flags & OOR_FLAG_CONTINUED) && read_size == 0)
// return 0;
// new page
if (data->current_packet == 0) {
// no new pages after flag is set
if (data->flags & OOR_FLAG_EOS)
return 0;
int page_size = read_page_info(data, sf, *p_offset);
if (!page_size) return 0;
*p_offset += page_size;
if (data->packet_count == 0) {
VGM_LOG("OOR: empty page found\n");
return 0;
}
}
// read chunk to buf (note that size 0 is valid in rare cases)
int packet_size = data->packet_size[data->current_packet];
data->current_packet++;
if (data->current_packet == data->packet_count)
data->current_packet = 0;
if (read_size + packet_size > buf_size) {
VGM_LOG("OOR: packet too big\n");
return 0;
}
int bytes = read_streamfile(buf + read_size, *p_offset, packet_size, sf);
if (bytes != packet_size)
return 0;
*p_offset += packet_size;
read_size += packet_size;
// packet with continued flag must be merged with next packet (typically in next page)
bool is_last = data->current_packet == 0; // was reset above
if (!(is_last && (data->flags & OOR_FLAG_PARTIAL)))
break;
}
return read_size;
}
// read header info (1st page) and extract info to init Vorbis
static int read_header_packet(vorbis_custom_codec_data* data, STREAMFILE* sf, uint32_t* p_offset) {
// bitreader data
uint8_t* buf = data->buffer;
int hdr_size = 0x20; // variable but should be smaller
if (hdr_size > data->buffer_size)
return 0;
int bytes = read_streamfile(buf, *p_offset, hdr_size, sf);
if (bytes != hdr_size) return 0;
bitstream_t is = {0};
bm_setup(&is, buf, bytes);
// oor bitstream info
oor_page_t page = {0};
oor_header_t hdr = {0};
// header page
oor_read_page(&is, &page);
oor_read_header(&is, &hdr);
if (!oor_validate_header_page(&page, &hdr))
return 0;
// load info for header (also used for output)
vorbis_custom_config* cfg = &data->config;
cfg->channels = hdr.channels;
cfg->sample_rate = hdr.sample_rate;
cfg->blocksize_0_exp = hdr.blocksize0_exp;
cfg->blocksize_1_exp = hdr.blocksize1_exp;
cfg->last_granule = hdr.last_granule;
uint32_t packet_size = (bm_pos(&is) / 8);
*p_offset += packet_size;
return packet_size;
}
// read setup info (2nd page) and load codebooks info buf
static int build_header_setup(uint8_t* buf, int buf_size, vorbis_custom_codec_data* data, STREAMFILE* sf, uint32_t* p_offset) {
// setup info packet
int info_size = read_packet(buf, buf_size, data, sf, p_offset);
if (!info_size) return 0;
if (info_size != 0x01) //fixed mini-packet
return 0;
bitstream_t is = {0};
bm_setup(&is, data->buffer, info_size);
oor_setup_t setup = {0};
oor_read_setup(&is, &setup);
// paste missing info
if (buf_size <= 0x07)
return 0;
put_u8 (buf+0x00, 0x05); // packet_type (setup)
memcpy (buf+0x01, "vorbis", 6); // id
// read actual codebook based on prev mini-packet
int setup_size;
if (setup.codebook_id) {
#ifndef VGM_DISABLE_CODEBOOKS
// load setup from data in executables
setup_size = vcb_load_codebook_array(buf + 0x07, buf_size - 0x07, setup.codebook_id, vcb_list, vcb_list_count);
if (!setup_size) return 0;
#else
setup_size = 0;
#endif
// next packet is always 0 when codebook id is set
int empty_size = read_packet(buf + 0x07 + setup_size, buf_size - 0x07 - setup_size, data, sf, p_offset);
if (empty_size != 0) return 0;
}
else {
// load setup from data in file
setup_size = read_packet(buf + 0x07, buf_size - 0x07, data, sf, p_offset);
if (!setup_size) return 0;
}
return 0x07 + setup_size;
}
int vorbis_custom_setup_init_oor(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data) {
int ret;
uint32_t offset = start_offset;
// header
int head_size = read_header_packet(data, sf, &offset);
if (!head_size) return false;
// identification packet
data->op.bytes = build_header_identification(data->buffer, data->buffer_size, &data->config);
ret = vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op);
if (ret != 0) return false;
// comment packet
data->op.bytes = build_header_comment(data->buffer, data->buffer_size);
ret = vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op);
if (ret != 0) return false;
// setup packet
data->op.bytes = build_header_setup(data->buffer, data->buffer_size, data, sf, &offset);
ret = vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op);
if (ret != 0) return false;
data->config.data_start_offset = offset;
return true;
}
int vorbis_custom_parse_packet_oor(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data) {
uint32_t offset = stream->offset;
data->op.bytes = read_packet(data->buffer, data->buffer_size, data, stream->streamfile, &offset);
stream->offset = offset;
return data->op.bytes != 0;
}
#endif

View file

@ -4,9 +4,9 @@
#include <vorbis/codec.h> #include <vorbis/codec.h>
#include "../util/bitstream_lsb.h" #include "../util/bitstream_lsb.h"
#define WWISE_VORBIS_USE_PRECOMPILED_WVC 1 /* if enabled vgmstream weights ~150kb more but doesn't need external .wvc packets */ // if enabled vgmstream weights ~150kb more but doesn't need external packets
#if WWISE_VORBIS_USE_PRECOMPILED_WVC #ifndef VGM_DISABLE_CODEBOOKS
#include "vorbis_custom_data_wwise.h" #include "libs/vorbis_codebooks_wwise.h"
#endif #endif
@ -30,11 +30,7 @@ static size_t rebuild_setup(uint8_t* obuf, size_t obufsize, wpacket_t* wp, STREA
static int ww2ogg_generate_vorbis_packet(bitstream_t* ow, bitstream_t* iw, wpacket_t* wp, vorbis_custom_codec_data* data); static int ww2ogg_generate_vorbis_packet(bitstream_t* ow, bitstream_t* iw, wpacket_t* wp, vorbis_custom_codec_data* data);
static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis_custom_codec_data* data, size_t packet_size, STREAMFILE* sf); static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis_custom_codec_data* data, size_t packet_size, STREAMFILE* sf);
static int load_wvc(uint8_t* ibuf, size_t ibufsize, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE* sf); static int load_codebooks(uint8_t* ibuf, size_t ibufsize, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE* sf);
#if !(WWISE_VORBIS_USE_PRECOMPILED_WVC)
static int load_wvc_file(uint8_t* buf, size_t bufsize, uint32_t codebook_id, STREAMFILE* sf);
#endif
static int load_wvc_array(uint8_t* buf, size_t bufsize, uint32_t codebook_id, wwise_setup_t setup_type);
/* **************************************************************************** */ /* **************************************************************************** */
@ -676,7 +672,7 @@ static int ww2ogg_codebook_library_rebuild_by_id(bitstream_t* ow, uint32_t codeb
size_t cb_size; size_t cb_size;
bitstream_t iw; bitstream_t iw;
cb_size = load_wvc(ibuf,ibufsize, codebook_id, setup_type, sf); cb_size = load_codebooks(ibuf,ibufsize, codebook_id, setup_type, sf);
if (cb_size == 0) goto fail; if (cb_size == 0) goto fail;
bl_setup(&iw, ibuf, ibufsize); bl_setup(&iw, ibuf, ibufsize);
@ -1083,28 +1079,7 @@ fail:
/* INTERNAL UTILS */ /* INTERNAL UTILS */
/* **************************************************************************** */ /* **************************************************************************** */
/* loads an external Wwise Vorbis Codebooks file (wvc) referenced by ID and returns size */ #ifdef VGM_DISABLE_CODEBOOKS
static int load_wvc(uint8_t* ibuf, size_t ibufsize, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE* sf) {
size_t bytes;
/* try to locate from the precompiled list */
bytes = load_wvc_array(ibuf, ibufsize, codebook_id, setup_type);
if (bytes)
return bytes;
#if !(WWISE_VORBIS_USE_PRECOMPILED_WVC)
/* try to load from external file (ignoring type, just use file if found) */
bytes = load_wvc_file(ibuf, ibufsize, codebook_id, sf);
if (bytes)
return bytes;
#endif
/* not found */
VGM_LOG("Wwise Vorbis: codebook_id %04x not found\n", codebook_id);
return 0;
}
#if !(WWISE_VORBIS_USE_PRECOMPILED_WVC)
static int load_wvc_file(uint8_t* buf, size_t bufsize, uint32_t codebook_id, STREAMFILE* sf) { static int load_wvc_file(uint8_t* buf, size_t bufsize, uint32_t codebook_id, STREAMFILE* sf) {
STREAMFILE* sf_setup = NULL; STREAMFILE* sf_setup = NULL;
size_t wvc_size = 0; size_t wvc_size = 0;
@ -1149,36 +1124,25 @@ fail:
} }
#endif #endif
static int load_wvc_array(uint8_t* buf, size_t bufsize, uint32_t codebook_id, wwise_setup_t setup_type) { /* loads an external Wwise Vorbis Codebooks file (wvc) referenced by ID and returns size */
#if WWISE_VORBIS_USE_PRECOMPILED_WVC static int load_codebooks(uint8_t* ibuf, size_t ibufsize, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE* sf) {
int bytes;
/* get pointer to array */ #ifndef VGM_DISABLE_CODEBOOKS
{
int i, list_length;
const wvc_info * wvc_list;
// locate from precompiled list
switch (setup_type) { switch (setup_type) {
case WWV_EXTERNAL_CODEBOOKS: case WWV_EXTERNAL_CODEBOOKS:
wvc_list = wvc_list_standard; bytes = vcb_load_codebook_array(ibuf, ibufsize, codebook_id, vcb_list_standard, vcb_list_count_standard);
list_length = sizeof(wvc_list_standard) / sizeof(wvc_info);
break; break;
case WWV_AOTUV603_CODEBOOKS: case WWV_AOTUV603_CODEBOOKS:
wvc_list = wvc_list_aotuv603; bytes = vcb_load_codebook_array(ibuf, ibufsize, codebook_id, vcb_list_aotuv603, vcb_list_count_aotuv603);
list_length = sizeof(wvc_list_standard) / sizeof(wvc_info);
break; break;
default: default:
goto fail; return 0;
}
for (i=0; i < list_length; i++) {
if (wvc_list[i].id == codebook_id) {
if (wvc_list[i].size > bufsize) goto fail;
/* found: copy data as-is */
memcpy(buf,wvc_list[i].codebook, wvc_list[i].size);
return wvc_list[i].size;
}
}
} }
if (bytes)
return bytes;
// this can be used with 1:1 dump of the codebook file // this can be used with 1:1 dump of the codebook file
#if 0 #if 0
@ -1204,8 +1168,14 @@ static int load_wvc_array(uint8_t* buf, size_t bufsize, uint32_t codebook_id, ww
} }
#endif #endif
fail: #else
// load from external files
bytes = load_wvc_file(ibuf, ibufsize, codebook_id, sf);
if (bytes)
return bytes;
#endif #endif
VGM_LOG("Wwise Vorbis: codebook_id %04x not found\n", codebook_id);
return 0; return 0;
} }

View file

@ -350,6 +350,7 @@ static const char* extension_list[] = {
"mi4", //fake extension for .mib (renamed, to be removed) "mi4", //fake extension for .mib (renamed, to be removed)
"mib", "mib",
"mic", "mic",
"mio",
"mnstr", "mnstr",
"mogg", "mogg",
//"m4a", //common //"m4a", //common
@ -418,6 +419,7 @@ static const char* extension_list[] = {
"ogv", "ogv",
"oma", //FFmpeg/not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA) "oma", //FFmpeg/not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
"omu", "omu",
"oor",
"opu", "opu",
//"opus", //common //"opus", //common
"opusx", "opusx",
@ -667,7 +669,6 @@ static const char* extension_list[] = {
"wic", //txth/reserved [Road Rash (SAT)-videos] "wic", //txth/reserved [Road Rash (SAT)-videos]
"wip", //txth/reserved [Colin McRae DiRT (PC)] "wip", //txth/reserved [Colin McRae DiRT (PC)]
"wlv", //txth/reserved [ToeJam & Earl III: Mission to Earth (DC)] "wlv", //txth/reserved [ToeJam & Earl III: Mission to Earth (DC)]
"wmus", //fake extension (to be removed)
"wp2", "wp2",
"wpd", "wpd",
"wsd", "wsd",
@ -924,7 +925,9 @@ static const coding_info coding_info_list[] = {
{coding_TAC, "tri-Ace Codec"}, {coding_TAC, "tri-Ace Codec"},
{coding_ICE_RANGE, "Inti Creates Range Codec"}, {coding_ICE_RANGE, "Inti Creates Range Codec"},
{coding_ICE_DCT, "Inti Creates DCT Codec"}, {coding_ICE_DCT, "Inti Creates DCT Codec"},
{coding_KA1A, "Koei Tecmo KA1A Codec"}, {coding_KA1A, "Koei Tecmo KA1A"},
{coding_UBI_MPEG, "Ubisoft MPEG"},
{coding_MIO, "Entis MIO"},
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
{coding_OGG_VORBIS, "Ogg Vorbis"}, {coding_OGG_VORBIS, "Ogg Vorbis"},
@ -1178,7 +1181,6 @@ static const meta_info meta_info_list[] = {
{meta_PS2_SND, "Might and Magic SSND Header"}, {meta_PS2_SND, "Might and Magic SSND Header"},
{meta_SMSS, "Treasure SMSS header"}, {meta_SMSS, "Treasure SMSS header"},
{meta_ADS_MIDWAY, "Midway ADS header"}, {meta_ADS_MIDWAY, "Midway ADS header"},
{meta_PS2_MCG, "Gunvari MCG Header"},
{meta_ZSD, "Konami ZSD header"}, {meta_ZSD, "Konami ZSD header"},
{meta_REDSPARK, "RedSpark header"}, {meta_REDSPARK, "RedSpark header"},
{meta_RAGE_AUD, "Rockstar AUD header"}, {meta_RAGE_AUD, "Rockstar AUD header"},
@ -1214,7 +1216,7 @@ static const meta_info meta_info_list[] = {
{meta_WB, "Triangle Service .WB header"}, {meta_WB, "Triangle Service .WB header"},
{meta_S14, "Namco .S14 raw header"}, {meta_S14, "Namco .S14 raw header"},
{meta_SSS, "Namco .SSS raw header"}, {meta_SSS, "Namco .SSS raw header"},
{meta_PS2_GCM, "Namco GCM header"}, {meta_MCG, "Namco MCG header"},
{meta_SMPL, "Skonec SMPL header"}, {meta_SMPL, "Skonec SMPL header"},
{meta_MSA, "Success .MSA header"}, {meta_MSA, "Success .MSA header"},
{meta_VOI, "Irem .VOI header"}, {meta_VOI, "Irem .VOI header"},
@ -1250,7 +1252,6 @@ static const meta_info meta_info_list[] = {
{meta_LSF_N1NJ4N, "Gizmondo Studios Helsingborg LSF header"}, {meta_LSF_N1NJ4N, "Gizmondo Studios Helsingborg LSF header"},
{meta_XWAV, "feelplus XWAV header"}, {meta_XWAV, "feelplus XWAV header"},
{meta_RAW_SNDS, "PC .snds raw header"}, {meta_RAW_SNDS, "PC .snds raw header"},
{meta_PS2_WMUS, "assumed The Warriors Sony ADPCM by .wmus extension"},
{meta_HYPERSCAN_KVAG, "Mattel Hyperscan KVAG"}, {meta_HYPERSCAN_KVAG, "Mattel Hyperscan KVAG"},
{meta_PSND, "Polarbit PSND header"}, {meta_PSND, "Polarbit PSND header"},
{meta_ADP_WILDFIRE, "Wildfire ADP! header"}, {meta_ADP_WILDFIRE, "Wildfire ADP! header"},
@ -1473,7 +1474,9 @@ static const meta_info meta_info_list[] = {
{meta_XABP, "cavia XABp header"}, {meta_XABP, "cavia XABp header"},
{meta_I3DS, "Codemasters i3DS header"}, {meta_I3DS, "Codemasters i3DS header"},
{meta_AXHD, "Angel Studios AXHD header"}, {meta_AXHD, "Angel Studios AXHD header"},
{meta_SHAA, "Nintendo Alarmo SHAA header"} {meta_SHAA, "Nintendo SHAA header"},
{meta_OOR, "age .OOR header"},
{meta_MIO, "Entis .MIO header"},
}; };
void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) { void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {

View file

@ -18,9 +18,9 @@
* This may make the API a bit odd, will probably improve later. Probably. * This may make the API a bit odd, will probably improve later. Probably.
* *
* Notes: * Notes:
* - now there is an API, internals (vgmstream.h) may change in the future so avoid accesing them * - now there is an API, internals (vgmstream.h) will change in the future so avoid accesing them
* - some details described in the API may not happen at the moment (defined for future changes) * - some details described in the API may not happen at the moment (defined for future changes)
* - uses long-winded libvgmstream_* names since internals alredy use the vgmstream_* 'namespace', #define as needed * - uses long-winded libvgmstream_* names since internals alredy use the vgmstream_* 'namespace', #define if needed
* - c-strings should be in UTF-8 * - c-strings should be in UTF-8
*/ */
@ -71,20 +71,20 @@ LIBVGMSTREAM_API uint32_t libvgmstream_get_version(void);
/*****************************************************************************/ /*****************************************************************************/
/* DECODE */ /* DECODE */
/* interleaved samples: buf[0]=ch0, buf[1]=ch1, buf[2]=ch0, buf[3]=ch0, ... */ /* available sample formats, interleaved: buf[0]=ch0, buf[1]=ch1, buf[2]=ch0, buf[3]=ch0, ... */
typedef enum { typedef enum {
LIBVGMSTREAM_SAMPLE_PCM16 = 1, LIBVGMSTREAM_SFMT_PCM16 = 1,
LIBVGMSTREAM_SAMPLE_PCM24 = 2, //LIBVGMSTREAM_SFMT_PCM24 = 2,
LIBVGMSTREAM_SAMPLE_PCM32 = 3, //LIBVGMSTREAM_SFMT_PCM32 = 3,
LIBVGMSTREAM_SAMPLE_FLOAT = 4, LIBVGMSTREAM_SFMT_FLOAT = 4,
} libvgmstream_sample_t; } libvgmstream_sfmt_t;
/* current song info, may be copied around (values are info-only) */ /* current song info, may be copied around (values are info-only) */
typedef struct { typedef struct {
/* main (always set) */ /* main (always set) */
int channels; // output channels int channels; // output channels
int sample_rate; // output sample rate int sample_rate; // output sample rate
libvgmstream_sample_t sample_type; // output buffer's sample type libvgmstream_sfmt_t sample_format; // output buffer's sample type
int sample_size; // derived from sample_type (pcm16=0x02, float=0x04, etc) int sample_size; // derived from sample_type (pcm16=0x02, float=0x04, etc)
/* extra info (may be 0 if not known or not relevant) */ /* extra info (may be 0 if not known or not relevant) */
@ -126,8 +126,8 @@ typedef struct {
// query description and since libvgmstream returns its own copy it shouldn't be too much of a problem // query description and since libvgmstream returns its own copy it shouldn't be too much of a problem
// ** (may be separated later) // ** (may be separated later)
int format_id; // when reopening subfiles or similar formats without checking other all possible formats int format_id; // current format's ID (can be set when reopening streams to load a particular format)
// ** this value WILL change without warning between vgmstream versions/commits, but usually only add // ** this value WILL change without warning between vgmstream versions/commits
} libvgmstream_format_t; } libvgmstream_format_t;
@ -165,6 +165,7 @@ LIBVGMSTREAM_API void libvgmstream_free(libvgmstream_t* lib);
/* configures how vgmstream behaves internally when playing a file */ /* configures how vgmstream behaves internally when playing a file */
typedef struct { typedef struct {
bool disable_config_override; // ignore forced (TXTP) config bool disable_config_override; // ignore forced (TXTP) config
bool allow_play_forever; // must allow manually as some cases a TXTP may set loop forever but client may not handle it bool allow_play_forever; // must allow manually as some cases a TXTP may set loop forever but client may not handle it
@ -174,46 +175,39 @@ typedef struct {
bool really_force_loop; // forces full loops (0..samples) even if file has loop points bool really_force_loop; // forces full loops (0..samples) even if file has loop points
bool ignore_fade; // don't fade after N loops and play remaning stream (for files with outros) bool ignore_fade; // don't fade after N loops and play remaning stream (for files with outros)
double loop_count; // target loops (values like 1.5 are ok) double loop_count; // target loops (values like 1.5 are ok); defaults to 1; set to -1 to remove the loop section
double fade_time; // fade period after target loops double fade_time; // fade period after target loops
double fade_delay; // fade delay after target loops double fade_delay; // fade delay after target loops
int stereo_track; // forces vgmstream to decode one 2ch+2ch+2ch... 'track' and discard other channels, where 0 = disabled, 1..N = Nth track
int auto_downmix_channels; // downmix if vgmstream's channels are higher than value int auto_downmix_channels; // downmix if vgmstream's channels are higher than value
// ** for players that can only handle N channels // ** for players that can only handle N channels
// ** this type of downmixing is very simplistic and not recommended // ** this type of downmixing is very simplistic and not recommended
bool force_pcm16; // forces output buffer to be remixed into PCM16 libvgmstream_sfmt_t force_sfmt; // forces output buffer to be remixed into some sample format
bool force_float; // forces output buffer to be remixed into float
//int format_id; // force a format (for example when loading new subsong of the same archive, for a minuscule speed up)
// // ** only applies when called before _open_stream
} libvgmstream_config_t; } libvgmstream_config_t;
/* pass default config, that will be applied to song on open /* optionally pass config to apply to next _open_stream (or current stream if already loaded and not setup previously)
* - invalid config or complex cases (ex. some TXTP) may ignore these settings * - some settings may be ignored in invalid or complex cases (ex. TXTP with pre-configured options)
* - should be called without a song loaded (before _open or after _close) * - once config is applied to current stream new _setup calls only apply to next _open_stream
* - without config vgmstream will decode the current stream once * - pass NULL to clear current config
* - remember config may change format info like channels or output format (recheck if calling after loading song)
*/ */
LIBVGMSTREAM_API void libvgmstream_setup(libvgmstream_t* lib, libvgmstream_config_t* cfg); LIBVGMSTREAM_API void libvgmstream_setup(libvgmstream_t* lib, libvgmstream_config_t* cfg);
/* configures how vgmstream opens the format */
typedef struct {
libstreamfile_t* libsf; // custom IO streamfile that provides reader info for vgmstream
// ** not needed after _open and should be closed, as vgmstream re-opens its own SFs internally as needed
int subsong_index; // target subsong (1..N) or 0 = default/first
// ** to check if a file has subsongs, _open first + check format->total_subsongs (then _open 2nd, 3rd, etc)
int format_id; // force a format (for example when loading new subsong of the same archive)
int stereo_track; // forces vgmstream to decode one 2ch+2ch+2ch... 'track' and discard other channels, where 0 = disabled, 1..N = Nth track
} libvgmstream_options_t;
/* Opens file based on config and prepares it to play if supported. /* Opens file based on config and prepares it to play if supported.
* - returns < 0 on error (file not recognised, invalid subsong index, etc) * - returns < 0 on error (file not recognised, invalid subsong index, etc)
* - will close currently loaded song if needed * - will close currently loaded song if needed
* - libsf (custom IO) is not needed after _open and should be closed, as vgmstream re-opens as needed
* - subsong can be 1..N or 0 = default/first
* ** to check if a file has subsongs, _open default + check format->total_subsongs (then _open Nth)
*/ */
LIBVGMSTREAM_API int libvgmstream_open_stream(libvgmstream_t* lib, libvgmstream_options_t* open_options); LIBVGMSTREAM_API int libvgmstream_open_stream(libvgmstream_t* lib, libstreamfile_t* libsf, int subsong);
/* Closes current song; may still use libvgmstream to open other songs /* Closes current song; may still use libvgmstream to open other songs
*/ */
@ -222,6 +216,7 @@ LIBVGMSTREAM_API void libvgmstream_close_stream(libvgmstream_t* lib);
/* Decodes next batch of samples /* Decodes next batch of samples
* - vgmstream supplies its own buffer, updated on lib->decoder->* values (may change between calls) * - vgmstream supplies its own buffer, updated on lib->decoder->* values (may change between calls)
* - on last call will return samples + set flag lib->decoder->done (must handle last buf before quitting)
* - returns < 0 on error * - returns < 0 on error
*/ */
LIBVGMSTREAM_API int libvgmstream_render(libvgmstream_t* lib); LIBVGMSTREAM_API int libvgmstream_render(libvgmstream_t* lib);
@ -248,6 +243,10 @@ LIBVGMSTREAM_API void libvgmstream_seek(libvgmstream_t* lib, int64_t sample);
LIBVGMSTREAM_API void libvgmstream_reset(libvgmstream_t* lib); LIBVGMSTREAM_API void libvgmstream_reset(libvgmstream_t* lib);
/* Helper: calls _init + _setup + _open_stream
*/
LIBVGMSTREAM_API libvgmstream_t* libvgmstream_create(libstreamfile_t* libsf, int subsong, libvgmstream_config_t* cfg);
/*****************************************************************************/ /*****************************************************************************/
/* HELPERS */ /* HELPERS */
@ -259,29 +258,25 @@ typedef enum {
LIBVGMSTREAM_LOG_LEVEL_NONE = 100, LIBVGMSTREAM_LOG_LEVEL_NONE = 100,
} libvgmstream_loglevel_t; } libvgmstream_loglevel_t;
typedef struct {
libvgmstream_loglevel_t level; // log level
void (*callback)(int level, const char* str); // log callback
bool stdout_callback; // use default log callback rather than user supplied
} libvgmstream_log_t;
/* Defines a global log callback, as vgmstream sometimes communicates format issues to the user. /* Defines a global log callback, as vgmstream sometimes communicates format issues to the user.
* - note that log is currently set globally rather than per libvgmstream_t * - note that log is currently set globally rather than per libvgmstream_t
* - call with LOG_LEVEL_NONE to disable current callback
* - call with NULL callback to use default stdout callback
*/ */
LIBVGMSTREAM_API void libvgmstream_set_log(libvgmstream_log_t* cfg); LIBVGMSTREAM_API void libvgmstream_set_log(libvgmstream_loglevel_t level, void (*callback)(int level, const char* str));
/* Returns a list of supported extensions (WARNING: it's pretty big), such as "adx", "dsp", etc. /* Returns a list of supported extensions (WARNING: it's pretty big), such as "adx", "dsp", etc.
* Mainly for plugins that want to know which extensions are supported. * Mainly for plugins that want to know which extensions are supported.
* - returns NULL if no size is provided * - returns NULL if no size is provided
*/ */
LIBVGMSTREAM_API const char** libvgmstream_get_extensions(size_t* size); LIBVGMSTREAM_API const char** libvgmstream_get_extensions(int* size);
/* Same as above, buf returns a list what vgmstream considers "common" formats (such as "wav", "ogg"), /* Same as above, buf returns a list what vgmstream considers "common" formats (such as "wav", "ogg"),
* which usually one doesn't want to associate to vgmstream. * which usually one doesn't want to associate to vgmstream.
* - returns NULL if no size is provided * - returns NULL if no size is provided
*/ */
LIBVGMSTREAM_API const char** libvgmstream_get_common_extensions(size_t* size); LIBVGMSTREAM_API const char** libvgmstream_get_common_extensions(int* size);
typedef struct { typedef struct {
@ -301,7 +296,7 @@ LIBVGMSTREAM_API bool libvgmstream_is_valid(const char* filename, libvgmstream_v
typedef struct { typedef struct {
bool force_title; // TODO: what was this for? bool force_title; // force stream name as title (by default it may be hiddedn if file has no subsongs)
bool subsong_range; // print a range of possible subsongs after title 'filename#1~N' bool subsong_range; // print a range of possible subsongs after title 'filename#1~N'
bool remove_extension; // remove extension from passed filename bool remove_extension; // remove extension from passed filename
bool remove_archive; // remove '(archive)|(subfile)' format of some plugins bool remove_archive; // remove '(archive)|(subfile)' format of some plugins
@ -350,11 +345,13 @@ LIBVGMSTREAM_API void libvgmstream_tags_find(libvgmstream_tags_t* tags, const ch
/* Extracts next valid tag in tagfile to key/val. /* Extracts next valid tag in tagfile to key/val.
* - returns false if no more tags are found (meant to be called repeatedly until false) * - returns false if no more tags are found (meant to be called repeatedly until false)
* - key/values are trimmed of beginning/end whitespaces and values are in UTF-8 * - key/values are trimmed of beginning/end whitespaces and values are UTF-8
*/ */
LIBVGMSTREAM_API bool libvgmstream_tags_next_tag(libvgmstream_tags_t* tags); LIBVGMSTREAM_API bool libvgmstream_tags_next_tag(libvgmstream_tags_t* tags);
/* Closes tags. */ /* Closes tags.
* - passed libsf is not closed
*/
LIBVGMSTREAM_API void libvgmstream_tags_free(libvgmstream_tags_t* tags); LIBVGMSTREAM_API void libvgmstream_tags_free(libvgmstream_tags_t* tags);

View file

@ -13,34 +13,23 @@
*/ */
enum {
LIBSTREAMFILE_SEEK_SET = 0,
LIBSTREAMFILE_SEEK_CUR = 1,
LIBSTREAMFILE_SEEK_END = 2,
//LIBSTREAMFILE_SEEK_GET_OFFSET = 3,
//LIBSTREAMFILE_SEEK_GET_SIZE = 5,
};
// should be "libvgmstream_streamfile_t" but it was getting unwieldly // should be "libvgmstream_streamfile_t" but it was getting unwieldly
typedef struct libstreamfile_t { typedef struct libstreamfile_t {
//uint32_t flags; // info flags for vgmstream //uint32_t flags; // info flags for vgmstream
void* user_data; // any internal structure void* user_data; // any internal structure
/* read 'length' data at internal offset to 'dst' /* read 'length' data at 'offset' to 'dst'
* - assumes 0 = failure/EOF * - assumes 0 = failure/EOF
* - note that vgmstream needs to seek + read from arbitrary offset (non-linearly) fairly often
*/ */
int (*read)(void* user_data, uint8_t* dst, int dst_size); int (*read)(void* user_data, uint8_t* dst, int64_t offset, int length);
/* seek to offset
* - note that vgmstream needs to seek + read fairly often (to be optimized someday)
*/
int64_t (*seek)(void* user_data, int64_t offset, int whence);
/* get max offset (typically for checks or sample calculations) /* get max offset (typically for checks or sample calculations)
*/ */
int64_t (*get_size)(void* user_data); int64_t (*get_size)(void* user_data);
/* get current filename (used to open same or other streamfiles and heuristics; no need to be a real path) /* get current filename
* - used to open same or other streamfiles and heuristics; no need to be a real path but extension matters
*/ */
const char* (*get_name)(void* user_data); const char* (*get_name)(void* user_data);
@ -49,13 +38,14 @@ typedef struct libstreamfile_t {
*/ */
struct libstreamfile_t* (*open)(void* user_data, const char* filename); struct libstreamfile_t* (*open)(void* user_data, const char* filename);
/* free current SF */ /* free current SF
*/
void (*close)(struct libstreamfile_t* libsf); void (*close)(struct libstreamfile_t* libsf);
} libstreamfile_t; } libstreamfile_t;
/* helper */ /* helpers */
static inline void libstreamfile_close(libstreamfile_t* libsf) { static inline void libstreamfile_close(libstreamfile_t* libsf) {
if (!libsf || !libsf->close) if (!libsf || !libsf->close)
return; return;

View file

@ -0,0 +1,57 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
/* .2dx - Konami/Bemani beatmania IIDX container [beatmania IIDX 9th Style (AC) - beatmania IIDX 15 DJ TROOPERS (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;
/* 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;
if (target_subsong == 0) target_subsong = 1;
total_subsongs = read_u32le(meta_offset + 0x4,sf);
if (target_subsong > total_subsongs)
goto fail;
subfile_offset = read_u32le(table_offset + 0x04 * (target_subsong - 1), sf);
subfile_size = read_u32le(subfile_offset + 0x8,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);
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -70,27 +70,27 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
off_t start_offset = 0, coef_offset = 0; off_t start_offset = 0, coef_offset = 0;
uint32_t aifx_size, file_size; uint32_t aifx_size, file_size;
coding_t coding_type = 0; coding_t coding_type = 0;
int channels = 0, sample_count = 0, sample_size = 0, sample_rate = 0;
int interleave = 0;
int loop_flag = 0;
int32_t loop_start = 0, loop_end = 0;
int is_aiff_ext = 0, is_aifc_ext = 0, is_aiff = 0, is_aifc = 0;
int fver_found = 0, comm_found = 0, data_found = 0;
off_t mark_offset = 0, inst_offset = 0;
/* checks */ /* checks */
if (!is_id32be(0x00,sf, "FORM")) if (!is_id32be(0x00,sf, "FORM"))
return NULL; return NULL;
int channels = 0, sample_count = 0, sample_size = 0, sample_rate = 0;
int interleave = 0;
int loop_flag = 0;
int32_t loop_start = 0, loop_end = 0;
off_t mark_offset = 0, inst_offset = 0;
bool is_aiff_ext = false, is_aifc_ext = false, is_aiff = false, is_aifc = false;
/* .aif: common (AIFF or AIFC) /* .aif: common (AIFF or AIFC)
* .wav: SimCity 3000 (Mac) (both AIFF and AIFC) * .wav: SimCity 3000 (Mac) (both AIFF and AIFC)
* .aiff: rare and actually AIFC (maybe renamed AIFF too) [Cro-Mag Rally (Mac)] * .aiff: rare and actually AIFC (maybe renamed AIFF too) [Cro-Mag Rally (Mac)]
* (extensionless): Doom (3DO) * (extensionless): Doom (3DO)
* *
* .aifc: renamed AIFC? * .aifc: renamed AIFC?
* .afc: ? * .afc: Waialae Country Club (3D0), Star Wars: Anakin's Speedway (PC)
* .cbd2: M2 games * .cbd2: M2 games
* .bgm: Super Street Fighter II Turbo (3DO) * .bgm: Super Street Fighter II Turbo (3DO)
* .fda: Homeworld 2 (PC) * .fda: Homeworld 2 (PC)
@ -106,14 +106,14 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
* .mpc: The Godfather (PC) (writercredit.mpc) * .mpc: The Godfather (PC) (writercredit.mpc)
*/ */
if (check_extensions(sf, "aif,laif,wav,lwav,aiff,laiff,")) { if (check_extensions(sf, "aif,laif,wav,lwav,aiff,laiff,")) {
is_aifc_ext = 1; is_aifc_ext = true;
is_aiff_ext = 1; is_aiff_ext = true;
} }
else if (check_extensions(sf, "aifc,laifc,afc,cbd2,bgm,fda,n64,xa,caf")) { else if (check_extensions(sf, "aifc,laifc,afc,cbd2,bgm,fda,n64,xa,caf")) {
is_aifc_ext = 1; is_aifc_ext = true;
} }
else if (check_extensions(sf, "acm,adp,ai,pcm,vp6,mpc,lmpc")) { else if (check_extensions(sf, "acm,adp,ai,pcm,vp6,mpc,lmpc")) {
is_aiff_ext = 1; is_aiff_ext = true;
} }
else { else {
return NULL; return NULL;
@ -125,15 +125,15 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
/* AIFF originally allowed only PCM (non-compressed) audio, so newer AIFC was added, /* AIFF originally allowed only PCM (non-compressed) audio, so newer AIFC was added,
* though some AIFF with other codecs exist */ * though some AIFF with other codecs exist */
if (is_id32be(0x08,sf, "AIFC")) { if (is_id32be(0x08,sf, "AIFC")) {
if (!is_aifc_ext) goto fail; if (!is_aifc_ext) return NULL;
is_aifc = 1; is_aifc = true;
} }
else if (is_id32be(0x08,sf, "AIFF")) { else if (is_id32be(0x08,sf, "AIFF")) {
if (!is_aiff_ext) goto fail; if (!is_aiff_ext) return NULL;
is_aiff = 1; is_aiff = true;
} }
else { else {
goto fail; return NULL;
} }
/* some games have wonky sizes, selectively fix to catch bad rips and new mutations */ /* some games have wonky sizes, selectively fix to catch bad rips and new mutations */
@ -146,31 +146,34 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
if (aifx_size + 0x08 != file_size) { if (aifx_size + 0x08 != file_size) {
vgm_logi("AIFF: wrong reported size %x + 0x8 vs file size %x\n", aifx_size, file_size); vgm_logi("AIFF: wrong reported size %x + 0x8 vs file size %x\n", aifx_size, file_size);
goto fail; return NULL;
} }
/* read through chunks to verify format and find metadata */ /* read through chunks to verify format and find metadata */
{ {
bool fver_found = false, comm_found = false, data_found = false;
off_t offset = 0x0c; /* start with first chunk within FORM */ off_t offset = 0x0c; /* start with first chunk within FORM */
while (offset < file_size) { while (offset < file_size) {
uint32_t chunk_type = read_u32be(offset + 0x00,sf); uint32_t chunk_type = read_u32be(offset + 0x00,sf);
uint32_t chunk_size = read_u32be(offset + 0x04,sf); uint32_t chunk_size = read_u32be(offset + 0x04,sf);
/* chunks must be padded to an even number of bytes but chunk offset += 0x08;
* size does not include that padding */ if (offset + chunk_size > file_size) {
VGM_LOG("AIFF: wrong chunk_size %x + %x\n", (int)offset, chunk_size);
return NULL;
}
// Chunks must be padded to an even number of bytes but chunk size does not include that padding.
// Last chunk it may not be padded so handle after offset check (some tools only?) [Anakin's Speedway (PC)]
if (chunk_size % 2) if (chunk_size % 2)
chunk_size++; chunk_size++;
offset += 0x08;
if (offset + chunk_size > file_size)
goto fail;
switch(chunk_type) { switch(chunk_type) {
case 0x46564552: /* "FVER" (version info, officially required but some odd game ommits it [Cro-Mag Rally (Mac)]) */ case 0x46564552: /* "FVER" (version info, officially required but some odd game ommits it [Cro-Mag Rally (Mac)]) */
if (fver_found) goto fail; if (fver_found) goto fail;
if (is_aiff) goto fail; /* plain AIFF shouldn't have */ if (is_aiff) goto fail; /* plain AIFF shouldn't have */
fver_found = 1; fver_found = true;
if (chunk_size != 4) if (chunk_size != 4)
goto fail; goto fail;
@ -181,7 +184,7 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
case 0x434F4D4D: /* "COMM" (main header) */ case 0x434F4D4D: /* "COMM" (main header) */
if (comm_found) goto fail; if (comm_found) goto fail;
comm_found = 1; comm_found = true;
channels = read_u16be(offset + 0x00,sf); channels = read_u16be(offset + 0x00,sf);
sample_count = read_u32be(offset + 0x02,sf); /* sample_frames in theory, depends on codec */ sample_count = read_u32be(offset + 0x02,sf); /* sample_frames in theory, depends on codec */
@ -220,9 +223,10 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
case 0x434F4D50: { /* "COMP" (generic compression) */ case 0x434F4D50: { /* "COMP" (generic compression) */
uint8_t name_size = read_u8(offset + 0x16, sf); uint8_t name_size = read_u8(offset + 0x16, sf);
if (is_str("Relic Codec v1.6", name_size, offset + 0x17, sf)) { if (is_str("Relic Codec v1.6", name_size, offset + 0x17, sf)) { /* Homeworld 2 (PC) */
coding_type = coding_RELIC; coding_type = coding_RELIC;
sample_count = sample_count * 512; sample_count = sample_count * 512;
sample_rate = 44100; // fixed output
} }
else { else {
goto fail; goto fail;
@ -235,7 +239,14 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
coding_type = coding_VADPCM; coding_type = coding_VADPCM;
/* N64 tools don't create FVER, but it's required by the spec (could skip the check though) */ /* N64 tools don't create FVER, but it's required by the spec (could skip the check though) */
fver_found = 1; fver_found = true;
break;
}
case 0x76696D61: { /* "vima" [Star Wars Anakin's Speedway (PC), Star Wars Early Learning Activity Center (PC)] */
/* "Variable IMA 16 bit" */
coding_type = coding_IMUSE;
sample_rate = 22050; // field has garbage (like part of the name) consistently
break; break;
} }
@ -267,7 +278,7 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
case 0x53534E44: /* "SSND" (main data) */ case 0x53534E44: /* "SSND" (main data) */
case 0x4150434D: /* "APCM" (main data for XA) */ case 0x4150434D: /* "APCM" (main data for XA) */
if (data_found) goto fail; if (data_found) goto fail;
data_found = 1; data_found = true;
/* 00: offset (for aligment, usually 0) /* 00: offset (for aligment, usually 0)
* 04: block size (ex. XA: 0x914) */ * 04: block size (ex. XA: 0x914) */
@ -315,7 +326,6 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
offset += chunk_size; offset += chunk_size;
} }
}
if (is_aifc) { if (is_aifc) {
if (/*!fver_found ||*/ !comm_found || !data_found) if (/*!fver_found ||*/ !comm_found || !data_found)
@ -325,6 +335,8 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
if (!comm_found || !data_found) if (!comm_found || !data_found)
goto fail; goto fail;
} }
}
/* read loop points */ /* read loop points */
if (inst_offset && mark_offset) { if (inst_offset && mark_offset) {
@ -399,8 +411,6 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
vgmstream->codec_data = init_relic(channels, bitrate, sample_rate); vgmstream->codec_data = init_relic(channels, bitrate, sample_rate);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
vgmstream->sample_rate = 44100; /* fixed output */
break; break;
} }
@ -421,6 +431,13 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
//vgmstream->num_samples = vadpcm_bytes_to_samples(data_size, channels); /* unneeded */ //vgmstream->num_samples = vadpcm_bytes_to_samples(data_size, channels); /* unneeded */
break; break;
case coding_IMUSE: {
vgmstream->codec_data = init_imuse_aifc(sf, start_offset, channels);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
break;
}
default: default:
vgmstream->layout_type = (channels > 1) ? layout_interleave : layout_none; vgmstream->layout_type = (channels > 1) ? layout_interleave : layout_none;
vgmstream->interleave_block_size = interleave; vgmstream->interleave_block_size = interleave;

View file

@ -4,27 +4,25 @@
/* .BAF - Bizarre Creations bank file [Blur (PS3), Project Gotham Racing 4 (X360), Geometry Wars (PC)] */ /* .BAF - Bizarre Creations bank file [Blur (PS3), Project Gotham Racing 4 (X360), Geometry Wars (PC)] */
VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) { VGMSTREAM* init_vgmstream_baf(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
char bank_name[0x22+1], stream_name[0x20+1], file_name[STREAM_NAME_SIZE];
off_t start_offset, header_offset, name_offset; off_t start_offset, header_offset, name_offset;
size_t stream_size; size_t stream_size;
uint32_t channel_count, sample_rate, num_samples, version, codec, tracks; uint32_t channel_count, sample_rate, num_samples, version, codec, tracks;
int loop_flag, total_subsongs, target_subsong = sf->stream_index; int big_endian, loop_flag, total_subsongs, target_subsong = sf->stream_index;
read_u32_t read_u32; read_u32_t read_u32;
/* checks */ /* checks */
if (!is_id32be(0x00, sf, "BANK")) if (!is_id32be(0x00, sf, "BANK"))
goto fail; return NULL;
if (!check_extensions(sf, "baf")) if (!check_extensions(sf, "baf"))
goto fail; return NULL;
/* use BANK size to check endianness */ /* use BANK size to check endianness */
if (guess_endian32(0x04,sf)) { big_endian = guess_endian32(0x04, sf);
read_u32 = read_u32be; read_u32 = big_endian ? read_u32be : read_u32le;
} else {
read_u32 = read_u32le;
}
/* 0x04: bank size */ /* 0x04: bank size */
version = read_u32(0x08,sf); version = read_u32(0x08,sf);
@ -69,7 +67,7 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
tracks = 0; tracks = 0;
switch(codec) { switch(codec) {
case 0x03: /* PCM16LE */ case 0x03: /* PCM16 */
switch(version) { switch(version) {
case 0x03: /* Geometry Wars (PC) */ case 0x03: /* Geometry Wars (PC) */
sample_rate = read_u32(header_offset+0x38, sf); sample_rate = read_u32(header_offset+0x38, sf);
@ -84,6 +82,12 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
loop_flag = read_u8(header_offset+0x4b, sf); loop_flag = read_u8(header_offset+0x4b, sf);
break; break;
case 0x05: /* Blur 2 (X360) */
sample_rate = read_u32(header_offset+0x40, sf);
channel_count = read_u32(header_offset+0x48, sf);
loop_flag = read_u8(header_offset+0x50, sf) != 0;
break;
default: default:
goto fail; goto fail;
} }
@ -93,14 +97,14 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
case 0x07: /* PSX ADPCM (0x21 frame size) */ case 0x07: /* PSX ADPCM (0x21 frame size) */
if (version == 0x04 && read_u32(header_offset + 0x3c, sf) != 0) { if (version == 0x04 && read_u32(header_offset + 0x3c, sf) != 0) {
/* Blur (Prototype) (PS3) */ /* The Club (PS3), Blur (Prototype) (PS3) */
sample_rate = read_u32(header_offset+0x3c, sf); sample_rate = read_u32(header_offset+0x3c, sf);
channel_count = read_u32(header_offset+0x44, sf); channel_count = read_u32(header_offset+0x44, sf);
loop_flag = read_u8(header_offset+0x4b, sf); loop_flag = read_u8(header_offset+0x4b, sf);
/* mini-header at the start of the stream */ /* mini-header at the start of the stream */
num_samples = read_u32le(start_offset+0x04, sf) / 0x02; /* PCM size? */ num_samples = read_u32le(start_offset+0x04, sf) / channel_count;
start_offset += read_u32le(start_offset+0x00, sf); start_offset += read_u32le(start_offset+0x00, sf); /* 0x08 */
break; break;
} }
@ -117,14 +121,16 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
channel_count = channel_count * tracks; channel_count = channel_count * tracks;
} }
break; break;
default: default:
goto fail; goto fail;
} }
break; break;
case 0x08: /* XMA1 */ case 0x08: /* XMA1 */
case 0x09: /* XMA2 */
switch(version) { switch(version) {
case 0x04: /* Project Gotham Racing (X360) */ case 0x04: /* Project Gotham Racing 4 (X360) */
sample_rate = read_u32(header_offset+0x3c, sf); sample_rate = read_u32(header_offset+0x3c, sf);
channel_count = read_u32(header_offset+0x44, sf); channel_count = read_u32(header_offset+0x44, sf);
loop_flag = read_u8(header_offset+0x54, sf) != 0; loop_flag = read_u8(header_offset+0x54, sf) != 0;
@ -160,7 +166,7 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
switch(codec) { switch(codec) {
case 0x03: case 0x03:
vgmstream->coding_type = coding_PCM16LE; vgmstream->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
vgmstream->layout_type = layout_interleave; vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02; vgmstream->interleave_block_size = 0x02;
@ -179,44 +185,73 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *sf) {
vgmstream->loop_end_sample = num_samples; vgmstream->loop_end_sample = num_samples;
break; break;
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
case 0x08: { case 0x08:
vgmstream->codec_data = init_ffmpeg_xma1_raw(sf, start_offset, stream_size, vgmstream->channels, vgmstream->sample_rate, 0); case 0x09: {
if (!vgmstream->codec_data) goto fail; int is_xma1 = (codec == 0x08);
vgmstream->coding_type = coding_FFmpeg; int block_size = 0x10000;
vgmstream->layout_type = layout_none;
/* need to manually find sample offsets, it was a thing with XMA1 */ /* need to manually find sample offsets, it was a thing with XMA1 */
{ {
ms_sample_data msd = {0}; ms_sample_data msd = {0};
msd.xma_version = 1; msd.xma_version = is_xma1 ? 1 : 2;
msd.channels = channel_count; msd.channels = channel_count;
msd.data_offset = start_offset; msd.data_offset = start_offset;
msd.data_size = stream_size; msd.data_size = stream_size;
msd.loop_flag = loop_flag; msd.loop_flag = loop_flag;
switch(version) {
case 0x04:
msd.loop_start_b = read_u32(header_offset+0x4c, sf); msd.loop_start_b = read_u32(header_offset+0x4c, sf);
msd.loop_end_b = read_u32(header_offset+0x50, sf); msd.loop_end_b = read_u32(header_offset+0x50, sf);
msd.loop_start_subframe = (read_u8(header_offset+0x55, sf) >> 0) & 0x0f; msd.loop_start_subframe = (read_u8(header_offset+0x55, sf) >> 0) & 0x0f;
msd.loop_end_subframe = (read_u8(header_offset+0x55, sf) >> 4) & 0x0f; msd.loop_end_subframe = (read_u8(header_offset+0x55, sf) >> 4) & 0x0f;
break;
case 0x05:
msd.loop_start_b = read_u32(header_offset+0x50, sf);
msd.loop_end_b = read_u32(header_offset+0x54, sf);
msd.loop_start_subframe = (read_u8(header_offset+0x59, sf) >> 0) & 0x0f;
msd.loop_end_subframe = (read_u8(header_offset+0x59, sf) >> 4) & 0x0f;
break;
default:
goto fail;
}
xma_get_samples(&msd, sf); xma_get_samples(&msd, sf);
vgmstream->num_samples = msd.num_samples; /* also at 0x58, but unreliable? */ vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = msd.num_samples; /* also at 0x58(v4)/0x5C(v5) for XMA1, but unreliable? */
vgmstream->loop_start_sample = msd.loop_start_sample; vgmstream->loop_start_sample = msd.loop_start_sample;
vgmstream->loop_end_sample = msd.loop_end_sample; vgmstream->loop_end_sample = msd.loop_end_sample;
vgmstream->codec_data = is_xma1
? init_ffmpeg_xma1_raw(sf, start_offset, stream_size, vgmstream->channels, vgmstream->sample_rate, 0)
: init_ffmpeg_xma2_raw(sf, start_offset, stream_size, vgmstream->num_samples, vgmstream->channels, vgmstream->sample_rate, block_size, 0);
if (!vgmstream->codec_data) goto fail;
} }
xma_fix_raw_samples_ch(vgmstream, sf, start_offset, stream_size, channel_count, 1,1); xma_fix_raw_samples_ch(vgmstream, sf, start_offset, stream_size, channel_count, 1,1);
break; break;
} }
#endif #endif
default: default:
VGM_LOG("BAF: unknown codec %x\n", codec); VGM_LOG("BAF: unknown codec %x\n", codec);
goto fail; goto fail;
} }
read_string(vgmstream->stream_name,0x20+1, name_offset,sf); read_string(bank_name, sizeof(bank_name), (version == 0x03) ? 0x11 : 0x12, sf);
read_string(stream_name, sizeof(stream_name), name_offset, sf);
get_streamfile_basename(sf, file_name, STREAM_NAME_SIZE);
if (bank_name[0] && strcmp(file_name, bank_name) != 0)
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%s/%s", bank_name, stream_name);
else
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%s", stream_name);
if (!vgmstream_open_stream(vgmstream, sf, start_offset)) if (!vgmstream_open_stream(vgmstream, sf, start_offset))

View file

@ -724,8 +724,10 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) {
/* searches the chunk until it finds the target name/index, or breaks at empty name */ /* searches the chunk until it finds the target name/index, or breaks at empty name */
while (read_u8(stream_name_offset, sf)) { while (read_u8(stream_name_offset, sf)) {
/* in case it goes somewhere out of bounds unexpectedly */ /* in case it goes somewhere out of bounds unexpectedly */
if (((read_u8(stream_name_offset + 0x00, sf) + read_u8(stream_name_offset + 0x04, sf) + if (((read_u8(stream_name_offset + 0x00, sf)
read_u8(stream_name_offset + 0x08, sf) + read_u8(stream_name_offset + 0x0C, sf)) & 0x1F) != i) + read_u8(stream_name_offset + 0x04, sf)
+ read_u8(stream_name_offset + 0x08, sf)
+ read_u8(stream_name_offset + 0x0C, sf)) & 0x1F) != i)
goto fail; goto fail;
if (read_u16(stream_name_offset + 0x10, sf) == table4_entry_id) { if (read_u16(stream_name_offset + 0x10, sf) == table4_entry_id) {
read_string(h->stream_name, STREAM_NAME_SIZE, stream_name_offset, sf); read_string(h->stream_name, STREAM_NAME_SIZE, stream_name_offset, sf);
@ -735,7 +737,7 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) {
stream_name_offset += 0x14; stream_name_offset += 0x14;
} }
} }
//goto fail; /* didn't find any valid index? */ goto fail; /* didn't find any valid index? */
loop_break: loop_break:
break; break;

View file

@ -10,17 +10,16 @@ VGMSTREAM* init_vgmstream_compresswave(STREAMFILE *sf) {
/* checks */ /* checks */
if (!check_extensions(sf, "cwav"))
goto fail;
if (!is_id64be(0x00,sf, "CmpWave\0")) if (!is_id64be(0x00,sf, "CmpWave\0"))
goto fail; return NULL;
if (!check_extensions(sf, "cwav"))
return NULL;
channels = 2; /* always, header channels is internal config */ channels = 2; /* always, header channels is internal config */
start_offset = 0x00; start_offset = 0x00;
loop_flag = 1; //read_u8(0x430, sf) != 0; /* wrong count, see below */ loop_flag = true; //read_u8(0x430, sf) != 0; /* wrong count, see below */
/* codec allows to use a cipher value, not seen */ // codec allows to use a cipher value, not seen
/* there is also title and artist, but default to "UnTitled" / "NoName" */ // there is also title and artist, but default to "UnTitled" / "NoName"
/* build the VGMSTREAM */ /* build the VGMSTREAM */
@ -28,10 +27,9 @@ VGMSTREAM* init_vgmstream_compresswave(STREAMFILE *sf) {
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->meta_type = meta_COMPRESSWAVE; vgmstream->meta_type = meta_COMPRESSWAVE;
vgmstream->sample_rate = 44100; /* always, header rate is internal config */ vgmstream->sample_rate = 44100; // always, header rate is internal config
/* in PCM bytes */ vgmstream->num_samples = read_u64le(0x418, sf) / sizeof(int16_t) / channels; // in PCM bytes
vgmstream->num_samples = read_u64le(0x418, sf) / sizeof(int16_t) / channels; // known files have wrong loop values and just repeat
/* known files have wrong loop values and just repeat */
vgmstream->loop_start_sample = 0; //read_u64le(0x420, sf) / sizeof(int16_t) / channels; vgmstream->loop_start_sample = 0; //read_u64le(0x420, sf) / sizeof(int16_t) / channels;
vgmstream->loop_end_sample = vgmstream->num_samples; //read_u64le(0x428, sf) / sizeof(int16_t) / channels; vgmstream->loop_end_sample = vgmstream->num_samples; //read_u64le(0x428, sf) / sizeof(int16_t) / channels;

View file

@ -385,6 +385,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
mpeg_custom_config cfg = {0}; mpeg_custom_config cfg = {0};
cfg.fsb_padding = (vgmstream->channels > 2 ? 16 : 4); /* observed default */ cfg.fsb_padding = (vgmstream->channels > 2 ? 16 : 4); /* observed default */
cfg.data_size = fsb5.stream_offset + fsb5.stream_size;
vgmstream->codec_data = init_mpeg_custom(sb, fsb5.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg); vgmstream->codec_data = init_mpeg_custom(sb, fsb5.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;

View file

@ -70,6 +70,7 @@ static const fsbkey_info fsbkey_list[] = {
{ MODE_FSB5, FSBKEY_ADD("3cfe772db5b55b806541d3faf894020e") }, // Final Fantasy XV: War for Eos (Android) { MODE_FSB5, FSBKEY_ADD("3cfe772db5b55b806541d3faf894020e") }, // Final Fantasy XV: War for Eos (Android)
{ MODE_FSB5, FSBKEY_ADD("aj#$kLucf2lh}eqh") }, // Forza Motorsport 2023 (PC) { MODE_FSB5, FSBKEY_ADD("aj#$kLucf2lh}eqh") }, // Forza Motorsport 2023 (PC)
{ MODE_FSB4, FSBKEY_ADD("dpdjeoqkr") }, // AirRider CrazyRacing (PC) { MODE_FSB4, FSBKEY_ADD("dpdjeoqkr") }, // AirRider CrazyRacing (PC)
{ MODE_FSB5, FSBKEY_ADD("weareAbsolutelyUnsure2018") }, // Wanderstop (PC)
/* some games use a key per file, generated from the filename /* some games use a key per file, generated from the filename
* (could add all of them but there are a lot of songs, so external .fsbkey are probably better) */ * (could add all of them but there are a lot of songs, so external .fsbkey are probably better) */

View file

@ -111,7 +111,7 @@ VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) {
/* Assumed mappings; seems correct vs Atom Viewer, that lists L/R/C/LFE/LS/RS and downmixes HCAs like that. /* Assumed mappings; seems correct vs Atom Viewer, that lists L/R/C/LFE/LS/RS and downmixes HCAs like that.
* USM HCA's seem to be L/R/SL/SR/C/LFE though (probably reordered at USM level, no detection done in Atom Viewer). */ * USM HCA's seem to be L/R/SL/SR/C/LFE though (probably reordered at USM level, no detection done in Atom Viewer). */
{ if (vgmstream->channels <= 8) { // 8 is max but just in case
static const uint32_t hca_mappings[] = { static const uint32_t hca_mappings[] = {
0, 0,
mapping_MONO, mapping_MONO,

View file

@ -518,6 +518,7 @@ static const hcakey_info hcakey_list[] = {
{0x0c59613fc788cec7}, // music_0210025 {0x0c59613fc788cec7}, // music_0210025
{0xf61a0cfac4072903}, // music_0210026 {0xf61a0cfac4072903}, // music_0210026
{0xa316e41cc9303921}, // music_0210027 {0xa316e41cc9303921}, // music_0210027
{0x61933afefe5f14c3}, // music_0210028
{0x15bb78c31db0a0b6}, // music_0220001 {0x15bb78c31db0a0b6}, // music_0220001
{0x59b1257242c40109}, // music_0220002 {0x59b1257242c40109}, // music_0220002
{0xdb402bd08d522f34}, // music_0220003 {0xdb402bd08d522f34}, // music_0220003
@ -711,6 +712,7 @@ static const hcakey_info hcakey_list[] = {
{0x9f37cb27968428fa}, // music_0610027 {0x9f37cb27968428fa}, // music_0610027
{0x36024c4a109520ec}, // music_0610028 {0x36024c4a109520ec}, // music_0610028
{0x758ad666ba171bd7}, // music_0610029 {0x758ad666ba171bd7}, // music_0610029
{0xe3c90dcaed524e49}, // music_0610030
{0x8258ddd6a1d0849b}, // music_0620001 {0x8258ddd6a1d0849b}, // music_0620001
{0x1dd21a1244ca12f1}, // music_0620002 {0x1dd21a1244ca12f1}, // music_0620002
{0xfdec74b23d8b494b}, // music_0620003 {0xfdec74b23d8b494b}, // music_0620003
@ -1267,6 +1269,11 @@ static const hcakey_info hcakey_list[] = {
{0x34c0f6db642145a0}, // music_5050307 {0x34c0f6db642145a0}, // music_5050307
{0xb7ecea9165c448da}, // music_5050308 {0xb7ecea9165c448da}, // music_5050308
{0xa5e9bd945c5caf2c}, // music_5050309 {0xa5e9bd945c5caf2c}, // music_5050309
{0x91ff4aedae9ce2c3}, // music_5050313
{0xeaaa417505d65dd1}, // music_5050322
{0x591899d025c3beb7}, // music_5050323
{0xa57678c62ef99124}, // music_5050324
{0x925f360a8ccb4c32}, // music_5050325
{0x52c250eade92393b}, // music_9010001 {0x52c250eade92393b}, // music_9010001
{0xf66e6bb5b0599b07}, // music_9010002 {0xf66e6bb5b0599b07}, // music_9010002
{0x8582b5a60dbbf948}, // music_9010003 {0x8582b5a60dbbf948}, // music_9010003
@ -1529,6 +1536,9 @@ static const hcakey_info hcakey_list[] = {
// Freedom Wars Remastered (Switch) // Freedom Wars Remastered (Switch)
{3258660547165106863}, // 2D391680A55B32AF {3258660547165106863}, // 2D391680A55B32AF
// Suikoden I & II HD Remaster (PC)
{14510296783270449627u}, // C95EEE0BA85411DB
}; };
#endif #endif

View file

@ -136,7 +136,7 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) {
vgmstream->coding_type = coding_IMUSE; vgmstream->coding_type = coding_IMUSE;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
vgmstream->codec_data = init_imuse(sf, channels); vgmstream->codec_data = init_imuse_mcomp(sf, channels);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
if (name_offset > 0) if (name_offset > 0)

View file

@ -1,64 +1,32 @@
#include "meta.h" #include "meta.h"
#include "../util.h" #include "../coding/coding.h"
#include "../util/meta_utils.h"
/* KRAW (from Geometry Wars - Galaxies) */ /* KRAW - from Geometry Wars: Galaxies (Wii) */
VGMSTREAM * init_vgmstream_kraw(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_kraw(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag = 0;
int channel_count;
/* check extension, case insensitive */ /* checks */
streamFile->get_name(streamFile,filename,sizeof(filename)); if (!is_id32be(0x00,sf, "kRAW"))
if (strcasecmp("kraw",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x6B524157) /* "kRAW" */
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 = 0x8;
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_PCM16BE;
vgmstream->num_samples = read_32bitBE(0x04,streamFile)/2/channel_count;
if (loop_flag) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = read_32bitBE(0x04,streamFile)/2/channel_count;
}
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_KRAW;
vgmstream->allow_dual_stereo = 1;
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL; return NULL;
// .kRAW: actual extension
if (!check_extensions(sf, "kraw"))
return NULL;
meta_header_t h = {0};
h.data_size = read_u32be(0x04,sf);
h.meta = meta_KRAW;
h.stream_offset = 0x08;
h.channels = 1;
h.sample_rate = 32000;
h.num_samples = pcm16_bytes_to_samples(h.data_size, h.channels);
h.allow_dual_stereo = true;
h.coding = coding_PCM16BE;
h.layout = layout_none;
h.open_stream = true;
h.sf = sf;
return alloc_metastream(&h);
} }

View file

@ -512,7 +512,6 @@ static bool parse_ktsr_subfile(ktsr_header_t* ktsr, STREAMFILE* sf, uint32_t off
ktsr->stream_sizes[0] = read_u32le(offset + 0x38, sf); ktsr->stream_sizes[0] = read_u32le(offset + 0x38, sf);
} }
ktsr->is_external = true; ktsr->is_external = true;
VGM_LOG("k=%x\n", ktsr->codec_value);
break; break;
case 0x41FDBD4E: /* internal [Attack on Titan: Wings of Freedom (Vita)] */ case 0x41FDBD4E: /* internal [Attack on Titan: Wings of Freedom (Vita)] */

View file

@ -8,7 +8,7 @@ VGMSTREAM* init_vgmstream_lp_ap_lep(STREAMFILE* sf) {
STREAMFILE* temp_sf = NULL; STREAMFILE* temp_sf = NULL;
off_t start_offset; off_t start_offset;
int loop_flag, channels, sample_rate, interleave; int loop_flag, channels, sample_rate, interleave;
int32_t data_size, loop_start; uint32_t data_size, loop_start, loop_end;
uint32_t id; uint32_t id;
@ -25,23 +25,47 @@ VGMSTREAM* init_vgmstream_lp_ap_lep(STREAMFILE* sf) {
switch (id) { switch (id) {
case 0x41502020: /* "AP " */ case 0x41502020: /* "AP " */
case 0x4C502020: /* "LP " */ case 0x4C502020: /* "LP " */
data_size = read_u32le(0x04,sf); // end offset after header
sample_rate = read_u32le(0x08,sf); sample_rate = read_u32le(0x08,sf);
interleave = read_u32le(0x0c,sf); interleave = read_u32le(0x0c,sf);
loop_start = read_u32le(0x14,sf); // 10: pan/volume?
data_size = read_u32le(0x18,sf); loop_start = read_u32le(0x14,sf); // absolute
start_offset = read_u32le(0x1C,sf); loop_end = read_u32le(0x18,sf); // end offset after header
start_offset= read_u32le(0x1C,sf); // after header
// tweak values considering (applies to both PS-ADPCM and PCM):
// - start_offset with PCM starts 0x20 before data, so must be after header (not a blank frame)
// - end offset after 0x20 usually ends when padding (0xFF) starts
// - loop end is usually the same except in PCM
// - loop start is always aligned to 0x800 (meaning no loop/0 uses 0x800 w/ start offset 0x7E0 + 0x20)
// * in PS-ADPCM start after header points to a regular frame, a bit odd since PS-ADPCM should start with blank frames
// but correct as LEP starts at 0x800 without them
start_offset += 0x20;
data_size += 0x20;
loop_end += 0x20;
data_size -= start_offset;
loop_end -= start_offset;
loop_start -= start_offset;
break; break;
case 0x4C455020: /* "LEP " */ case 0x4C455020: /* "LEP " (memory data?) */
data_size = read_u32le(0x08,sf); // 04: config?
data_size = read_u32le(0x08,sf); // within stream
// 10: pan/volume?
sample_rate = read_u16le(0x12,sf); sample_rate = read_u16le(0x12,sf);
loop_start = read_u32le(0x58,sf); loop_start = read_u32le(0x58,sf); // within stream?
// 5c: loop start?
// 60+: related to loop?
// not sure if loops are absolute, but since values are not 0x800-aligned like AP/LP assuming it's not
loop_end = data_size;
interleave = 0x10; interleave = 0x10;
start_offset = 0x800; start_offset = 0x800;
break; break;
default: default:
goto fail; return NULL;
} }
loop_flag = loop_start != 0; loop_flag = loop_start != 0;
@ -61,9 +85,9 @@ VGMSTREAM* init_vgmstream_lp_ap_lep(STREAMFILE* sf) {
vgmstream->layout_type = layout_interleave; vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave; vgmstream->interleave_block_size = interleave;
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channels, 16); vgmstream->num_samples = pcm16_bytes_to_samples(data_size, channels);
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, channels, 16); vgmstream->loop_start_sample = pcm16_bytes_to_samples(loop_start, channels);
vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->loop_end_sample = pcm16_bytes_to_samples(loop_end, channels);
temp_sf = setup_lp_streamfile(sf, start_offset); /* encrypted/obfuscated PCM */ temp_sf = setup_lp_streamfile(sf, start_offset); /* encrypted/obfuscated PCM */
if (!temp_sf) goto fail; if (!temp_sf) goto fail;
@ -77,7 +101,7 @@ VGMSTREAM* init_vgmstream_lp_ap_lep(STREAMFILE* sf) {
vgmstream->num_samples = ps_bytes_to_samples(data_size, channels); vgmstream->num_samples = ps_bytes_to_samples(data_size, channels);
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channels); vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channels);
vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, channels);
break; break;
default: default:

View file

@ -2,8 +2,8 @@
#include "../util.h" #include "../util.h"
#include "../coding/coding.h" #include "../coding/coding.h"
/* .GCM - from PS2 Namco games [Gunvari Collection + Time Crisis (PS2), NamCollection (PS2)] */ /* MCG - from PS2 Namco games [Gunvari Collection + Time Crisis (PS2), NamCollection (PS2)] */
VGMSTREAM* init_vgmstream_ps2_gcm(STREAMFILE* sf) { VGMSTREAM* init_vgmstream_mcg(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
uint32_t start_offset, name_offset; uint32_t start_offset, name_offset;
uint32_t vagp_l_offset, vagp_r_offset, track_size, data_size, channel_size; uint32_t vagp_l_offset, vagp_r_offset, track_size, data_size, channel_size;
@ -12,11 +12,10 @@ VGMSTREAM* init_vgmstream_ps2_gcm(STREAMFILE* sf) {
/* checks */ /* checks */
if (!is_id32be(0x00,sf, "MCG\0")) if (!is_id32be(0x00,sf, "MCG\0"))
goto fail; return NULL;
// .gcm: actual extension
/* .gcm: actual extension */
if (!check_extensions(sf, "gcm")) if (!check_extensions(sf, "gcm"))
goto fail; return NULL;
/* format is two v4 "VAGp" headers then interleaved data (even for 6ch files) */ /* format is two v4 "VAGp" headers then interleaved data (even for 6ch files) */
@ -59,7 +58,7 @@ VGMSTREAM* init_vgmstream_ps2_gcm(STREAMFILE* sf) {
vgmstream = allocate_vgmstream(channels, 0); vgmstream = allocate_vgmstream(channels, 0);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->meta_type = meta_PS2_GCM; vgmstream->meta_type = meta_MCG;
vgmstream->sample_rate = sample_rate; vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = ps_bytes_to_samples(channel_size, 1); vgmstream->num_samples = ps_bytes_to_samples(channel_size, 1);
vgmstream->coding_type = coding_PSX; vgmstream->coding_type = coding_PSX;

View file

@ -366,8 +366,6 @@ VGMSTREAM* init_vgmstream_smss(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ads_midway(STREAMFILE* sf); VGMSTREAM* init_vgmstream_ads_midway(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ps2_mcg(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_zsd(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_zsd(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_vgs_ps(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_vgs_ps(STREAMFILE *streamFile);
@ -431,7 +429,7 @@ VGMSTREAM* init_vgmstream_wb(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_raw_s14_sss(STREAMFILE* sf); VGMSTREAM* init_vgmstream_raw_s14_sss(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ps2_gcm(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_mcg(STREAMFILE* streamFile);
VGMSTREAM* init_vgmstream_smpl(STREAMFILE* sf); VGMSTREAM* init_vgmstream_smpl(STREAMFILE* sf);
@ -490,8 +488,6 @@ VGMSTREAM * init_vgmstream_xwav_old(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_raw_snds(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_raw_snds(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_wmus(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_hyperscan_kvag(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_hyperscan_kvag(STREAMFILE* streamFile);
VGMSTREAM* init_vgmstream_psnd(STREAMFILE* sf); VGMSTREAM* init_vgmstream_psnd(STREAMFILE* sf);
@ -1032,4 +1028,10 @@ VGMSTREAM* init_vgmstream_shaa(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_undefind(STREAMFILE* sf); VGMSTREAM* init_vgmstream_undefind(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_oor(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_mio(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_2dx(STREAMFILE* sf);
#endif #endif

View file

@ -0,0 +1,57 @@
#include "meta.h"
#include "../coding/coding.h"
/* .MIO - Entis's 'Music Interleaved and Orthogonal transformed' [HAYABUSA (PC), Rakuen no Kantai (PC/Android)] */
VGMSTREAM* init_vgmstream_mio(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
uint32_t start_offset;
/* checks */
if (!is_id64be(0x00,sf, "Entis\x1a\x00\x00"))
return NULL;
// all of Entis's formats have long text descriptors, will be re-checked during codec init
if (!is_id64be(0x10,sf, "Music In"))
return NULL;
if (!check_extensions(sf,"mio"))
return NULL;
// get info (abridged), could use lib though
int channels = read_s32le(0x90,sf);
int sample_rate = 44100; // there is input rate at 0x94 put output is fixed
int32_t num_samples = read_s32le(0xA0,sf);
// loops are in UTF16 tags, kinda annoying to read so get from lib below
int32_t loop_start = 0;
bool loop_flag = 1; //(loop_start > 0);
start_offset = 0x00;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_MIO;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
// .mio has multiple modes (lapped/huffman/lossless) but not that interesting to print as info
vgmstream->codec_data = init_mio(sf, &loop_start);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_MIO;
vgmstream->layout_type = layout_none;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = num_samples;
vgmstream->loop_flag = (loop_start >= 0);
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1446,7 +1446,7 @@ VGMSTREAM* init_vgmstream_dsp_wiivoice(STREAMFILE* sf) {
} }
/* WIIADPCM - Exient wrapper [Need for Speed: Hot Pursuit (Wii), Angry Birds: Star Wars (WiiU)] */ /* WIIADPCM - Exient wrapper [Need for Speed: Hot Pursuit (Wii), Angry Birds: Star Wars (Wii/WiiU)] */
VGMSTREAM* init_vgmstream_dsp_wiiadpcm(STREAMFILE* sf) { VGMSTREAM* init_vgmstream_dsp_wiiadpcm(STREAMFILE* sf) {
dsp_meta dspm = {0}; dsp_meta dspm = {0};
@ -1456,18 +1456,33 @@ VGMSTREAM* init_vgmstream_dsp_wiiadpcm(STREAMFILE* sf) {
if (!check_extensions(sf, "adpcm")) if (!check_extensions(sf, "adpcm"))
return NULL; return NULL;
dspm.interleave = read_u32be(0x08,sf); /* interleave offset */ // no good flag so use v2's loop+type as other values are easy to mistake
/* 0x0c: NFS = 0 when RAM (2 DSP headers), interleave size when stream (2 WIIADPCM headers) int test = read_u32be(0x2c,sf);
* AB = 0 (2 WIIADPCM headers) */ if (!(test == 0x00010000 || test == 0x00000000)) {
// V1 (NFSHP)
dspm.channels = (dspm.interleave ? 2 : 1); // 08: ch2 offset
// 0c: real interleave in streams (xN WIIADPCM headers), null in memory audio (xN DSP headers)
dspm.header_offset = 0x10;
dspm.max_channels = 2; dspm.max_channels = 2;
}
else {
// V2 (ABSW)
// 08-18: chN offset
// 1c: real interleave in streams (xN WIIADPCM headers), null in memory audio (xN DSP headers)
// (interleave may be set in mono too)
dspm.header_offset = 0x20;
dspm.max_channels = 6;
}
if (read_u32be(0x10,sf) != 0) dspm.channels = 1;
dspm.header_offset = 0x10; /* NFSHP */ for (int i = 0; i < dspm.max_channels - 1; i++) {
else uint32_t offset = read_u32be(0x08 + i * 0x04, sf);
dspm.header_offset = 0x20; /* ABSW */ if (!offset)
break;
dspm.channels += 1;
}
dspm.interleave = read_u32be(0x08,sf); // use first channel offset as interleave
if (dspm.interleave) if (dspm.interleave)
dspm.interleave -= dspm.header_offset; dspm.interleave -= dspm.header_offset;
dspm.interleave_first_skip = 0x60 + dspm.header_offset; dspm.interleave_first_skip = 0x60 + dspm.header_offset;
@ -1476,7 +1491,6 @@ VGMSTREAM* init_vgmstream_dsp_wiiadpcm(STREAMFILE* sf) {
dspm.header_spacing = dspm.interleave; dspm.header_spacing = dspm.interleave;
dspm.start_offset = dspm.header_offset + 0x60; dspm.start_offset = dspm.header_offset + 0x60;
dspm.meta_type = meta_DSP_WIIADPCM; dspm.meta_type = meta_DSP_WIIADPCM;
return init_vgmstream_dsp_common(sf, &dspm); return init_vgmstream_dsp_common(sf, &dspm);
} }

View file

@ -0,0 +1,100 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
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;
/* checks */
if (read_u8(0x00, sf) != 0x08 && read_u32be(0x00, sf) != 0x48000000) //v0 and v1 first page headers
return NULL;
if (!check_extensions(sf, "oor"))
return NULL;
// bitpacked header, should fail during on init with bad data but do minor validations to skip some allocs
if (!is_oor(sf))
return NULL;
#ifdef VGM_USE_VORBIS
vorbis_custom_config cfg = {0}; //loads info on success
data = init_vorbis_custom(sf, 0x00, VORBIS_OOR, &cfg);
if (!data) return NULL;
start_offset = cfg.data_start_offset;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(cfg.channels, 0);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_OOR;
vgmstream->sample_rate = cfg.sample_rate;
vgmstream->num_samples = cfg.last_granule;
vgmstream->layout_type = layout_none;
vgmstream->coding_type = coding_VORBIS_custom;
vgmstream->codec_data = data;
data = NULL;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
//TODO: improve
// 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;
}
// OOR is bitpacked but try to determine if bytes look like a .oor (will fail later if we picked a wrong candidate).
static bool is_oor(STREAMFILE* sf) {
static uint8_t empty_granule[0x09];
uint8_t data[0x10] = {0};
read_streamfile(data, 0x00, sizeof(data), sf);
int page_version;
int head_pos;
if (data[0x00] == 0x48 && memcmp(data + 0x01, empty_granule, 9) == 0) {
// V1: bits 01 0010 00 + granule + header
head_pos = 0x0A;
page_version = 1;
}
else if (data[0x00] == 0x08) {
// V0: bits 00 0010 00 + header
head_pos = 0x01;
page_version = 0;
}
else {
return false;
}
uint16_t head = (data[head_pos] << 8) | data[head_pos+1];
int version = (head >> 14) & 0x03; //2b
int channels = (head >> 11) & 0x07; //3b
int sr_selector = (head >> 9) & 0x03; //3b
int srate = (head >> 1) & 0xFF; //3b
if (version != page_version || channels == 0)
return false;
if (sr_selector == 3 && srate > 10)
return false;
return true;
}

View file

@ -1,67 +0,0 @@
#include "meta.h"
#include "../util.h"
/* GUN (Gunvari Streams) */
VGMSTREAM * init_vgmstream_ps2_mcg(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("mcg",filename_extension(filename))) goto fail;
/* check header */
if (!((read_32bitBE(0x00,streamFile) == 0x4D434700) &&
(read_32bitBE(0x20,streamFile) == 0x56414770) &&
(read_32bitBE(0x50,streamFile) == 0x56414770)))
goto fail;
loop_flag = (read_32bitLE(0x34,streamFile)!=0);
channel_count = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x80;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x30,streamFile);
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = read_32bitBE(0x2C,streamFile)/16*14*channel_count;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile);
vgmstream->meta_type = meta_PS2_MCG;
if (vgmstream->loop_flag)
{
vgmstream->loop_start_sample = read_32bitLE(0x34,streamFile);
vgmstream->loop_end_sample = vgmstream->num_samples;
}
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1,62 +0,0 @@
#include "meta.h"
#include "../coding/coding.h"
/* VA3 - Konami / Sony Atrac3 Container [PS2 DDR Supernova 2 Arcade] */
VGMSTREAM * init_vgmstream_va3(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
uint32_t data_size;
/* check extension, case insensitive */
if (!check_extensions(streamFile, "va3"))
goto fail;
if (read_32bitBE(0x00, streamFile) != 0x21334156) /* "!3AV" */
goto fail;
/* va3 header */
start_offset = 0x800;
data_size = read_32bitLE(0x04, streamFile);// get_streamfile_size(streamFile) - start_offset;
// pretty sure 0x4 LE 32 bit is some sort of filesize...
loop_flag = 0;
//0x18 is 1... what is this?
channel_count = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VA3;
vgmstream->sample_rate = read_32bitLE(0x14, streamFile);
vgmstream->num_samples = read_32bitLE(0x08, streamFile);
vgmstream->channels = channel_count;
#ifdef VGM_USE_FFMPEG
{
int block_align, encoder_delay;
block_align = 0xC0 * vgmstream->channels;
encoder_delay = 0; //todo
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamFile, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
}
#else
goto fail;
#endif
/* open the file for reading */
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1,102 +0,0 @@
#include "meta.h"
#include "../util.h"
//#include <windows.h>
//#include <tchar.h>
/* WMUS - Arbitrary extension chosen for The Warriors (PS2) */
VGMSTREAM * init_vgmstream_ps2_wmus(STREAMFILE *streamFile)
{
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
int loop_flag = 1;
int channel_count;
off_t start_offset;
int i;
int blockCount;
int shortBlockSize;
int lastBlockLocation;
char filenameWHED[PATH_LIMIT];
STREAMFILE * streamFileWHED = NULL;
//_TCHAR szBuffer[100];
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("wmus",filename_extension(filename)))
{
goto fail;
}
/* check for .WHED file */
strcpy(filenameWHED, filename);
strcpy(filenameWHED + strlen(filenameWHED) - 4, "WHED");
streamFileWHED = streamFile->open(streamFile, filenameWHED, STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!streamFileWHED)
{
goto fail;
}
/* check loopand channel */
loop_flag = 1;
channel_count = read_32bitLE(0x14, streamFileWHED);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream)
{
goto fail;
}
/* fill in the vital statistics */
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x04, streamFileWHED);
vgmstream->coding_type = coding_PSX;
vgmstream->interleave_block_size = read_32bitLE(0x18, streamFileWHED);
blockCount = read_32bitLE(0x1C, streamFileWHED) * channel_count;
shortBlockSize = read_32bitLE(0x20, streamFileWHED);
vgmstream->num_samples = (vgmstream->interleave_block_size * blockCount) / 16 / channel_count * 28;
vgmstream->loop_start_sample = 0;
lastBlockLocation = (vgmstream->interleave_block_size * blockCount) - (vgmstream->interleave_block_size - shortBlockSize);
vgmstream->loop_end_sample = lastBlockLocation / 16 / channel_count * 28;
//_stprintf(szBuffer, _T("%x"), lastBlockLocation);
//MessageBox(NULL, szBuffer, _T("Foo"), MB_OK);
vgmstream->layout_type = layout_interleave;
vgmstream->meta_type = meta_PS2_WMUS;
start_offset = 0;
/* open the file for reading by each channel */
{
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[i].streamfile) goto fail;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=
(off_t)(start_offset+vgmstream->interleave_block_size*i);
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (streamFileWHED) close_streamfile(streamFileWHED);
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View file

@ -4,65 +4,62 @@
/* tri-Ace codec file [Star Ocean 3 (PS2), Valkyrie Profile 2 (PS2), Radiata Stories (PS2)] */ /* tri-Ace codec file [Star Ocean 3 (PS2), Valkyrie Profile 2 (PS2), Radiata Stories (PS2)] */
VGMSTREAM* init_vgmstream_tac(STREAMFILE* sf) { VGMSTREAM* init_vgmstream_tac(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
int loop_flag, channel_count; int loop_flag, channels;
uint16_t loop_frame, frame_count, loop_discard, frame_last;
uint32_t info_offset, loop_offset, stream_size, file_size;
off_t start_offset; off_t start_offset;
/* checks */ /* checks */
// file is validated on decoder init, catch simple errors (see tac_decoder_lib.h for full header)
uint32_t info_offset = read_u32le(0x00,sf);
if (info_offset < 0x20 || info_offset > 0x4E000) /* offset points to value inside first "block" */
return NULL;
/* (extensionless): bigfiles have no known names (libs calls mention "St*" and "Sac*" though) /* (extensionless): bigfiles have no known names (libs calls mention "St*" and "Sac*" though)
* .aac: fake for convenience given it's a tri-Ace AAC's grandpa (but don't use unless you must) * .aac: fake for convenience given it's a tri-Ace AAC's grandpa (but don't use unless you must)
* .pk3/.20: extremely ugly fake extensions randomly given by an old extractor, *DON'T* */ * .pk3/.20: extremely ugly fake extensions randomly given by an old extractor, *DON'T* */
if (!check_extensions(sf, ",aac,laac")) if (!check_extensions(sf, ",aac,laac"))
goto fail; return NULL;
/* file is validated on decoder init, early catch of simple errors (see tac_decoder_lib.h for full header) */
info_offset = read_u32le(0x00,sf); uint16_t loop_frame = read_u16le(0x08,sf);
if (info_offset > 0x4E000 || info_offset < 0x20) /* offset points to value inside first "block" */ uint16_t loop_discard = read_u16le(0x0a,sf);
goto fail; uint16_t frame_count = read_u16le(0x0c,sf);
loop_frame = read_u16le(0x08,sf); uint16_t frame_last = read_u16le(0x0e,sf);
loop_discard = read_u16le(0x0a,sf); uint32_t loop_offset = read_u32le(0x10,sf);
frame_count = read_u16le(0x0c,sf); uint32_t stream_size = read_u32le(0x14,sf);
frame_last = read_u16le(0x0e,sf);
loop_offset = read_u32le(0x10,sf);
stream_size = read_u32le(0x14,sf);
if (stream_size % 0x4E000 != 0) /* multiple of blocks */ if (stream_size % 0x4E000 != 0) /* multiple of blocks */
goto fail; return NULL;
/* actual file can truncate last block */ /* actual file can truncate last block */
file_size = get_streamfile_size(sf); uint32_t file_size = get_streamfile_size(sf);
if (file_size > stream_size || file_size < stream_size - 0x4E000) if (file_size > stream_size || file_size < stream_size - 0x4E000)
goto fail; return NULL;
channel_count = 2; /* always stereo */ channels = 2; // always stereo
loop_flag = (loop_offset != stream_size); /* actual check may be loop_frame > 0? */ loop_flag = (loop_offset != stream_size); // actual check may be loop_frame > 0?
start_offset = 0; start_offset = 0; // handled internally
/* build the VGMSTREAM */ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag); vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->meta_type = meta_TAC; vgmstream->meta_type = meta_TAC;
vgmstream->sample_rate = 48000; vgmstream->sample_rate = 48000;
/* Frame at count/loop outputs less than full 1024 samples (thus loop or count-1 + extra). // Frame at count/loop outputs less than full 1024 samples (thus loop or count-1 + extra).
* A few files may pop when looping, but this seems to match game/emulator. */ // A few files may pop when looping, but this seems to match game/emulator.
vgmstream->num_samples = (frame_count - 1) * 1024 + (frame_last + 1); vgmstream->num_samples = (frame_count - 1) * 1024 + (frame_last + 1);
vgmstream->loop_start_sample = (loop_frame - 1) * 1024 + loop_discard; vgmstream->loop_start_sample = (loop_frame - 1) * 1024 + loop_discard;
vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->loop_end_sample = vgmstream->num_samples;
{
vgmstream->codec_data = init_tac(sf); vgmstream->codec_data = init_tac(sf);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_TAC; vgmstream->coding_type = coding_TAC;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
}
if (!vgmstream_open_stream(vgmstream, sf, start_offset)) if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail; goto fail;
return vgmstream; return vgmstream;
fail: fail:
close_vgmstream(vgmstream); close_vgmstream(vgmstream);
return NULL; return NULL;

View file

@ -78,6 +78,11 @@ void txtp_copy_config(play_config_t* dst, play_config_t* src) {
if (!src->config_set) if (!src->config_set)
return; return;
// "no loops" (intro only) and "ignore fade" can't work due to how decoding works, must use @body-* macros
if (src->loop_count_set && src->loop_count == 0 && src->ignore_fade) {
src->ignore_fade = false;
}
dst->config_set = 1; dst->config_set = 1;
copy_flag(&dst->play_forever, &src->play_forever); copy_flag(&dst->play_forever, &src->play_forever);
copy_flag(&dst->ignore_fade, &src->ignore_fade); copy_flag(&dst->ignore_fade, &src->ignore_fade);
@ -94,22 +99,6 @@ void txtp_copy_config(play_config_t* dst, play_config_t* src) {
copy_time(&dst->body_time_set, &dst->body_time, &dst->body_time_s, &src->body_time_set, &src->body_time, &src->body_time_s); copy_time(&dst->body_time_set, &dst->body_time, &dst->body_time_s, &src->body_time_set, &src->body_time, &src->body_time_s);
} }
#if 0
static void init_config(VGMSTREAM* vgmstream) {
play_config_t* cfg = &vgmstream->config;
//todo only on segmented/layered?
if (cfg->play_forever
cfg->loop_count_set || cfg->fade_time_set || cfg->fade_delay_set ||
cfg->pad_begin_set || cfg->pad_end_set || cfg->trim_begin_set || cfg->trim_end_set ||
cfg->body_time_set) {
VGM_LOG("setup!\n");
}
}
#endif
void txtp_add_mixing(txtp_entry_t* entry, txtp_mix_data_t* mix, txtp_mix_t command) { void txtp_add_mixing(txtp_entry_t* entry, txtp_mix_data_t* mix, txtp_mix_t command) {
if (entry->mixing_count + 1 > TXTP_MIXING_MAX) { if (entry->mixing_count + 1 > TXTP_MIXING_MAX) {
VGM_LOG("TXTP: too many mixes\n"); VGM_LOG("TXTP: too many mixes\n");

View file

@ -21,6 +21,11 @@
#define TXTP_GROUP_REPEAT 'R' #define TXTP_GROUP_REPEAT 'R'
#define TXTP_POSITION_LOOPS 'L' #define TXTP_POSITION_LOOPS 'L'
#define TXTP_BODY_INTRO 1
#define TXTP_BODY_MAIN 2
#define TXTP_BODY_OUTRO 3
/* mixing info */ /* mixing info */
typedef enum { typedef enum {
MIX_SWAP, MIX_SWAP,
@ -104,6 +109,8 @@ typedef struct {
double trim_second; double trim_second;
int32_t trim_sample; int32_t trim_sample;
int body_mode;
} txtp_entry_t; } txtp_entry_t;

View file

@ -384,6 +384,8 @@ static void add_settings(txtp_entry_t* current, txtp_entry_t* entry, const char*
current->loop_anchor_start = entry->loop_anchor_start; current->loop_anchor_start = entry->loop_anchor_start;
current->loop_anchor_end = entry->loop_anchor_end; current->loop_anchor_end = entry->loop_anchor_end;
current->body_mode = entry->body_mode;
} }
//TODO use //TODO use
@ -708,6 +710,16 @@ static void parse_params(txtp_entry_t* entry, char* params) {
txtp_add_mixing(entry, &mix, MACRO_DOWNMIX); txtp_add_mixing(entry, &mix, MACRO_DOWNMIX);
} }
else if (strcmp(command,"@body-intro") == 0) {
entry->body_mode = TXTP_BODY_INTRO;
VGM_LOG("body: %x\n", entry->body_mode);
}
else if (strcmp(command,"@body-main") == 0) {
entry->body_mode = TXTP_BODY_MAIN;
}
else if (strcmp(command,"@body-outro") == 0) {
entry->body_mode = TXTP_BODY_OUTRO;
}
else if (params[nc] == ' ') { else if (params[nc] == ' ') {
//;VGM_LOG("TXTP: comment\n"); //;VGM_LOG("TXTP: comment\n");
break; /* comment, ignore rest */ break; /* comment, ignore rest */
@ -1019,7 +1031,9 @@ static int parse_keyval(txtp_header_t* txtp, const char* key, const char* val) {
} }
else { else {
goto fail; // in rare cases a filename may contain a (blah=blah.blah), but it's hard to distinguish
// from key=val + setting with dots. Signal unknown command to treat it like a file (should fail later).
return -1;
} }
return 1; return 1;
@ -1066,9 +1080,11 @@ txtp_header_t* txtp_parse(STREAMFILE* sf) {
/* try key/val (ignores lead/trail spaces, # may be commands or comments) */ /* try key/val (ignores lead/trail spaces, # may be commands or comments) */
ok = sscanf(line, " %[^ \t#=] = %[^\t\r\n] ", key,val); ok = sscanf(line, " %[^ \t#=] = %[^\t\r\n] ", key,val);
if (ok == 2) { /* key=val */ if (ok == 2) { /* key=val */
if (!parse_keyval(txtp, key, val)) /* read key/val */ int ret = parse_keyval(txtp, key, val); /* read key/val */
goto fail; if (ret == 0) goto fail;
if (ret > 0)
continue; continue;
// ret < 0: try to handle as filename below
} }
/* must be a filename (only remove spaces from start/end, as filenames con contain mid spaces/#/etc) */ /* must be a filename (only remove spaces from start/end, as filenames con contain mid spaces/#/etc) */

View file

@ -13,6 +13,51 @@
/*******************************************************************************/ /*******************************************************************************/
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;
entry->config.fade_time_set = false;
entry->config.fade_delay_set = false;
entry->config.ignore_fade = false;
entry->config.ignore_loop = true;
switch(entry->body_mode) {
case TXTP_BODY_INTRO:
if (vgmstream->loop_start_sample == 0)
return;
entry->trim_set = true;
entry->trim_sample = vgmstream->loop_start_sample;
entry->config.config_set = true;
break;
case TXTP_BODY_MAIN:
entry->config.trim_begin_set = true;
entry->config.trim_begin = vgmstream->loop_start_sample;
entry->trim_set = true;
entry->trim_sample = vgmstream->loop_end_sample;
entry->config.config_set = true;
break;
case TXTP_BODY_OUTRO:
if (vgmstream->loop_end_sample >= vgmstream->num_samples)
return;
entry->config.trim_begin_set = true;
entry->config.trim_begin = vgmstream->loop_end_sample;
entry->config.config_set = true;
break;
default:
break;
}
}
static void apply_settings(VGMSTREAM* vgmstream, txtp_entry_t* current) { static void apply_settings(VGMSTREAM* vgmstream, txtp_entry_t* current) {
/* base settings */ /* base settings */
@ -36,6 +81,8 @@ static void apply_settings(VGMSTREAM* vgmstream, txtp_entry_t* current) {
vgmstream_force_loop(vgmstream, current->loop_install_set, current->loop_start_sample, current->loop_end_sample); vgmstream_force_loop(vgmstream, current->loop_install_set, current->loop_start_sample, current->loop_end_sample);
} }
apply_settings_body(vgmstream, current);
if (current->trim_set) { if (current->trim_set) {
if (current->trim_second != 0.0) { if (current->trim_second != 0.0) {
/* trim sample can become 0 here when second is too small (rounded) */ /* trim sample can become 0 here when second is too small (rounded) */

View file

@ -1011,7 +1011,11 @@ static VGMSTREAM* init_vgmstream_ubi_sb_base(ubi_sb_header* sb, STREAMFILE* sf_h
vgmstream->layout_type = layout_interleave; vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02; vgmstream->interleave_block_size = 0x02;
if (vgmstream->num_samples == 0) { /* happens in .bnm */ // in .bnm samples may be null, or PCM size (similar to Ubi-MPEG)
if (sb->is_bnm)
vgmstream->num_samples = 0;
if (vgmstream->num_samples == 0) {
vgmstream->num_samples = pcm_bytes_to_samples(sb->stream_size, sb->channels, 16); vgmstream->num_samples = pcm_bytes_to_samples(sb->stream_size, sb->channels, 16);
vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->loop_end_sample = vgmstream->num_samples;
} }
@ -1221,14 +1225,44 @@ static VGMSTREAM* init_vgmstream_ubi_sb_base(ubi_sb_header* sb, STREAMFILE* sf_h
} }
break; break;
case FMT_MPDX: case FMT_MPDX: {
/* a custom, chunked MPEG format (sigh) /* custom MPEG (.MPD, .MPU. MPX, internal, etc):
* 0x00: samples? (related to size) * 0x00: samples
* 0x04: "2RUS" (apparently "1RUS" for mono files) * 0x04: optional ID for 'surround' config ("2RUS" or "1RUS" or none)
* Rest is a MPEG-like sync but not an actual MPEG header? (DLLs do refer it as MPEG) * Data is custom-ish MP2 packets with odd surround modes
* Files may have multiple "2RUS" or just a big one * - .MPX have multiple small streams pasted together (subsongs in .bnm point to each)
* A companion .csb has some not-too-useful info */ * - .MPD has 1 big-ish stream
* A companion .csb has sequence info (maybe before compiled to .bnm)
*/
int32_t block_samples = read_s32le(start_offset + 0x00, sf_data);
uint32_t mode = read_u32be(start_offset + 0x04, sf_data);
start_offset += 0x04;
if ((mode & 0x00FFFFFF) == get_id32be("\0RUS"))
start_offset += 0x04;
// for some reason num_samples is either size of PCM or 0
if (sb->num_samples && block_samples * sizeof(short) * sb->channels != sb->num_samples) {
VGM_LOG("UBI SB: wrong MPEG block samples found block=%i vs total=%i\n", block_samples, sb->num_samples);
goto fail; goto fail;
}
//TODO: needed for smoother segments, but not sure if block samples counts this
// (usually blocks' frames have more samples than defined but not always; maybe should output delay's samples at EOF)
int encoder_delay = 480; //observed
vgmstream->num_samples = block_samples - encoder_delay;
vgmstream->loop_end_sample = block_samples - encoder_delay;
if (sb->loop_start) {
vgmstream->loop_start_sample = sb->loop_start / sizeof(short) / sb->channels;
}
vgmstream->codec_data = init_ubimpeg(mode);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_UBI_MPEG;
vgmstream->layout_type = layout_none;
break;
}
default: default:
VGM_LOG("UBI SB: unknown codec\n"); VGM_LOG("UBI SB: unknown codec\n");
@ -1236,7 +1270,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_base(ubi_sb_header* sb, STREAMFILE* sf_h
} }
/* open the actual for decoding (sf_data can be an internal or external stream) */ /* open the actual for decoding (sf_data can be an internal or external stream) */
if ( !vgmstream_open_stream(vgmstream, sf_data, start_offset) ) if (!vgmstream_open_stream(vgmstream, sf_data, start_offset))
goto fail; goto fail;
return vgmstream; return vgmstream;
@ -3071,10 +3105,10 @@ static int config_sb_version(ubi_sb_header* sb, STREAMFILE* sf) {
sb->version = 0x00000000; sb->version = 0x00000000;
} }
/* Tonic Touble beta has garbage instead of version */ /* Tonic Touble Special Edition has garbage instead of version */
if (sb->is_bnm && sb->version > 0x00000000 && sb->platform == UBI_PC) { if (sb->is_bnm && sb->version > 0x00000000 && sb->platform == UBI_PC) {
if (check_project_file(sf, "ED_MAIN.LCB", 0)) { if (check_project_file(sf, "ED_MAIN.LCB", 0) || check_project_file(sf, "../ED_MAIN.LCB", 0)) {
is_ttse_pc = 1; is_ttse_pc = true;
sb->version = 0x00000000; sb->version = 0x00000000;
} }
} }

View file

@ -0,0 +1,59 @@
#include "meta.h"
#include "../coding/coding.h"
/* VA3 - from Konami games [Dance Dance Revolution Supernova 2 (Arcade)] */
VGMSTREAM* init_vgmstream_va3(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channels;
uint32_t data_size;
/* checks */
if (!is_id32be(0x00, sf, "!3AV"))
return NULL;
// .va3: actual extension
if (!check_extensions(sf, "va3"))
return NULL;
start_offset = 0x800;
data_size = read_u32le(0x04, sf);
loop_flag = 0;
channels = 2;
//0c: null (loops?)
//10: null (loops?)
//18: flag? (always 1)
//1c: always 0x0200 (channels?)
//20: always 100 (volume?)
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VA3;
vgmstream->num_samples = read_s32le(0x08, sf);
vgmstream->sample_rate = read_s32le(0x14, sf);
#ifdef VGM_USE_FFMPEG
{
int block_align = 0xC0 * vgmstream->channels;
int encoder_delay = 0; //TODO
vgmstream->codec_data = init_ffmpeg_atrac3_raw(sf, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
}
#else
goto fail;
#endif
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -28,8 +28,9 @@ VGMSTREAM* init_vgmstream_vag(STREAMFILE* sf) {
* .snd: Alien Breed (Vita) * .snd: Alien Breed (Vita)
* .svg: ModernGroove: Ministry of Sound Edition (PS2) * .svg: ModernGroove: Ministry of Sound Edition (PS2)
* (extensionless): The Urbz (PS2), The Sims series (PS2) * (extensionless): The Urbz (PS2), The Sims series (PS2)
* .wav: Sniper Elite (PS2), The Simpsons Game (PS2/PSP) */ * .wav: Sniper Elite (PS2), The Simpsons Game (PS2/PSP)
if (!check_extensions(sf,"vag,swag,str,vig,l,r,vas,xa2,snd,svg,,wav,lwav")) * .msv: Casper and the Ghostly Trio (PS2), Earache Extreme Metal Racing (PS2) */
if (!check_extensions(sf,"vag,swag,str,vig,l,r,vas,xa2,snd,svg,,wav,lwav,msv"))
return NULL; return NULL;
file_size = get_streamfile_size(sf); file_size = get_streamfile_size(sf);

View file

@ -226,8 +226,6 @@ VGMSTREAM* init_vgmstream_vas_kceo_container(STREAMFILE* sf) {
} }
} }
else if (read_u32le(0x00, sf) == 0x800) { /* Xbox/PC (start?) */ else if (read_u32le(0x00, sf) == 0x800) { /* Xbox/PC (start?) */
VGM_STEP();
total_subsongs = read_s32le(0x04, sf); total_subsongs = read_s32le(0x04, sf);
if (target_subsong == 0) target_subsong = 1; if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;

View file

@ -13,7 +13,7 @@ VGMSTREAM* init_vgmstream_vig_kces(STREAMFILE* sf) {
/* checks */ /* checks */
if (read_u32be(0x00,sf) != 0x01006408) if (read_u32be(0x00,sf) != 0x01006408)
return NULL; return NULL;
/* .vig: actual extension from DDR exes */ /* .vig: actual extension from AC versions + PS2 exes */
if (!check_extensions(sf, "vig")) if (!check_extensions(sf, "vig"))
return NULL; return NULL;

View file

@ -4,27 +4,27 @@
#include "xavs_streamfile.h" #include "xavs_streamfile.h"
/* XAVS - Reflections audio and video+audio container [Stuntman (PS2)] */ /* XAVS - Reflections audio and video+audio container [Stuntman (PS2)] */
VGMSTREAM * init_vgmstream_xavs(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_xavs(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
off_t start_offset; off_t start_offset;
int loop_flag, channel_count; int loop_flag, channels;
int total_subsongs, target_subsong = streamFile->stream_index; int total_subsongs, target_subsong = sf->stream_index;
STREAMFILE *temp_streamFile = NULL;
/* checks */ /* checks */
if (!check_extensions(streamFile, "xav")) if (!is_id32be(0x00, sf, "XAVS"))
goto fail; return NULL;
if (read_32bitBE(0x00, streamFile) != 0x58415653) /* "XAVS" */ if (!check_extensions(sf, "xav"))
goto fail; return NULL;
loop_flag = 0; loop_flag = 0;
channel_count = 2; channels = 2;
start_offset = 0x00; start_offset = 0x00;
/* 0x04: 16b width + height (0 if file has no video) */ /* 0x04: 16b width + height (0 if file has no video) */
/* 0x08: related to video (0 if file has no video) */ /* 0x08: related to video (0 if file has no video) */
total_subsongs = read_16bitLE(0x0c, streamFile); total_subsongs = read_u16le(0x0c, sf);
/* 0x0c: volume? (0x50, 0x4e) */ /* 0x0c: volume? (0x50, 0x4e) */
/* 0x10: biggest video chunk? (0 if file has no video) */ /* 0x10: biggest video chunk? (0 if file has no video) */
/* 0x14: biggest audio chunk? */ /* 0x14: biggest audio chunk? */
@ -33,12 +33,12 @@ VGMSTREAM * init_vgmstream_xavs(STREAMFILE *streamFile) {
if (target_subsong > total_subsongs || total_subsongs <= 0) goto fail; if (target_subsong > total_subsongs || total_subsongs <= 0) goto fail;
/* could use a blocked layout, but this needs interleaved PCM within blocks which can't be done ATM */ /* could use a blocked layout, but this needs interleaved PCM within blocks which can't be done ATM */
temp_streamFile = setup_xavs_streamfile(streamFile, 0x18, target_subsong - 1); temp_sf = setup_xavs_streamfile(sf, 0x18, target_subsong - 1);
if (!temp_streamFile) goto fail; if (!temp_sf) goto fail;
/* build the VGMSTREAM */ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag); vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->meta_type = meta_XAVS; vgmstream->meta_type = meta_XAVS;
@ -50,9 +50,9 @@ VGMSTREAM * init_vgmstream_xavs(STREAMFILE *streamFile) {
/* no apparent flags, most videos use 0x41 but not all */ /* no apparent flags, most videos use 0x41 but not all */
{ {
off_t offset = 0x18; off_t offset = 0x18;
while (offset < get_streamfile_size(streamFile)) { while (offset < get_streamfile_size(sf)) {
uint32_t chunk_id = read_32bitLE(offset+0x00, streamFile) & 0xFF; uint32_t chunk_id = read_u32le(offset+0x00, sf) & 0xFF;
uint32_t chunk_size = read_32bitLE(offset+0x00, streamFile) >> 8; uint32_t chunk_size = read_u32le(offset+0x00, sf) >> 8;
if ((chunk_id & 0xF0) == 0x40) { if ((chunk_id & 0xF0) == 0x40) {
vgmstream->sample_rate = 48000; vgmstream->sample_rate = 48000;
@ -72,16 +72,16 @@ VGMSTREAM * init_vgmstream_xavs(STREAMFILE *streamFile) {
} }
} }
vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(temp_streamFile), channel_count, 16); vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(temp_sf), channels, 16);
if (!vgmstream_open_stream(vgmstream,temp_streamFile,start_offset)) if (!vgmstream_open_stream(vgmstream, temp_sf, start_offset))
goto fail; goto fail;
close_streamfile(temp_streamFile); close_streamfile(temp_sf);
return vgmstream; return vgmstream;
fail: fail:
close_streamfile(temp_streamFile); close_streamfile(temp_sf);
close_vgmstream(vgmstream); close_vgmstream(vgmstream);
return NULL; return NULL;
} }

View file

@ -7,28 +7,27 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
STREAMFILE* sf_body = NULL; STREAMFILE* sf_body = NULL;
uint32_t offset; uint32_t offset;
uint32_t stream_type, stream_offset, stream_size;
uint32_t name_offset, name_size;
uint32_t flags;
int32_t num_samples;
int version = 0;
int loop_flag, channels, codec, sample_rate; int loop_flag, channels, codec, sample_rate;
int total_subsongs, target_subsong = sf->stream_index;
/* checks */ /* checks */
if (!check_extensions(sf, "xsh")) uint32_t version = read_u32le(0x00, sf);
goto fail; if (version < 0x009D || version > 0x101)
return NULL;
version = read_u32le(0x00, sf);
if (read_u32le(0x04, sf) != 0) if (read_u32le(0x04, sf) != 0)
goto fail; return NULL;
total_subsongs = read_u32le(0x08, sf); if (!check_extensions(sf, "xsh"))
return NULL;
int total_subsongs = read_u32le(0x08, sf);
int target_subsong = sf->stream_index;
if (target_subsong == 0) target_subsong = 1; if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
uint32_t stream_type, stream_offset, stream_size, flags;
uint32_t name_offset, name_size;
int32_t num_samples;
switch(version) { switch(version) {
case 0x009D: /* Spider-Man 2002 (Xbox) */ case 0x009D: /* Spider-Man 2002 (Xbox) */
offset = 0x0c + (target_subsong-1) * 0x60; offset = 0x0c + (target_subsong-1) * 0x60;
@ -74,22 +73,23 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
break; break;
default: default:
goto fail; return NULL;
} }
loop_flag = 0; // full loop flag (ex. Spider-Man city_e.XSH#7,22)
loop_flag = (flags & 0x01) != 0;
if (stream_type < 0 || stream_type > 2) if (stream_type > 2)
goto fail; return NULL;
/* 0x00: floats x4 (volume/pan/etc? usually 1.0, 1.0, 10.0, 10.0) */ // 0x00: floats x4 (volume/pan/etc? usually 1.0, 1.0, 10.0, 10.0)
codec = read_u16le(offset + 0x10,sf); codec = read_u16le(offset + 0x10,sf);
channels = read_u16le(offset + 0x12,sf); channels = read_u16le(offset + 0x12,sf);
sample_rate = read_u32le(offset + 0x14,sf); sample_rate = read_u32le(offset + 0x14,sf);
/* 0x18: avg bitrate */ // 0x18: avg bitrate
/* 0x1c: block size */ // 0x1c: block size
/* 0x1e: bps */ // 0x1e: bps
/* 0x20: 2? */ // 0x20: 2?
if (stream_type == 0) { if (stream_type == 0) {
vgmstream = init_vgmstream_silence_container(total_subsongs); vgmstream = init_vgmstream_silence_container(total_subsongs);
@ -120,6 +120,11 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
vgmstream->num_streams = total_subsongs; vgmstream->num_streams = total_subsongs;
read_string(vgmstream->stream_name, name_size, name_offset,sf); read_string(vgmstream->stream_name, name_size, name_offset,sf);
// external .xss shouldn't have loop info though
if (loop_flag && !vgmstream->loop_flag) {
vgmstream_force_loop(vgmstream, loop_flag, 0, vgmstream->num_samples);
}
close_streamfile(sf_body); close_streamfile(sf_body);
return vgmstream; return vgmstream;
//break; //break;
@ -138,7 +143,6 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
default: default:
goto fail; goto fail;
} }
} }
else { else {
sf_body = open_streamfile_by_ext(sf,"xsd"); sf_body = open_streamfile_by_ext(sf,"xsd");
@ -167,6 +171,8 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
num_samples = xbox_ima_bytes_to_samples(stream_size, channels); num_samples = xbox_ima_bytes_to_samples(stream_size, channels);
vgmstream->num_samples = num_samples; vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = num_samples;
break; break;
} }

View file

@ -6,17 +6,19 @@
/* Simple bitreader for MPEG/standard bit style, in 'most significant byte' (MSB) format. /* Simple bitreader for MPEG/standard bit style, in 'most significant byte' (MSB) format.
* Example: with 0x1234 = 00010010 00110100, reading 5b + 6b = 00010 010001 * Example: with 0x1234 = 00010010 00110100, reading 5b + 6b = 00010 010001
* (first upper 5b, then next lower 3b and next upper 3b = 6b) * (first upper 5b, then next lower 3b and next upper 3b = 6b)
* Kept in .h since it's slightly faster (compiler can optimize statics better using default compile flags). */ * Kept in .h since it's slightly faster (compiler can optimize statics better using default compile flags).
* Assumes bufs aren't that big (probable max ~0x20000000)
*/
typedef struct { typedef struct {
uint8_t* buf; /* buffer to read/write */ uint8_t* buf; // buffer to read/write
size_t bufsize; /* max size */ uint32_t bufsize; // max size
size_t b_max; /* max size in bits */ uint32_t b_max; // max size in bits
uint32_t b_off; /* current offset in bits inside buffer */ uint32_t b_off; // current offset in bits inside buffer
} bitstream_t; } bitstream_t;
/* convenience util */ /* convenience util */
static inline void bm_setup(bitstream_t* bs, uint8_t* buf, size_t bufsize) { static inline void bm_setup(bitstream_t* bs, uint8_t* buf, uint32_t bufsize) {
bs->buf = buf; bs->buf = buf;
bs->bufsize = bufsize; bs->bufsize = bufsize;
bs->b_max = bufsize * 8; bs->b_max = bufsize * 8;
@ -136,6 +138,14 @@ fail:
return 0; return 0;
} }
static inline uint32_t bm_read(bitstream_t* ib, uint32_t bits) {
uint32_t value;
int res = bm_get(ib, bits, &value);
if (!res)
return 0;
return value;
}
/* Write bits (max 32) to buf and update the bit offset. Order is BE (MSB). */ /* Write bits (max 32) to buf and update the bit offset. Order is BE (MSB). */
static inline int bm_put(bitstream_t* ob, uint32_t bits, uint32_t value) { static inline int bm_put(bitstream_t* ob, uint32_t bits, uint32_t value) {
uint32_t shift, pos; uint32_t shift, pos;

View file

@ -0,0 +1,16 @@
#ifndef _IO_CALLBACK_H_
#define _IO_CALLBACK_H_
#include <stdint.h>
#define IO_CALLBACK_SEEK_SET 0
#define IO_CALLBACK_SEEK_CUR 1
#define IO_CALLBACK_SEEK_END 2
typedef struct {
void* arg;
int64_t (*read)(void* dst, int size, int n, void* arg);
int64_t (*seek)(void* arg, int64_t offset, int whence);
int64_t (*tell)(void* arg);
} io_callback_t;
#endif

View file

@ -0,0 +1,53 @@
#include "io_callback_sf.h"
#include <stdint.h>
static int64_t io_sf_read(void* dst, int size, int n, void* arg) {
io_priv_t* io = arg;
int bytes_read = read_streamfile(dst, io->offset, size * n, io->sf);
int items_read = bytes_read / size;
io->offset += bytes_read;
return items_read;
}
static int64_t io_sf_seek(void* arg, int64_t offset, int whence) {
io_priv_t* io = arg;
int64_t base_offset;
switch (whence) {
case IO_CALLBACK_SEEK_SET:
base_offset = 0;
break;
case IO_CALLBACK_SEEK_CUR:
base_offset = io->offset;
break;
case IO_CALLBACK_SEEK_END:
base_offset = get_streamfile_size(io->sf);
break;
default:
return -1;
}
int64_t new_offset = base_offset + offset;
if (new_offset < 0 /*|| new_offset > get_streamfile_size(config->sf)*/) {
return -1; /* unseekable */
}
else {
io->offset = new_offset;
return 0;
}
}
static int64_t io_sf_tell(void* arg) {
io_priv_t* io = arg;
return io->offset;
}
void io_callbacks_set_sf(io_callback_t* cb, io_priv_t* arg) {
cb->arg = arg;
cb->read = io_sf_read;
cb->seek = io_sf_seek;
cb->tell = io_sf_tell;
}

View file

@ -0,0 +1,16 @@
#ifndef _IO_CALLBACK_SF_H_
#define _IO_CALLBACK_SF_H_
#include "io_callback.h"
#include "../streamfile.h"
#include <stdint.h>
#include <stdio.h>
typedef struct {
STREAMFILE* sf;
int64_t offset;
} io_priv_t;
void io_callbacks_set_sf(io_callback_t* cb, io_priv_t* arg);
#endif

View file

@ -15,6 +15,7 @@ logger_t log_impl = {0};
//void* log = &log_impl; //void* log = &log_impl;
enum { enum {
LOG_LEVEL_NONE = 0,
LOG_LEVEL_INFO = 1, LOG_LEVEL_INFO = 1,
LOG_LEVEL_DEBUG = 2, LOG_LEVEL_DEBUG = 2,
LOG_LEVEL_ALL = 100, LOG_LEVEL_ALL = 100,
@ -30,6 +31,11 @@ void vgm_log_set_callback(void* ctx_p, int level, int type, void* callback) {
ctx->level = level; ctx->level = level;
if (level == LOG_LEVEL_NONE) {
ctx->callback = NULL;
return;
}
switch(type) { switch(type) {
case 0: case 0:
ctx->callback = callback; ctx->callback = callback;

View file

@ -0,0 +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;
}

View file

@ -0,0 +1,17 @@
#ifndef _VORBIS_CODEBOOKS_H_
#define _VORBIS_CODEBOOKS_H_
#include <stdint.h>
#include "../streamfile.h"
typedef struct {
uint32_t id;
uint32_t size;
const uint8_t* codebooks;
} vcb_info_t;
int vcb_load_codebook_array(uint8_t* buf, int buf_size, uint32_t setup_id, const vcb_info_t* list, int list_length);
//, STREAMFILE* sf
#endif

Some files were not shown because too many files have changed in this diff Show more