Updated VGMStream to r1050-3272-g842171b8

This commit is contained in:
Christopher Snowhill 2020-09-21 22:22:53 -07:00
parent 6a534ad900
commit bb38853ee9
113 changed files with 11112 additions and 8439 deletions

View file

@ -218,7 +218,6 @@
834FE111215C79ED000A5D3D /* ck.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0E8215C79EC000A5D3D /* ck.c */; }; 834FE111215C79ED000A5D3D /* ck.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0E8215C79EC000A5D3D /* ck.c */; };
835027131ED119E000C25929 /* mta2_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 835027121ED119E000C25929 /* mta2_decoder.c */; }; 835027131ED119E000C25929 /* mta2_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 835027121ED119E000C25929 /* mta2_decoder.c */; };
8350C0551E071881009E0A93 /* xma.c in Sources */ = {isa = PBXBuildFile; fileRef = 8350C0541E071881009E0A93 /* xma.c */; }; 8350C0551E071881009E0A93 /* xma.c in Sources */ = {isa = PBXBuildFile; fileRef = 8350C0541E071881009E0A93 /* xma.c */; };
8350C05A1E071990009E0A93 /* ps2_svag_snk.c in Sources */ = {isa = PBXBuildFile; fileRef = 8350C0591E071990009E0A93 /* ps2_svag_snk.c */; };
8351F3292212B53400A606E4 /* dsa_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8351F3252212B53300A606E4 /* dsa_decoder.c */; }; 8351F3292212B53400A606E4 /* dsa_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8351F3252212B53300A606E4 /* dsa_decoder.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 */; };
@ -375,7 +374,6 @@
836F6FFA18BDC2190095E648 /* ps2_spm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBE18BDC2190095E648 /* ps2_spm.c */; }; 836F6FFA18BDC2190095E648 /* ps2_spm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBE18BDC2190095E648 /* ps2_spm.c */; };
836F6FFB18BDC2190095E648 /* ps2_sps.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBF18BDC2190095E648 /* ps2_sps.c */; }; 836F6FFB18BDC2190095E648 /* ps2_sps.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBF18BDC2190095E648 /* ps2_sps.c */; };
836F6FFC18BDC2190095E648 /* ps2_ster.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC018BDC2190095E648 /* ps2_ster.c */; }; 836F6FFC18BDC2190095E648 /* ps2_ster.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC018BDC2190095E648 /* ps2_ster.c */; };
836F700018BDC2190095E648 /* ps2_svag.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC418BDC2190095E648 /* ps2_svag.c */; };
836F700118BDC2190095E648 /* ps2_tec.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC518BDC2190095E648 /* ps2_tec.c */; }; 836F700118BDC2190095E648 /* ps2_tec.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC518BDC2190095E648 /* ps2_tec.c */; };
836F700218BDC2190095E648 /* ps2_tk5.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC618BDC2190095E648 /* ps2_tk5.c */; }; 836F700218BDC2190095E648 /* ps2_tk5.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC618BDC2190095E648 /* ps2_tk5.c */; };
836F700418BDC2190095E648 /* ps2_vas.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC818BDC2190095E648 /* ps2_vas.c */; }; 836F700418BDC2190095E648 /* ps2_vas.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC818BDC2190095E648 /* ps2_vas.c */; };
@ -544,6 +542,21 @@
83AA5D241F6E2F9C0020821C /* awc.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA5D201F6E2F9B0020821C /* awc.c */; }; 83AA5D241F6E2F9C0020821C /* awc.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA5D201F6E2F9B0020821C /* awc.c */; };
83AA5D251F6E2F9C0020821C /* hca_keys.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AA5D211F6E2F9C0020821C /* hca_keys.h */; }; 83AA5D251F6E2F9C0020821C /* hca_keys.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AA5D211F6E2F9C0020821C /* hca_keys.h */; };
83AA5D271F6E2F9C0020821C /* stm.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA5D231F6E2F9C0020821C /* stm.c */; }; 83AA5D271F6E2F9C0020821C /* stm.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA5D231F6E2F9C0020821C /* stm.c */; };
83AA7F722519BFEA004C5298 /* vorbis_bitreader.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AA7F6D2519BFEA004C5298 /* vorbis_bitreader.h */; };
83AA7F732519BFEA004C5298 /* mpeg_bitreader.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AA7F712519BFEA004C5298 /* mpeg_bitreader.h */; };
83AA7F7D2519C042004C5298 /* dsb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7F742519C041004C5298 /* dsb.c */; };
83AA7F7E2519C042004C5298 /* svag_kcet.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7F752519C041004C5298 /* svag_kcet.c */; };
83AA7F7F2519C042004C5298 /* bsf.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7F762519C042004C5298 /* bsf.c */; };
83AA7F802519C042004C5298 /* sab_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AA7F772519C042004C5298 /* sab_streamfile.h */; };
83AA7F812519C042004C5298 /* silence.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7F782519C042004C5298 /* silence.c */; };
83AA7F822519C042004C5298 /* ktsc.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7F792519C042004C5298 /* ktsc.c */; };
83AA7F832519C042004C5298 /* adp_konami.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7F7A2519C042004C5298 /* adp_konami.c */; };
83AA7F842519C042004C5298 /* svag_snk.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7F7B2519C042004C5298 /* svag_snk.c */; };
83AA7F852519C042004C5298 /* zwv.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7F7C2519C042004C5298 /* zwv.c */; };
83AA7F8A2519C076004C5298 /* decode.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AA7F862519C076004C5298 /* decode.h */; };
83AA7F8B2519C076004C5298 /* render.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AA7F872519C076004C5298 /* render.h */; };
83AA7F8C2519C076004C5298 /* render.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7F882519C076004C5298 /* render.c */; };
83AA7F8D2519C076004C5298 /* decode.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7F892519C076004C5298 /* decode.c */; };
83AB8C761E8072A100086084 /* x360_ast.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AB8C741E8072A100086084 /* x360_ast.c */; }; 83AB8C761E8072A100086084 /* x360_ast.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AB8C741E8072A100086084 /* x360_ast.c */; };
83AFABBC23795202002F3947 /* xssb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AFABB923795201002F3947 /* xssb.c */; }; 83AFABBC23795202002F3947 /* xssb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AFABB923795201002F3947 /* xssb.c */; };
83AFABBD23795202002F3947 /* ea_eaac_opus_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AFABBA23795202002F3947 /* ea_eaac_opus_streamfile.h */; }; 83AFABBD23795202002F3947 /* ea_eaac_opus_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AFABBA23795202002F3947 /* ea_eaac_opus_streamfile.h */; };
@ -947,7 +960,6 @@
834FE0E8215C79EC000A5D3D /* ck.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ck.c; sourceTree = "<group>"; }; 834FE0E8215C79EC000A5D3D /* ck.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ck.c; sourceTree = "<group>"; };
835027121ED119E000C25929 /* mta2_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mta2_decoder.c; sourceTree = "<group>"; }; 835027121ED119E000C25929 /* mta2_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mta2_decoder.c; sourceTree = "<group>"; };
8350C0541E071881009E0A93 /* xma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xma.c; sourceTree = "<group>"; }; 8350C0541E071881009E0A93 /* xma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xma.c; sourceTree = "<group>"; };
8350C0591E071990009E0A93 /* ps2_svag_snk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_svag_snk.c; sourceTree = "<group>"; };
8351F3252212B53300A606E4 /* dsa_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dsa_decoder.c; sourceTree = "<group>"; }; 8351F3252212B53300A606E4 /* dsa_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dsa_decoder.c; sourceTree = "<group>"; };
8351F32A2212B57000A606E4 /* 208.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = 208.c; sourceTree = "<group>"; }; 8351F32A2212B57000A606E4 /* 208.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = 208.c; sourceTree = "<group>"; };
8351F32B2212B57000A606E4 /* ubi_bao_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ubi_bao_streamfile.h; sourceTree = "<group>"; }; 8351F32B2212B57000A606E4 /* ubi_bao_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ubi_bao_streamfile.h; sourceTree = "<group>"; };
@ -1105,7 +1117,6 @@
836F6EBE18BDC2190095E648 /* ps2_spm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_spm.c; sourceTree = "<group>"; }; 836F6EBE18BDC2190095E648 /* ps2_spm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_spm.c; sourceTree = "<group>"; };
836F6EBF18BDC2190095E648 /* ps2_sps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_sps.c; sourceTree = "<group>"; }; 836F6EBF18BDC2190095E648 /* ps2_sps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_sps.c; sourceTree = "<group>"; };
836F6EC018BDC2190095E648 /* ps2_ster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_ster.c; sourceTree = "<group>"; }; 836F6EC018BDC2190095E648 /* ps2_ster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_ster.c; sourceTree = "<group>"; };
836F6EC418BDC2190095E648 /* ps2_svag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_svag.c; sourceTree = "<group>"; };
836F6EC518BDC2190095E648 /* ps2_tec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_tec.c; sourceTree = "<group>"; }; 836F6EC518BDC2190095E648 /* ps2_tec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_tec.c; sourceTree = "<group>"; };
836F6EC618BDC2190095E648 /* ps2_tk5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_tk5.c; sourceTree = "<group>"; }; 836F6EC618BDC2190095E648 /* ps2_tk5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_tk5.c; sourceTree = "<group>"; };
836F6EC818BDC2190095E648 /* ps2_vas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_vas.c; sourceTree = "<group>"; }; 836F6EC818BDC2190095E648 /* ps2_vas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_vas.c; sourceTree = "<group>"; };
@ -1273,6 +1284,21 @@
83AA5D201F6E2F9B0020821C /* awc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = awc.c; sourceTree = "<group>"; }; 83AA5D201F6E2F9B0020821C /* awc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = awc.c; sourceTree = "<group>"; };
83AA5D211F6E2F9C0020821C /* hca_keys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hca_keys.h; sourceTree = "<group>"; }; 83AA5D211F6E2F9C0020821C /* hca_keys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hca_keys.h; sourceTree = "<group>"; };
83AA5D231F6E2F9C0020821C /* stm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = stm.c; sourceTree = "<group>"; }; 83AA5D231F6E2F9C0020821C /* stm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = stm.c; sourceTree = "<group>"; };
83AA7F6D2519BFEA004C5298 /* vorbis_bitreader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vorbis_bitreader.h; sourceTree = "<group>"; };
83AA7F712519BFEA004C5298 /* mpeg_bitreader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mpeg_bitreader.h; sourceTree = "<group>"; };
83AA7F742519C041004C5298 /* dsb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dsb.c; sourceTree = "<group>"; };
83AA7F752519C041004C5298 /* svag_kcet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = svag_kcet.c; sourceTree = "<group>"; };
83AA7F762519C042004C5298 /* bsf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bsf.c; sourceTree = "<group>"; };
83AA7F772519C042004C5298 /* sab_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sab_streamfile.h; sourceTree = "<group>"; };
83AA7F782519C042004C5298 /* silence.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = silence.c; sourceTree = "<group>"; };
83AA7F792519C042004C5298 /* ktsc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ktsc.c; sourceTree = "<group>"; };
83AA7F7A2519C042004C5298 /* adp_konami.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adp_konami.c; sourceTree = "<group>"; };
83AA7F7B2519C042004C5298 /* svag_snk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = svag_snk.c; sourceTree = "<group>"; };
83AA7F7C2519C042004C5298 /* zwv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zwv.c; sourceTree = "<group>"; };
83AA7F862519C076004C5298 /* decode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = decode.h; sourceTree = "<group>"; };
83AA7F872519C076004C5298 /* render.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render.h; sourceTree = "<group>"; };
83AA7F882519C076004C5298 /* render.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render.c; sourceTree = "<group>"; };
83AA7F892519C076004C5298 /* decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = decode.c; sourceTree = "<group>"; };
83AB8C741E8072A100086084 /* x360_ast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x360_ast.c; sourceTree = "<group>"; }; 83AB8C741E8072A100086084 /* x360_ast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x360_ast.c; sourceTree = "<group>"; };
83AFABB923795201002F3947 /* xssb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xssb.c; sourceTree = "<group>"; }; 83AFABB923795201002F3947 /* xssb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xssb.c; sourceTree = "<group>"; };
83AFABBA23795202002F3947 /* ea_eaac_opus_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ea_eaac_opus_streamfile.h; sourceTree = "<group>"; }; 83AFABBA23795202002F3947 /* ea_eaac_opus_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ea_eaac_opus_streamfile.h; sourceTree = "<group>"; };
@ -1469,11 +1495,15 @@
836F6DDF18BDC2180095E648 /* coding */, 836F6DDF18BDC2180095E648 /* coding */,
836F6DFF18BDC2180095E648 /* layout */, 836F6DFF18BDC2180095E648 /* layout */,
836F6E2718BDC2180095E648 /* meta */, 836F6E2718BDC2180095E648 /* meta */,
83AA7F892519C076004C5298 /* decode.c */,
83AA7F862519C076004C5298 /* decode.h */,
83A3F0711E3AD8B900D6A794 /* formats.c */, 83A3F0711E3AD8B900D6A794 /* formats.c */,
83C7282522BC8C1400678B4A /* mixing.c */, 83C7282522BC8C1400678B4A /* mixing.c */,
83C7282422BC8C1400678B4A /* mixing.h */, 83C7282422BC8C1400678B4A /* mixing.h */,
83C7282622BC8C1400678B4A /* plugins.c */, 83C7282622BC8C1400678B4A /* plugins.c */,
83C7282322BC8C1300678B4A /* plugins.h */, 83C7282322BC8C1300678B4A /* plugins.h */,
83AA7F882519C076004C5298 /* render.c */,
83AA7F872519C076004C5298 /* render.h */,
83A3F0731E3AD8B900D6A794 /* stack_alloc.h */, 83A3F0731E3AD8B900D6A794 /* stack_alloc.h */,
836F6F1718BDC2190095E648 /* streamfile.c */, 836F6F1718BDC2190095E648 /* streamfile.c */,
836F6F1818BDC2190095E648 /* streamfile.h */, 836F6F1818BDC2190095E648 /* streamfile.h */,
@ -1533,6 +1563,7 @@
836F6DEC18BDC2180095E648 /* lsf_decoder.c */, 836F6DEC18BDC2180095E648 /* lsf_decoder.c */,
83709E0B1ECBC1C3005C03D3 /* mc3_decoder.c */, 83709E0B1ECBC1C3005C03D3 /* mc3_decoder.c */,
836F6DEE18BDC2180095E648 /* mp4_aac_decoder.c */, 836F6DEE18BDC2180095E648 /* mp4_aac_decoder.c */,
83AA7F712519BFEA004C5298 /* mpeg_bitreader.h */,
839E21D91F2EDAF000EE54D7 /* mpeg_custom_utils_ahx.c */, 839E21D91F2EDAF000EE54D7 /* mpeg_custom_utils_ahx.c */,
83AA5D141F6E2F600020821C /* mpeg_custom_utils_awc.c */, 83AA5D141F6E2F600020821C /* mpeg_custom_utils_awc.c */,
83AA5D131F6E2F5F0020821C /* mpeg_custom_utils_ealayer3.c */, 83AA5D131F6E2F5F0020821C /* mpeg_custom_utils_ealayer3.c */,
@ -1562,6 +1593,7 @@
8373341023F60C7A00DE14DC /* tgcadpcm_decoder.c */, 8373341023F60C7A00DE14DC /* tgcadpcm_decoder.c */,
837CEA7623487E2400E62A4A /* ubi_adpcm_decoder.c */, 837CEA7623487E2400E62A4A /* ubi_adpcm_decoder.c */,
83F1EE2C245D4FB20076E182 /* vadpcm_decoder.c */, 83F1EE2C245D4FB20076E182 /* vadpcm_decoder.c */,
83AA7F6D2519BFEA004C5298 /* vorbis_bitreader.h */,
839E21D61F2EDAF000EE54D7 /* vorbis_custom_data_fsb.h */, 839E21D61F2EDAF000EE54D7 /* vorbis_custom_data_fsb.h */,
839E21DC1F2EDAF000EE54D7 /* vorbis_custom_data_wwise.h */, 839E21DC1F2EDAF000EE54D7 /* vorbis_custom_data_wwise.h */,
839E21D71F2EDAF000EE54D7 /* vorbis_custom_decoder.c */, 839E21D71F2EDAF000EE54D7 /* vorbis_custom_decoder.c */,
@ -1643,6 +1675,7 @@
836F6E2A18BDC2180095E648 /* aax.c */, 836F6E2A18BDC2180095E648 /* aax.c */,
837CEAD623487E8300E62A4A /* acb.c */, 837CEAD623487E8300E62A4A /* acb.c */,
836F6E2B18BDC2180095E648 /* acm.c */, 836F6E2B18BDC2180095E648 /* acm.c */,
83AA7F7A2519C042004C5298 /* adp_konami.c */,
834FE0CF215C79E8000A5D3D /* adpcm_capcom.c */, 834FE0CF215C79E8000A5D3D /* adpcm_capcom.c */,
836F6E2C18BDC2180095E648 /* ads.c */, 836F6E2C18BDC2180095E648 /* ads.c */,
8349A9021FE6258100E26435 /* adx_keys.h */, 8349A9021FE6258100E26435 /* adx_keys.h */,
@ -1682,6 +1715,7 @@
8373342523F60CDC00DE14DC /* bnsf_keys.h */, 8373342523F60CDC00DE14DC /* bnsf_keys.h */,
836F6E3918BDC2180095E648 /* bnsf.c */, 836F6E3918BDC2180095E648 /* bnsf.c */,
836F6E3A18BDC2180095E648 /* brstm.c */, 836F6E3A18BDC2180095E648 /* brstm.c */,
83AA7F762519C042004C5298 /* bsf.c */,
83EDE5D71A70951A005F5D84 /* btsnd.c */, 83EDE5D71A70951A005F5D84 /* btsnd.c */,
835C883122CC17BD001B4B3F /* bwav.c */, 835C883122CC17BD001B4B3F /* bwav.c */,
8306B0CF2098458F000302D4 /* caf.c */, 8306B0CF2098458F000302D4 /* caf.c */,
@ -1703,6 +1737,7 @@
834FE0CD215C79E8000A5D3D /* derf.c */, 834FE0CD215C79E8000A5D3D /* derf.c */,
8385D4E2245174C600FF8E67 /* diva.c */, 8385D4E2245174C600FF8E67 /* diva.c */,
836F6E4318BDC2180095E648 /* dmsg_segh.c */, 836F6E4318BDC2180095E648 /* dmsg_segh.c */,
83AA7F742519C041004C5298 /* dsb.c */,
8351F32C2212B57000A606E4 /* dsf.c */, 8351F32C2212B57000A606E4 /* dsf.c */,
83299FCF1E7660C7003A3242 /* dsp_adx.c */, 83299FCF1E7660C7003A3242 /* dsp_adx.c */,
836F6E4418BDC2180095E648 /* dsp_bdsp.c */, 836F6E4418BDC2180095E648 /* dsp_bdsp.c */,
@ -1766,6 +1801,7 @@
834FE0C3215C79E6000A5D3D /* kma9_streamfile.h */, 834FE0C3215C79E6000A5D3D /* kma9_streamfile.h */,
83A21F83201D8981000F04B9 /* kma9.c */, 83A21F83201D8981000F04B9 /* kma9.c */,
836F6E5918BDC2180095E648 /* kraw.c */, 836F6E5918BDC2180095E648 /* kraw.c */,
83AA7F792519C042004C5298 /* ktsc.c */,
83D20074248DDB760048BD24 /* ktsr.c */, 83D20074248DDB760048BD24 /* ktsr.c */,
830EBE122004656E0023AA10 /* ktss.c */, 830EBE122004656E0023AA10 /* ktss.c */,
8373342423F60CDB00DE14DC /* kwb.c */, 8373342423F60CDB00DE14DC /* kwb.c */,
@ -1898,8 +1934,6 @@
836F6EBE18BDC2190095E648 /* ps2_spm.c */, 836F6EBE18BDC2190095E648 /* ps2_spm.c */,
836F6EBF18BDC2190095E648 /* ps2_sps.c */, 836F6EBF18BDC2190095E648 /* ps2_sps.c */,
836F6EC018BDC2190095E648 /* ps2_ster.c */, 836F6EC018BDC2190095E648 /* ps2_ster.c */,
8350C0591E071990009E0A93 /* ps2_svag_snk.c */,
836F6EC418BDC2190095E648 /* ps2_svag.c */,
836F6EC518BDC2190095E648 /* ps2_tec.c */, 836F6EC518BDC2190095E648 /* ps2_tec.c */,
836F6EC618BDC2190095E648 /* ps2_tk5.c */, 836F6EC618BDC2190095E648 /* ps2_tk5.c */,
832BF80D21E05148006F50F1 /* ps2_va3.c */, 832BF80D21E05148006F50F1 /* ps2_va3.c */,
@ -1937,6 +1971,7 @@
836F6EE818BDC2190095E648 /* rwsd.c */, 836F6EE818BDC2190095E648 /* rwsd.c */,
836F6EE918BDC2190095E648 /* rwx.c */, 836F6EE918BDC2190095E648 /* rwx.c */,
836F6EEA18BDC2190095E648 /* s14_sss.c */, 836F6EEA18BDC2190095E648 /* s14_sss.c */,
83AA7F772519C042004C5298 /* sab_streamfile.h */,
8349A8F11FE6257D00E26435 /* sab.c */, 8349A8F11FE6257D00E26435 /* sab.c */,
83D20078248DDB770048BD24 /* sadf.c */, 83D20078248DDB770048BD24 /* sadf.c */,
83D20079248DDB770048BD24 /* sadl.c */, 83D20079248DDB770048BD24 /* sadl.c */,
@ -1953,6 +1988,7 @@
83C7280822BC893C00678B4A /* sfh.c */, 83C7280822BC893C00678B4A /* sfh.c */,
836F6EF118BDC2190095E648 /* sfl.c */, 836F6EF118BDC2190095E648 /* sfl.c */,
831BA6111EAC61A500CF89B0 /* sgxd.c */, 831BA6111EAC61A500CF89B0 /* sgxd.c */,
83AA7F782519C042004C5298 /* silence.c */,
839E21EA1F2EDB0500EE54D7 /* sk_aud.c */, 839E21EA1F2EDB0500EE54D7 /* sk_aud.c */,
836F6EF218BDC2190095E648 /* sli.c */, 836F6EF218BDC2190095E648 /* sli.c */,
8306B0D32098458F000302D4 /* smc_smh.c */, 8306B0D32098458F000302D4 /* smc_smh.c */,
@ -1972,6 +2008,8 @@
836F6EF718BDC2190095E648 /* str_snds.c */, 836F6EF718BDC2190095E648 /* str_snds.c */,
834FE0C2215C79E6000A5D3D /* str_wav.c */, 834FE0C2215C79E6000A5D3D /* str_wav.c */,
83C7280722BC893B00678B4A /* strm_abylight.c */, 83C7280722BC893B00678B4A /* strm_abylight.c */,
83AA7F752519C041004C5298 /* svag_kcet.c */,
83AA7F7B2519C042004C5298 /* svag_snk.c */,
834FE0D7215C79EA000A5D3D /* svg.c */, 834FE0D7215C79EA000A5D3D /* svg.c */,
836F6EF918BDC2190095E648 /* svs.c */, 836F6EF918BDC2190095E648 /* svs.c */,
83D0381724A4129A004CF90F /* swav.c */, 83D0381724A4129A004CF90F /* swav.c */,
@ -2065,6 +2103,7 @@
832BF80E21E05149006F50F1 /* zsnd_streamfile.h */, 832BF80E21E05149006F50F1 /* zsnd_streamfile.h */,
832BF80F21E05149006F50F1 /* zsnd.c */, 832BF80F21E05149006F50F1 /* zsnd.c */,
836F6F1618BDC2190095E648 /* zwdsp.c */, 836F6F1618BDC2190095E648 /* zwdsp.c */,
83AA7F7C2519C042004C5298 /* zwv.c */,
); );
path = meta; path = meta;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2099,6 +2138,7 @@
836F6F3518BDC2190095E648 /* nwa_decoder.h in Headers */, 836F6F3518BDC2190095E648 /* nwa_decoder.h in Headers */,
83031EC9243C50A800C3F3E0 /* circus_decoder_lzxpcm.h in Headers */, 83031EC9243C50A800C3F3E0 /* circus_decoder_lzxpcm.h in Headers */,
83C7282222BC893D00678B4A /* mta2_streamfile.h in Headers */, 83C7282222BC893D00678B4A /* mta2_streamfile.h in Headers */,
83AA7F802519C042004C5298 /* sab_streamfile.h in Headers */,
83A21F87201D8981000F04B9 /* fsb_keys.h in Headers */, 83A21F87201D8981000F04B9 /* fsb_keys.h in Headers */,
834FE0EC215C79ED000A5D3D /* kma9_streamfile.h in Headers */, 834FE0EC215C79ED000A5D3D /* kma9_streamfile.h in Headers */,
8349A90F1FE6258200E26435 /* aix_streamfile.h in Headers */, 8349A90F1FE6258200E26435 /* aix_streamfile.h in Headers */,
@ -2113,6 +2153,7 @@
83C7282822BC8C1500678B4A /* mixing.h in Headers */, 83C7282822BC8C1500678B4A /* mixing.h in Headers */,
832BF82C21E0514B006F50F1 /* hca_keys_awb.h in Headers */, 832BF82C21E0514B006F50F1 /* hca_keys_awb.h in Headers */,
8306B0E020984590000302D4 /* ppst_streamfile.h in Headers */, 8306B0E020984590000302D4 /* ppst_streamfile.h in Headers */,
83AA7F722519BFEA004C5298 /* vorbis_bitreader.h in Headers */,
834FE0BA215C798C000A5D3D /* ea_mt_decoder_utk.h in Headers */, 834FE0BA215C798C000A5D3D /* ea_mt_decoder_utk.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 */,
@ -2126,6 +2167,7 @@
8323894B1D22419B00482226 /* clHCA.h in Headers */, 8323894B1D22419B00482226 /* clHCA.h in Headers */,
83C7281122BC893D00678B4A /* 9tav_streamfile.h in Headers */, 83C7281122BC893D00678B4A /* 9tav_streamfile.h in Headers */,
83C7280F22BC893D00678B4A /* xwb_xsb.h in Headers */, 83C7280F22BC893D00678B4A /* xwb_xsb.h in Headers */,
83AA7F732519BFEA004C5298 /* mpeg_bitreader.h in Headers */,
83C7281622BC893D00678B4A /* xwma_konami_streamfile.h in Headers */, 83C7281622BC893D00678B4A /* xwma_konami_streamfile.h in Headers */,
839E21E81F2EDAF100EE54D7 /* mpeg_decoder.h in Headers */, 839E21E81F2EDAF100EE54D7 /* mpeg_decoder.h in Headers */,
839E21E51F2EDAF100EE54D7 /* vorbis_custom_decoder.h in Headers */, 839E21E51F2EDAF100EE54D7 /* vorbis_custom_decoder.h in Headers */,
@ -2138,6 +2180,7 @@
83031EC5243C50A800C3F3E0 /* circus_decoder_lib_data.h in Headers */, 83031EC5243C50A800C3F3E0 /* circus_decoder_lib_data.h in Headers */,
834FE0B5215C798C000A5D3D /* acm_decoder_libacm.h in Headers */, 834FE0B5215C798C000A5D3D /* acm_decoder_libacm.h in Headers */,
839E21E61F2EDAF100EE54D7 /* vorbis_custom_data_wwise.h in Headers */, 839E21E61F2EDAF100EE54D7 /* vorbis_custom_data_wwise.h in Headers */,
83AA7F8A2519C076004C5298 /* decode.h in Headers */,
8373342D23F60CDC00DE14DC /* bnsf_keys.h in Headers */, 8373342D23F60CDC00DE14DC /* bnsf_keys.h in Headers */,
834FE103215C79ED000A5D3D /* ea_schl_streamfile.h in Headers */, 834FE103215C79ED000A5D3D /* ea_schl_streamfile.h in Headers */,
83F0AA6021E2028C004BBC04 /* vsv_streamfile.h in Headers */, 83F0AA6021E2028C004BBC04 /* vsv_streamfile.h in Headers */,
@ -2151,6 +2194,7 @@
8306B0E820984590000302D4 /* opus_interleave_streamfile.h in Headers */, 8306B0E820984590000302D4 /* opus_interleave_streamfile.h in Headers */,
83031EDD243C510500C3F3E0 /* xnb_streamfile.h in Headers */, 83031EDD243C510500C3F3E0 /* xnb_streamfile.h in Headers */,
83D2007B248DDB770048BD24 /* mups_streamfile.h in Headers */, 83D2007B248DDB770048BD24 /* mups_streamfile.h in Headers */,
83AA7F8B2519C076004C5298 /* render.h in Headers */,
8373341623F60C7B00DE14DC /* g7221_decoder_aes.h in Headers */, 8373341623F60C7B00DE14DC /* g7221_decoder_aes.h in Headers */,
8373341923F60C7B00DE14DC /* g7221_decoder_lib_data.h in Headers */, 8373341923F60C7B00DE14DC /* g7221_decoder_lib_data.h in Headers */,
83AFABBD23795202002F3947 /* ea_eaac_opus_streamfile.h in Headers */, 83AFABBD23795202002F3947 /* ea_eaac_opus_streamfile.h in Headers */,
@ -2382,7 +2426,6 @@
836F6FD718BDC2190095E648 /* ps2_filp.c in Sources */, 836F6FD718BDC2190095E648 /* ps2_filp.c in Sources */,
83FF0EBC1E93282100C58054 /* wwise.c in Sources */, 83FF0EBC1E93282100C58054 /* wwise.c in Sources */,
836F6F7018BDC2190095E648 /* apple_caff.c in Sources */, 836F6F7018BDC2190095E648 /* apple_caff.c in Sources */,
836F700018BDC2190095E648 /* ps2_svag.c in Sources */,
836F6FB618BDC2190095E648 /* ngc_sck_dsp.c in Sources */, 836F6FB618BDC2190095E648 /* ngc_sck_dsp.c in Sources */,
836F6F2818BDC2190095E648 /* ima_decoder.c in Sources */, 836F6F2818BDC2190095E648 /* ima_decoder.c in Sources */,
837CEB072348809400E62A4A /* seb.c in Sources */, 837CEB072348809400E62A4A /* seb.c in Sources */,
@ -2445,6 +2488,7 @@
836F705618BDC2190095E648 /* util.c in Sources */, 836F705618BDC2190095E648 /* util.c in Sources */,
8306B0A820984552000302D4 /* blocked_ps2_iab.c in Sources */, 8306B0A820984552000302D4 /* blocked_ps2_iab.c in Sources */,
8306B0EA20984590000302D4 /* caf.c in Sources */, 8306B0EA20984590000302D4 /* caf.c in Sources */,
83AA7F842519C042004C5298 /* svag_snk.c in Sources */,
834FE107215C79ED000A5D3D /* mib_mih.c in Sources */, 834FE107215C79ED000A5D3D /* mib_mih.c in Sources */,
836F703618BDC2190095E648 /* thp.c in Sources */, 836F703618BDC2190095E648 /* thp.c in Sources */,
836F6F7818BDC2190095E648 /* Cstr.c in Sources */, 836F6F7818BDC2190095E648 /* Cstr.c in Sources */,
@ -2481,6 +2525,7 @@
836F6F6618BDC2190095E648 /* aax.c in Sources */, 836F6F6618BDC2190095E648 /* aax.c in Sources */,
836F6FD618BDC2190095E648 /* ps2_exst.c in Sources */, 836F6FD618BDC2190095E648 /* ps2_exst.c in Sources */,
8306B0BC20984552000302D4 /* blocked_vs.c in Sources */, 8306B0BC20984552000302D4 /* blocked_vs.c in Sources */,
83AA7F812519C042004C5298 /* silence.c in Sources */,
834FE0B3215C798C000A5D3D /* acm_decoder_util.c in Sources */, 834FE0B3215C798C000A5D3D /* acm_decoder_util.c in Sources */,
837CEA7A23487E2500E62A4A /* ffmpeg_decoder_utils.c in Sources */, 837CEA7A23487E2500E62A4A /* ffmpeg_decoder_utils.c in Sources */,
837CEAF823487F2C00E62A4A /* xmv_valve.c in Sources */, 837CEAF823487F2C00E62A4A /* xmv_valve.c in Sources */,
@ -2497,7 +2542,9 @@
836F6F6F18BDC2190095E648 /* akb.c in Sources */, 836F6F6F18BDC2190095E648 /* akb.c in Sources */,
83EED5D6203A8BD7008BEB45 /* blocked_ea_swvr.c in Sources */, 83EED5D6203A8BD7008BEB45 /* blocked_ea_swvr.c in Sources */,
8349A9181FE6258200E26435 /* ea_1snh.c in Sources */, 8349A9181FE6258200E26435 /* ea_1snh.c in Sources */,
83AA7F7E2519C042004C5298 /* svag_kcet.c in Sources */,
8373342C23F60CDC00DE14DC /* kwb.c in Sources */, 8373342C23F60CDC00DE14DC /* kwb.c in Sources */,
83AA7F852519C042004C5298 /* zwv.c in Sources */,
83EED5D4203A8BC7008BEB45 /* aus.c in Sources */, 83EED5D4203A8BC7008BEB45 /* aus.c in Sources */,
836F6F7F18BDC2190095E648 /* dmsg_segh.c in Sources */, 836F6F7F18BDC2190095E648 /* dmsg_segh.c in Sources */,
832BF81D21E0514B006F50F1 /* msf_tamasoft.c in Sources */, 832BF81D21E0514B006F50F1 /* msf_tamasoft.c in Sources */,
@ -2570,6 +2617,7 @@
836F705218BDC2190095E648 /* zwdsp.c in Sources */, 836F705218BDC2190095E648 /* zwdsp.c in Sources */,
836F6FFB18BDC2190095E648 /* ps2_sps.c in Sources */, 836F6FFB18BDC2190095E648 /* ps2_sps.c in Sources */,
836F6F2018BDC2190095E648 /* adx_decoder.c in Sources */, 836F6F2018BDC2190095E648 /* adx_decoder.c in Sources */,
83AA7F8D2519C076004C5298 /* decode.c in Sources */,
8349A8EC1FE6253900E26435 /* blocked_vawx.c in Sources */, 8349A8EC1FE6253900E26435 /* blocked_vawx.c in Sources */,
834FE0EA215C79ED000A5D3D /* aif_asobo.c in Sources */, 834FE0EA215C79ED000A5D3D /* aif_asobo.c in Sources */,
836F700418BDC2190095E648 /* ps2_vas.c in Sources */, 836F700418BDC2190095E648 /* ps2_vas.c in Sources */,
@ -2591,6 +2639,7 @@
836F6FAF18BDC2190095E648 /* ngc_dsp_std.c in Sources */, 836F6FAF18BDC2190095E648 /* ngc_dsp_std.c in Sources */,
836F6F7118BDC2190095E648 /* ast.c in Sources */, 836F6F7118BDC2190095E648 /* ast.c in Sources */,
834FE0BF215C79A9000A5D3D /* flat.c in Sources */, 834FE0BF215C79A9000A5D3D /* flat.c in Sources */,
83AA7F7D2519C042004C5298 /* dsb.c in Sources */,
836F6F6B18BDC2190095E648 /* agsc.c in Sources */, 836F6F6B18BDC2190095E648 /* agsc.c in Sources */,
836F700E18BDC2190095E648 /* ps2_xa2.c in Sources */, 836F700E18BDC2190095E648 /* ps2_xa2.c in Sources */,
837CEB0023487F2C00E62A4A /* smk.c in Sources */, 837CEB0023487F2C00E62A4A /* smk.c in Sources */,
@ -2624,6 +2673,7 @@
837CEAFF23487F2C00E62A4A /* raw_snds.c in Sources */, 837CEAFF23487F2C00E62A4A /* raw_snds.c in Sources */,
83031EDC243C510500C3F3E0 /* vid1.c in Sources */, 83031EDC243C510500C3F3E0 /* vid1.c in Sources */,
836F700218BDC2190095E648 /* ps2_tk5.c in Sources */, 836F700218BDC2190095E648 /* ps2_tk5.c in Sources */,
83AA7F8C2519C076004C5298 /* render.c in Sources */,
83AA5D271F6E2F9C0020821C /* stm.c in Sources */, 83AA5D271F6E2F9C0020821C /* stm.c in Sources */,
831BA61D1EAC61A500CF89B0 /* ubi_raki.c in Sources */, 831BA61D1EAC61A500CF89B0 /* ubi_raki.c in Sources */,
8306B0A520984552000302D4 /* blocked_ea_wve_au00.c in Sources */, 8306B0A520984552000302D4 /* blocked_ea_wve_au00.c in Sources */,
@ -2672,7 +2722,6 @@
8306B0AB20984552000302D4 /* layered.c in Sources */, 8306B0AB20984552000302D4 /* layered.c in Sources */,
8306B0EC20984590000302D4 /* pcm_sre.c in Sources */, 8306B0EC20984590000302D4 /* pcm_sre.c in Sources */,
836F6FC818BDC2190095E648 /* pos.c in Sources */, 836F6FC818BDC2190095E648 /* pos.c in Sources */,
8350C05A1E071990009E0A93 /* ps2_svag_snk.c in Sources */,
836F6F8918BDC2190095E648 /* gca.c in Sources */, 836F6F8918BDC2190095E648 /* gca.c in Sources */,
836F6FA418BDC2190095E648 /* nds_hwas.c in Sources */, 836F6FA418BDC2190095E648 /* nds_hwas.c in Sources */,
83A21F8A201D8982000F04B9 /* fsb_encrypted.c in Sources */, 83A21F8A201D8982000F04B9 /* fsb_encrypted.c in Sources */,
@ -2747,6 +2796,7 @@
83AFABBC23795202002F3947 /* xssb.c in Sources */, 83AFABBC23795202002F3947 /* xssb.c in Sources */,
836F704818BDC2190095E648 /* xbox_ims.c in Sources */, 836F704818BDC2190095E648 /* xbox_ims.c in Sources */,
837CEAF623487F2C00E62A4A /* mzrt.c in Sources */, 837CEAF623487F2C00E62A4A /* mzrt.c in Sources */,
83AA7F832519C042004C5298 /* adp_konami.c in Sources */,
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 */,
@ -2760,6 +2810,7 @@
83AA5D1D1F6E2F800020821C /* blocked_vgs.c in Sources */, 83AA5D1D1F6E2F800020821C /* blocked_vgs.c in Sources */,
8323894A1D22419B00482226 /* clHCA.c in Sources */, 8323894A1D22419B00482226 /* clHCA.c in Sources */,
836F702E18BDC2190095E648 /* sli.c in Sources */, 836F702E18BDC2190095E648 /* sli.c in Sources */,
83AA7F822519C042004C5298 /* ktsc.c in Sources */,
836F6FDE18BDC2190095E648 /* ps2_ild.c in Sources */, 836F6FDE18BDC2190095E648 /* ps2_ild.c in Sources */,
836F703E18BDC2190095E648 /* wii_ras.c in Sources */, 836F703E18BDC2190095E648 /* wii_ras.c in Sources */,
834FE0EE215C79ED000A5D3D /* ue4opus.c in Sources */, 834FE0EE215C79ED000A5D3D /* ue4opus.c in Sources */,
@ -2797,6 +2848,7 @@
83D2007C248DDB770048BD24 /* ktsr.c in Sources */, 83D2007C248DDB770048BD24 /* ktsr.c in Sources */,
836F704E18BDC2190095E648 /* xss.c in Sources */, 836F704E18BDC2190095E648 /* xss.c in Sources */,
836F6FD118BDC2190095E648 /* ps2_bg00.c in Sources */, 836F6FD118BDC2190095E648 /* ps2_bg00.c in Sources */,
83AA7F7F2519C042004C5298 /* bsf.c in Sources */,
836F6F4118BDC2190095E648 /* blocked.c in Sources */, 836F6F4118BDC2190095E648 /* blocked.c in Sources */,
836F6F3B18BDC2190095E648 /* ws_decoder.c in Sources */, 836F6F3B18BDC2190095E648 /* ws_decoder.c in Sources */,
838BDB6E1D3B043C0022CA6F /* ffmpeg.c in Sources */, 838BDB6E1D3B043C0022CA6F /* ffmpeg.c in Sources */,

View file

@ -5,17 +5,17 @@
/* libacm 1.2 (despite what libacm.h says) from: https://github.com/markokr/libacm */ /* libacm 1.2 (despite what libacm.h says) from: https://github.com/markokr/libacm */
typedef struct { typedef struct {
STREAMFILE *streamfile; STREAMFILE* streamfile; /* reference */
int offset; int offset;
} acm_io_config; } acm_io_config;
static int acm_read_streamfile(void *ptr, int size, int n, void *arg);
static int acm_seek_streamfile(void *arg, int offset, int whence);
static int acm_get_length_streamfile(void *arg);
acm_codec_data *init_acm(STREAMFILE *streamFile, int force_channel_number) { static int acm_read_streamfile(void* ptr, int size, int n, void* arg);
static int acm_seek_streamfile(void* arg, int offset, int whence);
static int acm_get_length_streamfile(void* arg);
acm_codec_data* init_acm(STREAMFILE* sf, int force_channel_number) {
acm_codec_data* data = NULL; acm_codec_data* data = NULL;
char filename[PATH_LIMIT];
data = calloc(1,sizeof(acm_codec_data)); data = calloc(1,sizeof(acm_codec_data));
@ -24,15 +24,14 @@ acm_codec_data *init_acm(STREAMFILE *streamFile, int force_channel_number) {
data->io_config = calloc(1,sizeof(acm_io_config)); data->io_config = calloc(1,sizeof(acm_io_config));
if (!data->io_config) goto fail; if (!data->io_config) goto fail;
streamFile->get_name(streamFile,filename,sizeof(filename)); data->streamfile = reopen_streamfile(sf, 0);
data->streamfile = open_streamfile(streamFile,filename);
if (!data->streamfile) goto fail; if (!data->streamfile) goto fail;
/* Setup libacm decoder, needs read callbacks and a parameter for said callbacks */ /* Setup libacm decoder, needs read callbacks and a parameter for said callbacks */
{ {
ACMStream *handle = NULL; ACMStream* handle = NULL;
int res; int res;
acm_io_config *io_config = data->io_config; acm_io_config* io_config = data->io_config;
acm_io_callbacks io_callbacks = {0}; acm_io_callbacks io_callbacks = {0};
io_config->offset = 0; io_config->offset = 0;
@ -60,8 +59,8 @@ fail:
return NULL; return NULL;
} }
void decode_acm(acm_codec_data *data, sample * outbuf, int32_t samples_to_do, int channelspacing) { void decode_acm(acm_codec_data* data, sample_t* outbuf, int32_t samples_to_do, int channelspacing) {
ACMStream * acm = data->handle; ACMStream* acm = data->handle;
int32_t samples_read = 0; int32_t samples_read = 0;
while (samples_read < samples_to_do) { while (samples_read < samples_to_do) {
@ -79,14 +78,14 @@ void decode_acm(acm_codec_data *data, sample * outbuf, int32_t samples_to_do, in
} }
} }
void reset_acm(acm_codec_data *data) { void reset_acm(acm_codec_data* data) {
if (!data || !data->handle) if (!data || !data->handle)
return; return;
acm_seek_pcm(data->handle, 0); acm_seek_pcm(data->handle, 0);
} }
void free_acm(acm_codec_data *data) { void free_acm(acm_codec_data* data) {
if (!data) if (!data)
return; return;
@ -96,6 +95,11 @@ void free_acm(acm_codec_data *data) {
free(data); free(data);
} }
STREAMFILE* acm_get_streamfile(acm_codec_data* data) {
if (!data) return NULL;
return data->streamfile;
}
/* ******************************* */ /* ******************************* */
static int acm_read_streamfile(void *ptr, int size, int n, void *arg) { static int acm_read_streamfile(void *ptr, int size, int n, void *arg) {

View file

@ -1,7 +1,7 @@
#include "coding.h" #include "coding.h"
#include "../util.h" #include "../util.h"
void decode_adx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int32_t frame_size, coding_t coding_type) { void decode_adx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int32_t frame_size, coding_t coding_type) {
uint8_t frame[0x12] = {0}; uint8_t frame[0x12] = {0};
off_t frame_offset; off_t frame_offset;
int i, frames_in, sample_count = 0; int i, frames_in, sample_count = 0;
@ -21,12 +21,22 @@ void decode_adx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing
frame_offset = stream->offset + bytes_per_frame * frames_in; frame_offset = stream->offset + bytes_per_frame * frames_in;
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */ read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
scale = get_16bitBE(frame+0x00);
scale = get_s16be(frame+0x00);
switch(coding_type) { switch(coding_type) {
case coding_CRI_ADX: case coding_CRI_ADX:
scale = scale + 1; scale = scale + 1;
coef1 = stream->adpcm_coef[0]; coef1 = stream->adpcm_coef[0];
coef2 = stream->adpcm_coef[1]; coef2 = stream->adpcm_coef[1];
/* Detect EOF scale (0x8001) found in some ADX of any type, signals "stop decoding" (without this frame?).
* Normally num_samples stops right before it, but ADXPLAY will honor it even in the middle on a file
* (may repeat last sample buffer). Some Baroque (SAT) videos set it on file end, but num_samples goes beyond.
* Just the upper bit triggers it even in encrypted ADX (max is 0x7FFF), but the check only here just in case. */
if (frame[0] == 0x80 && frame[1] == 0x01) {
scale = 0; /* fix scaled click, maybe should just exit */
VGM_LOG("ADX: reached EOF scale\n");
}
break; break;
case coding_CRI_ADX_exp: case coding_CRI_ADX_exp:
scale = 1 << (12 - scale); scale = 1 << (12 - scale);
@ -79,6 +89,6 @@ void decode_adx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing
} }
} }
void adx_next_key(VGMSTREAMCHANNEL * stream) { void adx_next_key(VGMSTREAMCHANNEL* stream) {
stream->adx_xor = (stream->adx_xor * stream->adx_mult + stream->adx_add) & 0x7fff; stream->adx_xor = (stream->adx_xor * stream->adx_mult + stream->adx_add) & 0x7fff;
} }

View file

@ -4,6 +4,14 @@
#ifdef VGM_USE_MAIATRAC3PLUS #ifdef VGM_USE_MAIATRAC3PLUS
#include "maiatrac3plus.h" #include "maiatrac3plus.h"
struct maiatrac3plus_codec_data {
sample_t* buffer;
int channels;
int samples_discard;
void* handle;
};
maiatrac3plus_codec_data *init_at3plus() { maiatrac3plus_codec_data *init_at3plus() {
maiatrac3plus_codec_data *data = malloc(sizeof(maiatrac3plus_codec_data)); maiatrac3plus_codec_data *data = malloc(sizeof(maiatrac3plus_codec_data));

View file

@ -1,19 +1,15 @@
#include "coding.h" #include "coding.h"
#ifdef VGM_USE_ATRAC9 #ifdef VGM_USE_ATRAC9
#ifdef __MACOSX__ #include "libatrac9/libatrac9.h"
#include <libatrac9/libatrac9.h>
#else
#include "libatrac9.h"
#endif
/* opaque struct */ /* opaque struct */
struct atrac9_codec_data { struct atrac9_codec_data {
uint8_t *data_buffer; uint8_t* data_buffer;
size_t data_buffer_size; size_t data_buffer_size;
sample_t *sample_buffer; sample_t* sample_buffer;
size_t samples_filled; /* number of samples in the buffer */ size_t samples_filled; /* number of samples in the buffer */
size_t samples_used; /* number of samples extracted from the buffer */ size_t samples_used; /* number of samples extracted from the buffer */
@ -21,15 +17,15 @@ struct atrac9_codec_data {
atrac9_config config; atrac9_config config;
void *handle; /* decoder handle */ void* handle; /* decoder handle */
Atrac9CodecInfo info; /* decoder info */ Atrac9CodecInfo info; /* decoder info */
}; };
atrac9_codec_data *init_atrac9(atrac9_config *cfg) { atrac9_codec_data* init_atrac9(atrac9_config* cfg) {
int status; int status;
uint8_t config_data[4]; uint8_t config_data[4];
atrac9_codec_data *data = NULL; atrac9_codec_data* data = NULL;
data = calloc(1, sizeof(atrac9_codec_data)); data = calloc(1, sizeof(atrac9_codec_data));
if (!data) goto fail; if (!data) goto fail;
@ -69,9 +65,9 @@ fail:
return NULL; return NULL;
} }
void decode_atrac9(VGMSTREAM *vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels) { void decode_atrac9(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do, int channels) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0]; VGMSTREAMCHANNEL* stream = &vgmstream->ch[0];
atrac9_codec_data * data = vgmstream->codec_data; atrac9_codec_data* data = vgmstream->codec_data;
int samples_done = 0; int samples_done = 0;
@ -138,8 +134,7 @@ decode_fail:
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample) * channels); memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample) * channels);
} }
void reset_atrac9(VGMSTREAM *vgmstream) { void reset_atrac9(atrac9_codec_data* data) {
atrac9_codec_data *data = vgmstream->codec_data;
if (!data) return; if (!data) return;
if (!data->handle) if (!data->handle)
@ -171,11 +166,11 @@ fail:
return; /* decode calls should fail... */ return; /* decode calls should fail... */
} }
void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample) { void seek_atrac9(VGMSTREAM* vgmstream, int32_t num_sample) {
atrac9_codec_data *data = vgmstream->codec_data; atrac9_codec_data* data = vgmstream->codec_data;
if (!data) return; if (!data) return;
reset_atrac9(vgmstream); reset_atrac9(data);
/* find closest offset to desired sample, and samples to discard after that offset to reach loop */ /* find closest offset to desired sample, and samples to discard after that offset to reach loop */
{ {
@ -216,7 +211,7 @@ void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample) {
} }
void free_atrac9(atrac9_codec_data *data) { void free_atrac9(atrac9_codec_data* data) {
if (!data) return; if (!data) return;
if (data->handle) Atrac9ReleaseHandle(data->handle); if (data->handle) Atrac9ReleaseHandle(data->handle);
@ -269,7 +264,7 @@ fail:
return 0; return 0;
} }
size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data *data) { size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data* data) {
return bytes / data->info.superframeSize * (data->info.frameSamples * data->info.framesInSuperframe); return bytes / data->info.superframeSize * (data->info.frameSamples * data->info.framesInSuperframe);
} }

View file

@ -4,16 +4,16 @@
#include "celt/celt_fsb.h" #include "celt/celt_fsb.h"
#define FSB_CELT_0_06_1_VERSION 0x80000009 /* libcelt-0.6.1 */ #define FSB_CELT_0_06_1_VERSION 0x80000009 /* libcelt-0.6.1 */
#define FSB_CELT_0_11_0_VERSION 0x80000010 /* libcelt-0.6.1 */ #define FSB_CELT_0_11_0_VERSION 0x80000010 /* libcelt-0.11.0 */
#define FSB_CELT_SAMPLES_PER_FRAME 512 #define FSB_CELT_SAMPLES_PER_FRAME 512
#define FSB_CELT_INTERNAL_SAMPLE_RATE 44100 #define FSB_CELT_INTERNAL_SAMPLE_RATE 44100
#define FSB_CELT_MAX_DATA_SIZE 0x200 /* from 0x2e~0x172/1d0, all files are CBR though */ #define FSB_CELT_MAX_DATA_SIZE 0x200 /* from 0x2e~0x172/1d0, all files are CBR though */
/* opaque struct */ /* opaque struct */
struct celt_codec_data { struct celt_codec_data {
sample *buffer; sample_t* buffer;
sample *sample_buffer; sample_t* sample_buffer;
size_t samples_filled; /* number of samples in the buffer */ size_t samples_filled; /* number of samples in the buffer */
size_t samples_used; /* number of samples extracted from the buffer */ size_t samples_used; /* number of samples extracted from the buffer */
@ -31,7 +31,7 @@ struct celt_codec_data {
celt_codec_data *init_celt_fsb(int channels, celt_lib_t version) { celt_codec_data *init_celt_fsb(int channels, celt_lib_t version) {
int error = 0, lib_version = 0; int error = 0, lib_version = 0;
celt_codec_data *data = NULL; celt_codec_data* data = NULL;
data = calloc(1, sizeof(celt_codec_data)); data = calloc(1, sizeof(celt_codec_data));
@ -79,9 +79,9 @@ fail:
} }
void decode_celt_fsb(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, int channels) { void decode_celt_fsb(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do, int channels) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0]; VGMSTREAMCHANNEL* stream = &vgmstream->ch[0];
celt_codec_data * data = vgmstream->codec_data; celt_codec_data* data = vgmstream->codec_data;
int samples_done = 0; int samples_done = 0;
@ -161,8 +161,7 @@ decode_fail:
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample) * channels); memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample) * channels);
} }
void reset_celt_fsb(VGMSTREAM *vgmstream) { void reset_celt_fsb(celt_codec_data* data) {
celt_codec_data *data = vgmstream->codec_data;
if (!data) return; if (!data) return;
/* recreate decoder (mode should not change) */ /* recreate decoder (mode should not change) */
@ -195,10 +194,10 @@ fail:
} }
void seek_celt_fsb(VGMSTREAM *vgmstream, int32_t num_sample) { void seek_celt_fsb(VGMSTREAM *vgmstream, int32_t num_sample) {
celt_codec_data *data = vgmstream->codec_data; celt_codec_data* data = vgmstream->codec_data;
if (!data) return; if (!data) return;
reset_celt_fsb(vgmstream); reset_celt_fsb(data);
data->samples_to_discard = num_sample; data->samples_to_discard = num_sample;
@ -207,7 +206,7 @@ void seek_celt_fsb(VGMSTREAM *vgmstream, int32_t num_sample) {
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset; vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset;
} }
void free_celt_fsb(celt_codec_data *data) { void free_celt_fsb(celt_codec_data* data) {
if (!data) return; if (!data) return;
switch(data->version) { switch(data->version) {

View file

@ -4,188 +4,229 @@
#include "../vgmstream.h" #include "../vgmstream.h"
/* adx_decoder */ /* adx_decoder */
void decode_adx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int32_t frame_bytes, coding_t coding_type); void decode_adx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int32_t frame_bytes, coding_t coding_type);
void adx_next_key(VGMSTREAMCHANNEL * stream); void adx_next_key(VGMSTREAMCHANNEL* stream);
/* g721_decoder */ /* g721_decoder */
void decode_g721(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_g721(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void g72x_init_state(struct g72x_state *state_ptr); void g72x_init_state(struct g72x_state* state_ptr);
/* ima_decoder */ /* ima_decoder */
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first); void decode_standard_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first);
void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_3ds_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_snds_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_otns_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_wv6_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_alp_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_alp_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ffta2_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_ffta2_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_blitz_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_blitz_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_mtf_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo); void decode_mtf_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); void decode_ms_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); void decode_ref_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_xbox_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo); void decode_xbox_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
void decode_xbox_ima_mch(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_xbox_ima_mch(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_nds_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_dat4_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); void decode_rad_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_rad_ima_mono(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_apple_ima4(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_fsb_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_wwise_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_awc_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int codec_config); void decode_ubi_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int codec_config);
void decode_h4m_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, uint16_t frame_format); void decode_h4m_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, uint16_t frame_format);
void decode_cd_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
size_t ima_bytes_to_samples(size_t bytes, int channels); size_t ima_bytes_to_samples(size_t bytes, int channels);
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels); size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels);
size_t xbox_ima_bytes_to_samples(size_t bytes, int channels); size_t xbox_ima_bytes_to_samples(size_t bytes, int channels);
size_t dat4_ima_bytes_to_samples(size_t bytes, int channels); size_t dat4_ima_bytes_to_samples(size_t bytes, int channels);
size_t apple_ima4_bytes_to_samples(size_t bytes, int channels); size_t apple_ima4_bytes_to_samples(size_t bytes, int channels);
/* ngc_dsp_decoder */ /* ngc_dsp_decoder */
void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_ngc_dsp(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ngc_dsp_subint(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int interleave); void decode_ngc_dsp_subint(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int interleave);
size_t dsp_bytes_to_samples(size_t bytes, int channels); size_t dsp_bytes_to_samples(size_t bytes, int channels);
int32_t dsp_nibbles_to_samples(int32_t nibbles); int32_t dsp_nibbles_to_samples(int32_t nibbles);
void dsp_read_coefs_be(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t offset, off_t spacing); void dsp_read_coefs_be(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t offset, off_t spacing);
void dsp_read_coefs_le(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t offset, off_t spacing); void dsp_read_coefs_le(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t offset, off_t spacing);
void dsp_read_coefs(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t offset, off_t spacing, int be); void dsp_read_coefs(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t offset, off_t spacing, int be);
void dsp_read_hist_be(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t offset, off_t spacing); void dsp_read_hist_be(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t offset, off_t spacing);
void dsp_read_hist_le(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t offset, off_t spacing); void dsp_read_hist_le(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t offset, off_t spacing);
void dsp_read_hist(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t offset, off_t spacing, int be); void dsp_read_hist(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t offset, off_t spacing, int be);
/* ngc_dtk_decoder */ /* ngc_dtk_decoder */
void decode_ngc_dtk(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_ngc_dtk(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
/* ngc_afc_decoder */ /* ngc_afc_decoder */
void decode_ngc_afc(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_ngc_afc(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* vadpcm_decoder */ /* vadpcm_decoder */
void decode_vadpcm(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int order); void decode_vadpcm(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int order);
//int32_t vadpcm_bytes_to_samples(size_t bytes, int channels); //int32_t vadpcm_bytes_to_samples(size_t bytes, int channels);
void vadpcm_read_coefs_be(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t offset, int order, int entries, int ch); void vadpcm_read_coefs_be(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t offset, int order, int entries, int ch);
/* pcm_decoder */ /* pcm_decoder */
void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm16le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm16be(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian); void decode_pcm16_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm8(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm8_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm8_unsigned(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm8_sb(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_pcm4(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_pcm4_unsigned(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_ulaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_ulaw_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_alaw(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_alaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian); void decode_pcmfloat(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample); size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
/* psx_decoder */ /* psx_decoder */
void decode_psx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int is_badflags, int config); void decode_psx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int is_badflags, int config);
void decode_psx_configurable(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size, int config); void decode_psx_configurable(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size, int config);
void decode_psx_pivotal(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size); void decode_psx_pivotal(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size);
int ps_find_loop_offsets(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end); int ps_find_loop_offsets(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t* out_loop_start, int32_t* out_loop_end);
int ps_find_loop_offsets_full(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end); int ps_find_loop_offsets_full(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t* out_loop_start, int32_t* out_loop_end);
size_t ps_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int discard_empty); size_t ps_find_padding(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, size_t interleave, int discard_empty);
size_t ps_bytes_to_samples(size_t bytes, int channels); size_t ps_bytes_to_samples(size_t bytes, int channels);
size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, int channels); size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, int channels);
int ps_check_format(STREAMFILE *streamFile, off_t offset, size_t max); int ps_check_format(STREAMFILE* sf, off_t offset, size_t max);
/* psv_decoder */ /* psv_decoder */
void decode_hevag(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_hevag(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* xa_decoder */ /* xa_decoder */
void decode_xa(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_xa(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
size_t xa_bytes_to_samples(size_t bytes, int channels, int is_blocked, int is_form2); size_t xa_bytes_to_samples(size_t bytes, int channels, int is_blocked, int is_form2);
/* ea_xa_decoder */ /* ea_xa_decoder */
void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_ea_xa(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_ea_xa_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_ea_xa_int(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_ea_xa_v2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_maxis_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_maxis_xa(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
int32_t ea_xa_bytes_to_samples(size_t bytes, int channels); int32_t ea_xa_bytes_to_samples(size_t bytes, int channels);
/* ea_xas_decoder */ /* ea_xas_decoder */
void decode_ea_xas_v0(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_ea_xas_v0(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_ea_xas_v1(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_ea_xas_v1(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
/* sdx2_decoder */ /* sdx2_decoder */
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_sdx2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_sdx2_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_cbd2(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_cbd2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_cbd2_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* ws_decoder */ /* ws_decoder */
void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_ws(VGMSTREAM* vgmstream, int channel, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* acm_decoder */ /* acm_decoder */
acm_codec_data *init_acm(STREAMFILE *streamFile, int force_channel_number); acm_codec_data* init_acm(STREAMFILE* sf, int force_channel_number);
void decode_acm(acm_codec_data *data, sample * outbuf, int32_t samples_to_do, int channelspacing); void decode_acm(acm_codec_data* data, sample_t* outbuf, int32_t samples_to_do, int channelspacing);
void reset_acm(acm_codec_data *data); void reset_acm(acm_codec_data* data);
void free_acm(acm_codec_data *data); void free_acm(acm_codec_data* data);
STREAMFILE* acm_get_streamfile(acm_codec_data* data);
/* nwa_decoder */ /* nwa_decoder */
void decode_nwa(NWAData *nwa, sample *outbuf, int32_t samples_to_do); typedef struct nwa_codec_data nwa_codec_data;
nwa_codec_data* init_nwa(STREAMFILE* sf);
void decode_nwa(nwa_codec_data* data, sample_t* outbuf, int32_t samples_to_do);
void seek_nwa(nwa_codec_data *data, int32_t sample);
void reset_nwa(nwa_codec_data *data);
void free_nwa(nwa_codec_data* data);
STREAMFILE* nwa_get_streamfile(nwa_codec_data* data);
/* msadpcm_decoder */ /* msadpcm_decoder */
void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t first_sample, int32_t samples_to_do); void decode_msadpcm_stereo(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t first_sample, int32_t samples_to_do);
void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_msadpcm_mono(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_msadpcm_ck(VGMSTREAM * vgmstream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_msadpcm_ck(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
long msadpcm_bytes_to_samples(long bytes, int block_size, int channels); long msadpcm_bytes_to_samples(long bytes, int block_size, int channels);
int msadpcm_check_coefs(STREAMFILE *sf, off_t offset); int msadpcm_check_coefs(STREAMFILE* sf, off_t offset);
/* yamaha_decoder */ /* yamaha_decoder */
void decode_aica(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo); void decode_aica(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
void decode_aska(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_aska(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_nxap(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_nxap(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
size_t yamaha_bytes_to_samples(size_t bytes, int channels); size_t yamaha_bytes_to_samples(size_t bytes, int channels);
size_t aska_bytes_to_samples(size_t bytes, int channels); size_t aska_bytes_to_samples(size_t bytes, int channels);
/* tgcadpcm_decoder */ /* tgcadpcm_decoder */
void decode_tgc(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int32_t first_sample, int32_t samples_to_do); void decode_tgc(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int32_t first_sample, int32_t samples_to_do);
/* nds_procyon_decoder */ /* nds_procyon_decoder */
void decode_nds_procyon(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_nds_procyon(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* l5_555_decoder */ /* l5_555_decoder */
void decode_l5_555(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_l5_555(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* sassc_decoder */ /* sassc_decoder */
void decode_sassc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_sassc(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* lsf_decode */ /* lsf_decode */
void decode_lsf(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_lsf(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* mtaf_decoder */ /* mtaf_decoder */
void decode_mtaf(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_mtaf(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
/* mta2_decoder */ /* mta2_decoder */
void decode_mta2(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_mta2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
/* mc3_decoder */ /* mc3_decoder */
void decode_mc3(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_mc3(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
/* fadpcm_decoder */ /* fadpcm_decoder */
void decode_fadpcm(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_fadpcm(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* asf_decoder */ /* asf_decoder */
void decode_asf(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_asf(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
int32_t asf_bytes_to_samples(size_t bytes, int channels); int32_t asf_bytes_to_samples(size_t bytes, int channels);
/* dsa_decoder */ /* dsa_decoder */
void decode_dsa(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_dsa(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* xmd_decoder */ /* xmd_decoder */
void decode_xmd(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, size_t frame_size); void decode_xmd(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, size_t frame_size);
/* derf_decoder */ /* derf_decoder */
void decode_derf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_derf(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* circus_decoder */ /* circus_decoder */
typedef struct circus_codec_data circus_codec_data; typedef struct circus_codec_data circus_codec_data;
circus_codec_data* init_circus_vq(STREAMFILE* sf, off_t start, uint8_t codec, uint8_t flags); circus_codec_data* init_circus_vq(STREAMFILE* sf, off_t start, uint8_t codec, uint8_t flags);
void decode_circus_vq(circus_codec_data* data, sample_t* outbuf, int32_t samples_to_do, int channels); void decode_circus_vq(circus_codec_data* data, sample_t* outbuf, int32_t samples_to_do, int channels);
void reset_circus_vq(circus_codec_data* data); void reset_circus_vq(circus_codec_data* data);
@ -193,93 +234,205 @@ void seek_circus_vq(circus_codec_data* data, int32_t num_sample);
void free_circus_vq(circus_codec_data* data); void free_circus_vq(circus_codec_data* data);
void decode_circus_adpcm(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_circus_adpcm(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* oki_decoder */ /* oki_decoder */
void decode_pcfx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int mode); void decode_pcfx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int mode);
void decode_oki16(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_oki16(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_oki4s(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_oki4s(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
size_t oki_bytes_to_samples(size_t bytes, int channels); size_t oki_bytes_to_samples(size_t bytes, int channels);
/* ptadpcm_decoder */ /* ptadpcm_decoder */
void decode_ptadpcm(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, size_t frame_size); void decode_ptadpcm(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, size_t frame_size);
size_t ptadpcm_bytes_to_samples(size_t bytes, int channels, size_t frame_size); size_t ptadpcm_bytes_to_samples(size_t bytes, int channels, size_t frame_size);
/* ubi_adpcm_decoder */ /* ubi_adpcm_decoder */
ubi_adpcm_codec_data *init_ubi_adpcm(STREAMFILE *streamFile, off_t offset, int channels); typedef struct ubi_adpcm_codec_data ubi_adpcm_codec_data;
void decode_ubi_adpcm(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t samples_to_do);
void reset_ubi_adpcm(ubi_adpcm_codec_data *data); ubi_adpcm_codec_data* init_ubi_adpcm(STREAMFILE* sf, off_t offset, int channels);
void seek_ubi_adpcm(ubi_adpcm_codec_data *data, int32_t num_sample); void decode_ubi_adpcm(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do);
void free_ubi_adpcm(ubi_adpcm_codec_data *data); void reset_ubi_adpcm(ubi_adpcm_codec_data* data);
int ubi_adpcm_get_samples(ubi_adpcm_codec_data *data); void seek_ubi_adpcm(ubi_adpcm_codec_data* data, int32_t num_sample);
void free_ubi_adpcm(ubi_adpcm_codec_data* data);
int ubi_adpcm_get_samples(ubi_adpcm_codec_data* data);
/* imuse_decoder */ /* imuse_decoder */
typedef struct imuse_codec_data imuse_codec_data; typedef struct imuse_codec_data imuse_codec_data;
imuse_codec_data *init_imuse(STREAMFILE* sf, 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 decode_imuse(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do);
void reset_imuse(imuse_codec_data* data); void reset_imuse(imuse_codec_data* data);
void seek_imuse(imuse_codec_data* data, int32_t num_sample); void seek_imuse(imuse_codec_data* data, int32_t num_sample);
void free_imuse(imuse_codec_data* data); void free_imuse(imuse_codec_data* data);
/* ea_mt_decoder*/ /* ea_mt_decoder*/
ea_mt_codec_data *init_ea_mt(int channels, int type); typedef struct ea_mt_codec_data ea_mt_codec_data;
ea_mt_codec_data *init_ea_mt_loops(int channels, int pcm_blocks, int loop_sample, off_t *loop_offsets);
void decode_ea_mt(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel); ea_mt_codec_data* init_ea_mt(int channels, int type);
void reset_ea_mt(VGMSTREAM * vgmstream); ea_mt_codec_data* init_ea_mt_loops(int channels, int pcm_blocks, int loop_sample, off_t* loop_offsets);
void flush_ea_mt(VGMSTREAM *vgmstream); void decode_ea_mt(VGMSTREAM* vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
void seek_ea_mt(VGMSTREAM * vgmstream, int32_t num_sample); void reset_ea_mt(VGMSTREAM* vgmstream);
void free_ea_mt(ea_mt_codec_data *data, int channels); void flush_ea_mt(VGMSTREAM* vgmstream);
void seek_ea_mt(VGMSTREAM* vgmstream, int32_t num_sample);
void free_ea_mt(ea_mt_codec_data* data, int channels);
/* relic_decoder */ /* relic_decoder */
typedef struct relic_codec_data relic_codec_data;
relic_codec_data* init_relic(int channels, int bitrate, int codec_rate); relic_codec_data* init_relic(int channels, int bitrate, int codec_rate);
void decode_relic(VGMSTREAMCHANNEL* stream, relic_codec_data* data, sample_t* outbuf, int32_t samples_to_do); void decode_relic(VGMSTREAMCHANNEL* stream, relic_codec_data* data, sample_t* outbuf, int32_t samples_to_do);
void reset_relic(relic_codec_data* data); void reset_relic(relic_codec_data* data);
void seek_relic(relic_codec_data* data, int32_t num_sample); void seek_relic(relic_codec_data* data, int32_t num_sample);
void free_relic(relic_codec_data* data); void free_relic(relic_codec_data* data);
/* hca_decoder */ /* hca_decoder */
hca_codec_data *init_hca(STREAMFILE *streamFile); typedef struct hca_codec_data hca_codec_data;
void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do);
void reset_hca(hca_codec_data * data); hca_codec_data* init_hca(STREAMFILE* sf);
void loop_hca(hca_codec_data * data, int32_t num_sample); void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do);
void free_hca(hca_codec_data * data); void reset_hca(hca_codec_data* data);
int test_hca_key(hca_codec_data * data, unsigned long long keycode); void loop_hca(hca_codec_data* data, int32_t num_sample);
void free_hca(hca_codec_data* data);
int test_hca_key(hca_codec_data* data, unsigned long long keycode);
void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode);
clHCA_stInfo* hca_get_info(hca_codec_data* data);
STREAMFILE* hca_get_streamfile(hca_codec_data* data);
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
/* ogg_vorbis_decoder */ /* ogg_vorbis_decoder */
ogg_vorbis_codec_data* init_ogg_vorbis(STREAMFILE *sf, off_t start, off_t size, ogg_vorbis_io *io); typedef struct ogg_vorbis_codec_data ogg_vorbis_codec_data;
void decode_ogg_vorbis(ogg_vorbis_codec_data *data, sample_t *outbuf, int32_t samples_to_do, int channels); typedef struct { //todo simplify
void reset_ogg_vorbis(VGMSTREAM *vgmstream); STREAMFILE *streamfile;
void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample); ogg_int64_t start; /* file offset where the Ogg starts */
void free_ogg_vorbis(ogg_vorbis_codec_data *data); ogg_int64_t offset; /* virtual offset, from 0 to size */
ogg_int64_t size; /* virtual size of the Ogg */
/* decryption setup */
void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource);
uint8_t scd_xor;
off_t scd_xor_length;
uint32_t xor_value;
} ogg_vorbis_io;
ogg_vorbis_codec_data* init_ogg_vorbis(STREAMFILE* sf, off_t start, off_t size, ogg_vorbis_io* io);
void decode_ogg_vorbis(ogg_vorbis_codec_data* data, sample_t* outbuf, int32_t samples_to_do, int channels);
void reset_ogg_vorbis(VGMSTREAM* vgmstream);
void seek_ogg_vorbis(ogg_vorbis_codec_data* data, int32_t num_sample);
void free_ogg_vorbis(ogg_vorbis_codec_data* data);
int ogg_vorbis_get_comment(ogg_vorbis_codec_data* data, const char** comment);
void ogg_vorbis_get_info(ogg_vorbis_codec_data* data, int* p_channels, int* p_sample_rate);
void ogg_vorbis_get_samples(ogg_vorbis_codec_data* data, int* p_samples);
void ogg_vorbis_set_disable_reordering(ogg_vorbis_codec_data* data, int set);
STREAMFILE* ogg_vorbis_get_streamfile(ogg_vorbis_codec_data* data);
int ogg_vorbis_get_comment(ogg_vorbis_codec_data *data, const char **comment);
void ogg_vorbis_get_info(ogg_vorbis_codec_data *data, int *p_channels, int *p_sample_rate);
void ogg_vorbis_get_samples(ogg_vorbis_codec_data *data, int *p_samples);
void ogg_vorbis_set_disable_reordering(ogg_vorbis_codec_data *data, int set);
STREAMFILE* ogg_vorbis_get_streamfile(ogg_vorbis_codec_data *data);
/* vorbis_custom_decoder */ /* vorbis_custom_decoder */
vorbis_custom_codec_data *init_vorbis_custom(STREAMFILE *streamfile, off_t start_offset, vorbis_custom_t type, vorbis_custom_config * config); typedef struct vorbis_custom_codec_data vorbis_custom_codec_data;
void decode_vorbis_custom(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels);
void reset_vorbis_custom(VGMSTREAM *vgmstream); typedef enum {
void seek_vorbis_custom(VGMSTREAM *vgmstream, int32_t num_sample); VORBIS_FSB, /* FMOD FSB: simplified/external setup packets, custom packet headers */
void free_vorbis_custom(vorbis_custom_codec_data *data); VORBIS_WWISE, /* Wwise WEM: many variations (custom setup, headers and data) */
VORBIS_OGL, /* Shin'en OGL: custom packet headers */
VORBIS_SK, /* Silicon Knights AUD: "OggS" replaced by "SK" */
VORBIS_VID1, /* Neversoft VID1: custom packet blocks/headers */
} vorbis_custom_t;
/* config for Wwise Vorbis (3 types for flexibility though not all combinations exist) */
typedef enum { WWV_HEADER_TRIAD, WWV_FULL_SETUP, WWV_INLINE_CODEBOOKS, WWV_EXTERNAL_CODEBOOKS, WWV_AOTUV603_CODEBOOKS } wwise_setup_t;
typedef enum { WWV_TYPE_8, WWV_TYPE_6, WWV_TYPE_2 } wwise_header_t;
typedef enum { WWV_STANDARD, WWV_MODIFIED } wwise_packet_t;
typedef struct {
/* to reconstruct init packets */
int channels;
int sample_rate;
int blocksize_0_exp;
int blocksize_1_exp;
uint32_t setup_id; /* external setup */
int big_endian; /* flag */
/* Wwise Vorbis config */
wwise_setup_t setup_type;
wwise_header_t header_type;
wwise_packet_t packet_type;
/* output (kinda ugly here but to simplify) */
off_t data_start_offset;
} vorbis_custom_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 reset_vorbis_custom(VGMSTREAM* vgmstream);
void seek_vorbis_custom(VGMSTREAM* vgmstream, int32_t num_sample);
void free_vorbis_custom(vorbis_custom_codec_data* data);
#endif #endif
#ifdef VGM_USE_MPEG #ifdef VGM_USE_MPEG
/* mpeg_decoder */ /* mpeg_decoder */
mpeg_codec_data *init_mpeg(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels); typedef struct mpeg_codec_data mpeg_codec_data;
mpeg_codec_data *init_mpeg_custom(STREAMFILE *streamFile, off_t start_offset, coding_t *coding_type, int channels, mpeg_custom_t custom_type, mpeg_custom_config *config);
void decode_mpeg(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels);
void reset_mpeg(VGMSTREAM *vgmstream);
void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample);
void free_mpeg(mpeg_codec_data *data);
void flush_mpeg(mpeg_codec_data * data);
long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data *data); /* Custom MPEG modes, mostly differing in the data layout */
typedef enum {
MPEG_STANDARD, /* 1 stream */
MPEG_AHX, /* 1 stream with false frame headers */
MPEG_XVAG, /* N streams of fixed interleave (frame-aligned, several data-frames of fixed size) */
MPEG_FSB, /* N streams of 1 data-frame+padding (=interleave) */
MPEG_P3D, /* N streams of fixed interleave (not frame-aligned) */
MPEG_SCD, /* N streams of fixed interleave (not frame-aligned) */
MPEG_EA, /* 1 stream (maybe N streams in absolute offsets?) */
MPEG_EAL31, /* EALayer3 v1 (SCHl), custom frames with v1 header */
MPEG_EAL31b, /* EALayer3 v1 (SNS), custom frames with v1 header + minor changes */
MPEG_EAL32P, /* EALayer3 v2 "PCM", custom frames with v2 header + bigger PCM blocks? */
MPEG_EAL32S, /* EALayer3 v2 "Spike", custom frames with v2 header + smaller PCM blocks? */
MPEG_LYN, /* N streams of fixed interleave */
MPEG_AWC, /* N streams in block layout (music) or absolute offsets (sfx) */
MPEG_EAMP3 /* custom frame header + MPEG frame + PCM blocks */
} mpeg_custom_t;
/* config for the above modes */
typedef struct {
int channels; /* max channels */
int fsb_padding; /* fsb padding mode */
int chunk_size; /* size of a data portion */
int data_size; /* playable size */
int interleave; /* size of stream interleave */
int encryption; /* encryption mode */
int big_endian;
int skip_samples;
/* for AHX */
int cri_type;
uint16_t cri_key1;
uint16_t cri_key2;
uint16_t cri_key3;
} mpeg_custom_config;
mpeg_codec_data* init_mpeg(STREAMFILE* sf, off_t start_offset, coding_t *coding_type, int channels);
mpeg_codec_data* init_mpeg_custom(STREAMFILE* sf, off_t start_offset, coding_t* coding_type, int channels, mpeg_custom_t custom_type, mpeg_custom_config* config);
void decode_mpeg(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do, int channels);
void reset_mpeg(mpeg_codec_data* data);
void seek_mpeg(VGMSTREAM* vgmstream, int32_t num_sample);
void free_mpeg(mpeg_codec_data* data);
void flush_mpeg(mpeg_codec_data* data);
int mpeg_get_sample_rate(mpeg_codec_data* data);
long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data* data);
#endif #endif
#ifdef VGM_USE_G7221 #ifdef VGM_USE_G7221
/* g7221_decoder */ /* g7221_decoder */
typedef struct g7221_codec_data g7221_codec_data;
g7221_codec_data* init_g7221(int channel_count, int frame_size); g7221_codec_data* init_g7221(int channel_count, int frame_size);
void decode_g7221(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t samples_to_do, int channel); void decode_g7221(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t samples_to_do, int channel);
void reset_g7221(g7221_codec_data* data); void reset_g7221(g7221_codec_data* data);
@ -288,73 +441,93 @@ void set_key_g7221(g7221_codec_data* data, const uint8_t* key);
int test_key_g7221(g7221_codec_data* data, off_t start, STREAMFILE* sf); int test_key_g7221(g7221_codec_data* data, off_t start, STREAMFILE* sf);
#endif #endif
#ifdef VGM_USE_G719 #ifdef VGM_USE_G719
/* g719_decoder */ /* g719_decoder */
g719_codec_data *init_g719(int channel_count, int frame_size); typedef struct g719_codec_data g719_codec_data;
void decode_g719(VGMSTREAM *vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
void reset_g719(g719_codec_data * data, int channels); g719_codec_data* init_g719(int channel_count, int frame_size);
void free_g719(g719_codec_data * data, int channels); void decode_g719(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t samples_to_do, int channel);
void reset_g719(g719_codec_data* data, int channels);
void free_g719(g719_codec_data* data, int channels);
#endif #endif
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
/* mp4_aac_decoder */ /* mp4_aac_decoder */
void decode_mp4_aac(mp4_aac_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels); void decode_mp4_aac(mp4_aac_codec_data* data, sample * outbuf, int32_t samples_to_do, int channels);
void reset_mp4_aac(VGMSTREAM *vgmstream); void reset_mp4_aac(VGMSTREAM* vgmstream);
void seek_mp4_aac(VGMSTREAM *vgmstream, int32_t num_sample); void seek_mp4_aac(VGMSTREAM* vgmstream, int32_t num_sample);
void free_mp4_aac(mp4_aac_codec_data * data); void free_mp4_aac(mp4_aac_codec_data* data);
#endif #endif
#ifdef VGM_USE_MAIATRAC3PLUS #ifdef VGM_USE_MAIATRAC3PLUS
/* at3plus_decoder */ /* at3plus_decoder */
maiatrac3plus_codec_data *init_at3plus(); typedef struct maiatrac3plus_codec_data maiatrac3plus_codec_data;
void decode_at3plus(VGMSTREAM *vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
void reset_at3plus(VGMSTREAM *vgmstream); maiatrac3plus_codec_data* init_at3plus();
void seek_at3plus(VGMSTREAM *vgmstream, int32_t num_sample); void decode_at3plus(VGMSTREAM* vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
void free_at3plus(maiatrac3plus_codec_data *data); void reset_at3plus(VGMSTREAM* vgmstream);
void seek_at3plus(VGMSTREAM* vgmstream, int32_t num_sample);
void free_at3plus(maiatrac3plus_codec_data* data);
#endif #endif
#ifdef VGM_USE_ATRAC9 #ifdef VGM_USE_ATRAC9
/* atrac9_decoder */ /* atrac9_decoder */
atrac9_codec_data *init_atrac9(atrac9_config *cfg); typedef struct {
void decode_atrac9(VGMSTREAM *vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels); int channels; /* to detect weird multichannel */
void reset_atrac9(VGMSTREAM *vgmstream); uint32_t config_data; /* ATRAC9 config header */
void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample); int encoder_delay; /* initial samples to discard */
void free_atrac9(atrac9_codec_data *data); } atrac9_config;
size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data *data); typedef struct atrac9_codec_data atrac9_codec_data;
atrac9_codec_data* init_atrac9(atrac9_config* cfg);
void decode_atrac9(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do, int channels);
void reset_atrac9(atrac9_codec_data* data);
void seek_atrac9(VGMSTREAM* vgmstream, int32_t num_sample);
void free_atrac9(atrac9_codec_data* data);
size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data* data);
size_t atrac9_bytes_to_samples_cfg(size_t bytes, uint32_t atrac9_config); size_t atrac9_bytes_to_samples_cfg(size_t bytes, uint32_t atrac9_config);
#endif #endif
#ifdef VGM_USE_CELT #ifdef VGM_USE_CELT
/* celt_fsb_decoder */ /* celt_fsb_decoder */
celt_codec_data *init_celt_fsb(int channels, celt_lib_t version); typedef enum { CELT_0_06_1,CELT_0_11_0} celt_lib_t;
void decode_celt_fsb(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, int channels); typedef struct celt_codec_data celt_codec_data;
void reset_celt_fsb(VGMSTREAM *vgmstream);
void seek_celt_fsb(VGMSTREAM *vgmstream, int32_t num_sample); celt_codec_data* init_celt_fsb(int channels, celt_lib_t version);
void free_celt_fsb(celt_codec_data *data); void decode_celt_fsb(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do, int channels);
void reset_celt_fsb(celt_codec_data* data);
void seek_celt_fsb(VGMSTREAM* vgmstream, int32_t num_sample);
void free_celt_fsb(celt_codec_data* data);
#endif #endif
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
/* ffmpeg_decoder */ /* ffmpeg_decoder */
ffmpeg_codec_data *init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size); ffmpeg_codec_data* init_ffmpeg_offset(STREAMFILE* sf, uint64_t start, uint64_t size);
ffmpeg_codec_data *init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size); ffmpeg_codec_data* init_ffmpeg_header_offset(STREAMFILE* sf, uint8_t* header, uint64_t header_size, uint64_t start, uint64_t size);
ffmpeg_codec_data *init_ffmpeg_header_offset_subsong(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size, int target_subsong); ffmpeg_codec_data* init_ffmpeg_header_offset_subsong(STREAMFILE* sf, uint8_t* header, uint64_t header_size, uint64_t start, uint64_t size, int target_subsong);
void decode_ffmpeg(VGMSTREAM *stream, sample_t * outbuf, int32_t samples_to_do, int channels); void decode_ffmpeg(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do, int channels);
void reset_ffmpeg(VGMSTREAM *vgmstream); void reset_ffmpeg(ffmpeg_codec_data* data);
void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample); void seek_ffmpeg(ffmpeg_codec_data* data, int32_t num_sample);
void free_ffmpeg(ffmpeg_codec_data *data); void free_ffmpeg(ffmpeg_codec_data* data);
void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples); void ffmpeg_set_skip_samples(ffmpeg_codec_data* data, int skip_samples);
uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data * data); uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data* data);
void ffmpeg_set_channel_remapping(ffmpeg_codec_data * data, int *channels_remap); void ffmpeg_set_channel_remapping(ffmpeg_codec_data* data, int* channels_remap);
const char* ffmpeg_get_codec_name(ffmpeg_codec_data * data); const char* ffmpeg_get_codec_name(ffmpeg_codec_data* data);
void ffmpeg_set_force_seek(ffmpeg_codec_data * data); void ffmpeg_set_force_seek(ffmpeg_codec_data* data);
const char* ffmpeg_get_metadata_value(ffmpeg_codec_data* data, const char* key); const char* ffmpeg_get_metadata_value(ffmpeg_codec_data* data, const char* key);
STREAMFILE* ffmpeg_get_streamfile(ffmpeg_codec_data* data);
/* ffmpeg_decoder_utils.c (helper-things) */ /* ffmpeg_decoder_utils.c (helper-things) */
ffmpeg_codec_data * init_ffmpeg_atrac3_raw(STREAMFILE *sf, off_t offset, size_t data_size, int sample_count, int channels, int sample_rate, int block_align, int encoder_delay); ffmpeg_codec_data* init_ffmpeg_atrac3_raw(STREAMFILE* sf, off_t offset, size_t data_size, int sample_count, int channels, int sample_rate, int block_align, int encoder_delay);
ffmpeg_codec_data * init_ffmpeg_atrac3_riff(STREAMFILE *sf, off_t offset, int* out_samples); ffmpeg_codec_data* init_ffmpeg_atrac3_riff(STREAMFILE* sf, off_t offset, int* out_samples);
/* ffmpeg_decoder_custom_opus.c (helper-things) */ /* ffmpeg_decoder_custom_opus.c (helper-things) */
@ -368,28 +541,28 @@ typedef struct {
int channel_mapping[8]; int channel_mapping[8];
} opus_config; } opus_config;
ffmpeg_codec_data * init_ffmpeg_switch_opus_config(STREAMFILE *streamFile, off_t start_offset, size_t data_size, opus_config* cfg); ffmpeg_codec_data* init_ffmpeg_switch_opus_config(STREAMFILE* sf, off_t start_offset, size_t data_size, opus_config* cfg);
ffmpeg_codec_data * init_ffmpeg_switch_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate); ffmpeg_codec_data* init_ffmpeg_switch_opus(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
ffmpeg_codec_data * init_ffmpeg_ue4_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate); ffmpeg_codec_data* init_ffmpeg_ue4_opus(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
ffmpeg_codec_data * init_ffmpeg_ea_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate); ffmpeg_codec_data* init_ffmpeg_ea_opus(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
ffmpeg_codec_data * init_ffmpeg_x_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate); ffmpeg_codec_data* init_ffmpeg_x_opus(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
size_t switch_opus_get_samples(off_t offset, size_t stream_size, STREAMFILE *streamFile); size_t switch_opus_get_samples(off_t offset, size_t stream_size, STREAMFILE* sf);
size_t switch_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile); size_t switch_opus_get_encoder_delay(off_t offset, STREAMFILE* sf);
size_t ue4_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile); size_t ue4_opus_get_encoder_delay(off_t offset, STREAMFILE* sf);
size_t ea_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile); size_t ea_opus_get_encoder_delay(off_t offset, STREAMFILE* sf);
#endif #endif
/* coding_utils */ /* coding_utils */
int ffmpeg_fmt_chunk_swap_endian(uint8_t * chunk, size_t chunk_size, uint16_t codec); int ffmpeg_fmt_chunk_swap_endian(uint8_t* chunk, size_t chunk_size, uint16_t codec);
int ffmpeg_make_riff_atrac3plus(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int encoder_delay); int ffmpeg_make_riff_atrac3plus(uint8_t* buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int encoder_delay);
int ffmpeg_make_riff_xma1(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int stream_mode); int ffmpeg_make_riff_xma1(uint8_t* buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int stream_mode);
int ffmpeg_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_count, int block_size); int ffmpeg_make_riff_xma2(uint8_t* buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_count, int block_size);
int ffmpeg_make_riff_xma_from_fmt_chunk(uint8_t * buf, size_t buf_size, off_t fmt_offset, size_t fmt_size, size_t data_size, STREAMFILE *streamFile, int big_endian); int ffmpeg_make_riff_xma_from_fmt_chunk(uint8_t* buf, size_t buf_size, off_t fmt_offset, size_t fmt_size, size_t data_size, STREAMFILE* sf, int big_endian);
int ffmpeg_make_riff_xma2_from_xma2_chunk(uint8_t * buf, size_t buf_size, off_t xma2_offset, size_t xma2_size, size_t data_size, STREAMFILE *streamFile); int ffmpeg_make_riff_xma2_from_xma2_chunk(uint8_t* buf, size_t buf_size, off_t xma2_offset, size_t xma2_size, size_t data_size, STREAMFILE* sf);
int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t data_size, int channels, int sample_rate, int avg_bps, int block_align); int ffmpeg_make_riff_xwma(uint8_t* buf, size_t buf_size, int codec, size_t data_size, int channels, int sample_rate, int avg_bps, int block_align);
/* MS audio format's sample info (struct to avoid passing so much stuff, separate for reusing) */ /* MS audio format's sample info (struct to avoid passing so much stuff, separate for reusing) */
typedef struct { typedef struct {
@ -413,39 +586,26 @@ typedef struct {
int32_t loop_start_sample; int32_t loop_start_sample;
int32_t loop_end_sample; int32_t loop_end_sample;
} ms_sample_data; } ms_sample_data;
void xma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile); void xma_get_samples(ms_sample_data* msd, STREAMFILE* sf);
void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags); void wmapro_get_samples(ms_sample_data* msd, STREAMFILE* sf, int block_align, int sample_rate, uint32_t decode_flags);
void wma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags); void wma_get_samples(ms_sample_data* msd, STREAMFILE* sf, int block_align, int sample_rate, uint32_t decode_flags);
void xma1_parse_fmt_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * channels, int * sample_rate, int * loop_flag, int32_t * loop_start_b, int32_t * loop_end_b, int32_t * loop_subframe, int be); void xma1_parse_fmt_chunk(STREAMFILE* sf, off_t chunk_offset, int* channels, int* sample_rate, int* loop_flag, int32_t* loop_start_b, int32_t* loop_end_b, int32_t* loop_subframe, int be);
void xma2_parse_fmt_chunk_extra(STREAMFILE *streamFile, off_t chunk_offset, int * loop_flag, int32_t * out_num_samples, int32_t * out_loop_start_sample, int32_t * out_loop_end_sample, int be); void xma2_parse_fmt_chunk_extra(STREAMFILE* sf, off_t chunk_offset, int* loop_flag, int32_t* out_num_samples, int32_t* out_loop_start_sample, int32_t* out_loop_end_sample, int be);
void xma2_parse_xma2_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * channels, int * sample_rate, int * loop_flag, int32_t * num_samples, int32_t * loop_start_sample, int32_t * loop_end_sample); void xma2_parse_xma2_chunk(STREAMFILE* sf, off_t chunk_offset, int* channels, int* sample_rate, int* loop_flag, int32_t* num_samples, int32_t* loop_start_sample, int32_t* loop_end_sample);
void xma_fix_raw_samples(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples); void xma_fix_raw_samples(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples);
void xma_fix_raw_samples_hb(VGMSTREAM *vgmstream, STREAMFILE *headerFile, STREAMFILE *bodyFile, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples); void xma_fix_raw_samples_hb(VGMSTREAM* vgmstream, STREAMFILE* sf_head, STREAMFILE* sf_body, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples);
void xma_fix_raw_samples_ch(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, int channel_per_stream, int fix_num_samples, int fix_loop_samples); void xma_fix_raw_samples_ch(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t stream_offset, size_t stream_size, int channel_per_stream, int fix_num_samples, int fix_loop_samples);
size_t atrac3_bytes_to_samples(size_t bytes, int full_block_align); size_t atrac3_bytes_to_samples(size_t bytes, int full_block_align);
size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align); size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align);
size_t ac3_bytes_to_samples(size_t bytes, int full_block_align, int channels); size_t ac3_bytes_to_samples(size_t bytes, int full_block_align, int channels);
size_t aac_get_samples(STREAMFILE *streamFile, off_t start_offset, size_t bytes); size_t aac_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes);
size_t mpeg_get_samples(STREAMFILE *streamFile, off_t start_offset, size_t bytes); size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes);
/* An internal struct to pass around and simulate a bitstream. */
typedef enum { BITSTREAM_MSF, BITSTREAM_VORBIS } vgm_bitstream_t;
typedef struct {
uint8_t * buf; /* buffer to read/write*/
size_t bufsize; /* max size of the buffer */
off_t b_off; /* current offset in bits inside the buffer */
vgm_bitstream_t mode; /* read/write modes */
} vgm_bitstream;
int r_bits(vgm_bitstream * ib, int num_bits, uint32_t * value);
int w_bits(vgm_bitstream * ob, int num_bits, uint32_t value);
/* helper to pass a wrapped, clamped, fake extension-ed, SF to another meta */ /* helper to pass a wrapped, clamped, fake extension-ed, SF to another meta */
STREAMFILE* setup_subfile_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* extension); STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, off_t subfile_offset, size_t subfile_size, const char* extension);
#endif /*_CODING_H*/ #endif /*_CODING_H*/

View file

@ -1012,152 +1012,6 @@ size_t aac_get_samples(STREAMFILE *streamFile, off_t start_offset, size_t bytes)
return frames * samples_per_frame; return frames * samples_per_frame;
} }
/* ******************************************** */
/* BITSTREAM */
/* ******************************************** */
/* Read bits (max 32) from buf and update the bit offset. Vorbis packs values in LSB order and byte by byte.
* (ex. from 2 bytes 00100111 00000001 we can could read 4b=0111 and 6b=010010, 6b=remainder (second value is split into the 2nd byte) */
static int r_bits_vorbis(vgm_bitstream * ib, int num_bits, uint32_t * value) {
off_t off, pos;
int i, bit_buf, bit_val;
if (num_bits == 0) return 1;
if (num_bits > 32 || num_bits < 0 || ib->b_off + num_bits > ib->bufsize*8) goto fail;
*value = 0; /* set all bits to 0 */
off = ib->b_off / 8; /* byte offset */
pos = ib->b_off % 8; /* bit sub-offset */
for (i = 0; i < num_bits; i++) {
bit_buf = (1U << pos) & 0xFF; /* bit check for buf */
bit_val = (1U << i); /* bit to set in value */
if (ib->buf[off] & bit_buf) /* is bit in buf set? */
*value |= bit_val; /* set bit */
pos++; /* new byte starts */
if (pos%8 == 0) {
pos = 0;
off++;
}
}
ib->b_off += num_bits;
return 1;
fail:
return 0;
}
/* Write bits (max 32) to buf and update the bit offset. Vorbis packs values in LSB order and byte by byte.
* (ex. writing 1101011010 from b_off 2 we get 01101011 00001101 (value split, and 11 in the first byte skipped)*/
static int w_bits_vorbis(vgm_bitstream * ob, int num_bits, uint32_t value) {
off_t off, pos;
int i, bit_val, bit_buf;
if (num_bits == 0) return 1;
if (num_bits > 32 || num_bits < 0 || ob->b_off + num_bits > ob->bufsize*8) goto fail;
off = ob->b_off / 8; /* byte offset */
pos = ob->b_off % 8; /* bit sub-offset */
for (i = 0; i < num_bits; i++) {
bit_val = (1U << i); /* bit check for value */
bit_buf = (1U << pos) & 0xFF; /* bit to set in buf */
if (value & bit_val) /* is bit in val set? */
ob->buf[off] |= bit_buf; /* set bit */
else
ob->buf[off] &= ~bit_buf; /* unset bit */
pos++; /* new byte starts */
if (pos%8 == 0) {
pos = 0;
off++;
}
}
ob->b_off += num_bits;
return 1;
fail:
return 0;
}
/* Read bits (max 32) from buf and update the bit offset. Order is BE (MSF). */
static int r_bits_msf(vgm_bitstream * ib, int num_bits, uint32_t * value) {
off_t off, pos;
int i, bit_buf, bit_val;
if (num_bits == 0) return 1;
if (num_bits > 32 || num_bits < 0 || ib->b_off + num_bits > ib->bufsize*8) goto fail;
*value = 0; /* set all bits to 0 */
off = ib->b_off / 8; /* byte offset */
pos = ib->b_off % 8; /* bit sub-offset */
for (i = 0; i < num_bits; i++) {
bit_buf = (1U << (8-1-pos)) & 0xFF; /* bit check for buf */
bit_val = (1U << (num_bits-1-i)); /* bit to set in value */
if (ib->buf[off] & bit_buf) /* is bit in buf set? */
*value |= bit_val; /* set bit */
pos++;
if (pos%8 == 0) { /* new byte starts */
pos = 0;
off++;
}
}
ib->b_off += num_bits;
return 1;
fail:
return 0;
}
/* Write bits (max 32) to buf and update the bit offset. Order is BE (MSF). */
static int w_bits_msf(vgm_bitstream * ob, int num_bits, uint32_t value) {
off_t off, pos;
int i, bit_val, bit_buf;
if (num_bits == 0) return 1;
if (num_bits > 32 || num_bits < 0 || ob->b_off + num_bits > ob->bufsize*8) goto fail;
off = ob->b_off / 8; /* byte offset */
pos = ob->b_off % 8; /* bit sub-offset */
for (i = 0; i < num_bits; i++) {
bit_val = (1U << (num_bits-1-i)); /* bit check for value */
bit_buf = (1U << (8-1-pos)) & 0xFF; /* bit to set in buf */
if (value & bit_val) /* is bit in val set? */
ob->buf[off] |= bit_buf; /* set bit */
else
ob->buf[off] &= ~bit_buf; /* unset bit */
pos++;
if (pos%8 == 0) { /* new byte starts */
pos = 0;
off++;
}
}
ob->b_off += num_bits;
return 1;
fail:
return 0;
}
int r_bits(vgm_bitstream * ib, int num_bits, uint32_t * value) {
if (ib->mode == BITSTREAM_VORBIS)
return r_bits_vorbis(ib,num_bits,value);
else
return r_bits_msf(ib,num_bits,value);
}
int w_bits(vgm_bitstream * ob, int num_bits, uint32_t value) {
if (ob->mode == BITSTREAM_VORBIS)
return w_bits_vorbis(ob,num_bits,value);
else
return w_bits_msf(ob,num_bits,value);
}
/* ******************************************** */ /* ******************************************** */
/* CUSTOM STREAMFILES */ /* CUSTOM STREAMFILES */
/* ******************************************** */ /* ******************************************** */

View file

@ -8,11 +8,8 @@
static volatile int g_ffmpeg_initialized = 0; static volatile int g_ffmpeg_initialized = 0;
static void free_ffmpeg_config(ffmpeg_codec_data *data); static void free_ffmpeg_config(ffmpeg_codec_data* data);
static int init_ffmpeg_config(ffmpeg_codec_data * data, int target_subsong, int reset); static int init_ffmpeg_config(ffmpeg_codec_data* data, int target_subsong, int reset);
static void reset_ffmpeg_internal(ffmpeg_codec_data *data);
static void seek_ffmpeg_internal(ffmpeg_codec_data *data, int32_t num_sample);
/* ******************************************** */ /* ******************************************** */
/* INTERNAL UTILS */ /* INTERNAL UTILS */
@ -34,7 +31,7 @@ static void g_init_ffmpeg() {
} }
} }
static void remap_audio(sample_t *outbuf, int sample_count, int channels, int *channel_mappings) { static void remap_audio(sample_t* outbuf, int sample_count, int channels, int* channel_mappings) {
int ch_from,ch_to,s; int ch_from,ch_to,s;
sample_t temp; sample_t temp;
for (s = 0; s < sample_count; s++) { for (s = 0; s < sample_count; s++) {
@ -65,7 +62,7 @@ static void remap_audio(sample_t *outbuf, int sample_count, int channels, int *c
* first frame/packet and sets up index to timestamp 0. This ensures faulty demuxers will seek to 0 correctly. * first frame/packet and sets up index to timestamp 0. This ensures faulty demuxers will seek to 0 correctly.
* Some formats may not seek to 0 even with this, though. * Some formats may not seek to 0 even with this, though.
*/ */
static int init_seek(ffmpeg_codec_data * data) { static int init_seek(ffmpeg_codec_data* data) {
int ret, ts_index, packet_count = 0; int ret, ts_index, packet_count = 0;
int64_t ts = 0; /* seek timestamp */ int64_t ts = 0; /* seek timestamp */
int64_t pos = 0; /* data offset */ int64_t pos = 0; /* data offset */
@ -161,8 +158,8 @@ fail:
/* ******************************************** */ /* ******************************************** */
/* AVIO callback: read stream, handling custom data */ /* AVIO callback: read stream, handling custom data */
static int ffmpeg_read(void *opaque, uint8_t *buf, int read_size) { static int ffmpeg_read(void* opaque, uint8_t* buf, int read_size) {
ffmpeg_codec_data *data = (ffmpeg_codec_data *) opaque; ffmpeg_codec_data* data = opaque;
int bytes = 0; int bytes = 0;
int max_to_copy = 0; int max_to_copy = 0;
@ -196,8 +193,8 @@ static int ffmpeg_read(void *opaque, uint8_t *buf, int read_size) {
} }
/* AVIO callback: seek stream, handling custom data */ /* AVIO callback: seek stream, handling custom data */
static int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) { static int64_t ffmpeg_seek(void* opaque, int64_t offset, int whence) {
ffmpeg_codec_data *data = (ffmpeg_codec_data *) opaque; ffmpeg_codec_data* data = opaque;
int ret = 0; int ret = 0;
/* get cache'd size */ /* get cache'd size */
@ -243,12 +240,12 @@ static int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) {
/* MAIN INIT/DECODER */ /* MAIN INIT/DECODER */
/* ******************************************** */ /* ******************************************** */
ffmpeg_codec_data * init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size) { ffmpeg_codec_data* init_ffmpeg_offset(STREAMFILE* sf, uint64_t start, uint64_t size) {
return init_ffmpeg_header_offset(streamFile, NULL,0, start,size); return init_ffmpeg_header_offset(sf, NULL,0, start,size);
} }
ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size) { ffmpeg_codec_data* init_ffmpeg_header_offset(STREAMFILE* sf, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size) {
return init_ffmpeg_header_offset_subsong(streamFile, header, header_size, start, size, 0); return init_ffmpeg_header_offset_subsong(sf, header, header_size, start, size, 0);
} }
@ -261,8 +258,8 @@ ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t *
* NULL header can used given if the stream has internal data recognized by FFmpeg at offset. * NULL header can used given if the stream has internal data recognized by FFmpeg at offset.
* Stream index can be passed if the file has multiple audio streams that FFmpeg can demux (1=first). * Stream index can be passed if the file has multiple audio streams that FFmpeg can demux (1=first).
*/ */
ffmpeg_codec_data * init_ffmpeg_header_offset_subsong(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size, int target_subsong) { ffmpeg_codec_data* init_ffmpeg_header_offset_subsong(STREAMFILE* sf, uint8_t* header, uint64_t header_size, uint64_t start, uint64_t size, int target_subsong) {
ffmpeg_codec_data * data = NULL; ffmpeg_codec_data* data = NULL;
int errcode; int errcode;
@ -270,9 +267,9 @@ ffmpeg_codec_data * init_ffmpeg_header_offset_subsong(STREAMFILE *streamFile, ui
if ((header && !header_size) || (!header && header_size)) if ((header && !header_size) || (!header && header_size))
goto fail; goto fail;
if (size == 0 || start + size > get_streamfile_size(streamFile)) { if (size == 0 || start + size > get_streamfile_size(sf)) {
VGM_LOG("FFMPEG: wrong start+size found: %x + %x > %x \n", (uint32_t)start, (uint32_t)size, get_streamfile_size(streamFile)); VGM_LOG("FFMPEG: wrong start+size found: %x + %x > %x \n", (uint32_t)start, (uint32_t)size, get_streamfile_size(sf));
size = get_streamfile_size(streamFile) - start; size = get_streamfile_size(sf) - start;
} }
@ -284,7 +281,7 @@ ffmpeg_codec_data * init_ffmpeg_header_offset_subsong(STREAMFILE *streamFile, ui
data = calloc(1, sizeof(ffmpeg_codec_data)); data = calloc(1, sizeof(ffmpeg_codec_data));
if (!data) return NULL; if (!data) return NULL;
data->streamfile = reopen_streamfile(streamFile, 0); data->streamfile = reopen_streamfile(sf, 0);
if (!data->streamfile) goto fail; if (!data->streamfile) goto fail;
/* fake header to trick FFmpeg into demuxing/decoding the stream */ /* fake header to trick FFmpeg into demuxing/decoding the stream */
@ -366,7 +363,7 @@ fail:
return NULL; return NULL;
} }
static int init_ffmpeg_config(ffmpeg_codec_data * data, int target_subsong, int reset) { static int init_ffmpeg_config(ffmpeg_codec_data* data, int target_subsong, int reset) {
int errcode = 0; int errcode = 0;
/* basic IO/format setup */ /* basic IO/format setup */
@ -455,7 +452,7 @@ fail:
} }
/* decodes a new frame to internal data */ /* decodes a new frame to internal data */
static int decode_ffmpeg_frame(ffmpeg_codec_data *data) { static int decode_ffmpeg_frame(ffmpeg_codec_data* data) {
int errcode; int errcode;
int frame_error = 0; int frame_error = 0;
@ -672,7 +669,7 @@ static void samples_dblp_to_s16(sample_t* obuf, double** inbuf, int ichs, int sa
} }
} }
static void copy_samples(ffmpeg_codec_data *data, sample_t *outbuf, int samples_to_do) { static void copy_samples(ffmpeg_codec_data* data, sample_t* outbuf, int samples_to_do) {
int channels = data->codecCtx->channels; int channels = data->codecCtx->channels;
int is_planar = av_sample_fmt_is_planar(data->codecCtx->sample_fmt) && (channels > 1); int is_planar = av_sample_fmt_is_planar(data->codecCtx->sample_fmt) && (channels > 1);
void* ibuf; void* ibuf;
@ -709,8 +706,8 @@ static void copy_samples(ffmpeg_codec_data *data, sample_t *outbuf, int samples_
} }
/* decode samples of any kind of FFmpeg format */ /* decode samples of any kind of FFmpeg format */
void decode_ffmpeg(VGMSTREAM *vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels) { void decode_ffmpeg(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do, int channels) {
ffmpeg_codec_data *data = vgmstream->codec_data; ffmpeg_codec_data* data = vgmstream->codec_data;
while (samples_to_do > 0) { while (samples_to_do > 0) {
@ -757,14 +754,11 @@ decode_fail:
/* UTILS */ /* UTILS */
/* ******************************************** */ /* ******************************************** */
void reset_ffmpeg_internal(ffmpeg_codec_data *data) { void reset_ffmpeg(ffmpeg_codec_data* data) {
seek_ffmpeg_internal(data, 0); seek_ffmpeg(data, 0);
}
void reset_ffmpeg(VGMSTREAM *vgmstream) {
reset_ffmpeg_internal(vgmstream->codec_data);
} }
void seek_ffmpeg_internal(ffmpeg_codec_data *data, int32_t num_sample) { void seek_ffmpeg(ffmpeg_codec_data* data, int32_t num_sample) {
if (!data) return; if (!data) return;
/* Start from 0 and discard samples until sample (slower but not too noticeable). /* Start from 0 and discard samples until sample (slower but not too noticeable).
@ -813,12 +807,8 @@ fail:
data->bad_init = 1; /* internals were probably free'd */ data->bad_init = 1; /* internals were probably free'd */
} }
void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
seek_ffmpeg_internal(vgmstream->codec_data, num_sample);
}
static void free_ffmpeg_config(ffmpeg_codec_data* data) {
static void free_ffmpeg_config(ffmpeg_codec_data *data) {
if (data == NULL) if (data == NULL)
return; return;
@ -858,7 +848,7 @@ static void free_ffmpeg_config(ffmpeg_codec_data *data) {
//todo avformat_find_stream_info may cause some Win Handle leaks? related to certain option //todo avformat_find_stream_info may cause some Win Handle leaks? related to certain option
} }
void free_ffmpeg(ffmpeg_codec_data *data) { void free_ffmpeg(ffmpeg_codec_data* data) {
if (data == NULL) if (data == NULL)
return; return;
@ -883,7 +873,7 @@ void free_ffmpeg(ffmpeg_codec_data *data) {
* This could be added per format in FFmpeg directly, but it's here for flexibility and due to bugs * This could be added per format in FFmpeg directly, but it's here for flexibility and due to bugs
* (FFmpeg's stream->(start_)skip_samples causes glitches in XMA). * (FFmpeg's stream->(start_)skip_samples causes glitches in XMA).
*/ */
void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples) { void ffmpeg_set_skip_samples(ffmpeg_codec_data* data, int skip_samples) {
AVStream *stream = NULL; AVStream *stream = NULL;
if (!data || !data->formatCtx) if (!data || !data->formatCtx)
return; return;
@ -902,7 +892,7 @@ void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples) {
} }
/* returns channel layout if set */ /* returns channel layout if set */
uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data * data) { uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data* data) {
if (!data || !data->codecCtx) return 0; if (!data || !data->codecCtx) return 0;
return (uint32_t)data->codecCtx->channel_layout; /* uint64 but there ain't so many speaker mappings */ return (uint32_t)data->codecCtx->channel_layout; /* uint64 but there ain't so many speaker mappings */
} }
@ -910,7 +900,7 @@ uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data * data) {
/* yet another hack to fix codecs that encode channels in different order and reorder on decoder /* yet another hack to fix codecs that encode channels in different order and reorder on decoder
* but FFmpeg doesn't do it automatically * but FFmpeg doesn't do it automatically
* (maybe should be done via mixing, but could clash with other stuff?) */ * (maybe should be done via mixing, but could clash with other stuff?) */
void ffmpeg_set_channel_remapping(ffmpeg_codec_data * data, int *channel_remap) { void ffmpeg_set_channel_remapping(ffmpeg_codec_data* data, int *channel_remap) {
int i; int i;
if (data->channels > 32) if (data->channels > 32)
@ -922,7 +912,7 @@ void ffmpeg_set_channel_remapping(ffmpeg_codec_data * data, int *channel_remap)
data->channel_remap_set = 1; data->channel_remap_set = 1;
} }
const char* ffmpeg_get_codec_name(ffmpeg_codec_data * data) { const char* ffmpeg_get_codec_name(ffmpeg_codec_data* data) {
if (!data || !data->codec) if (!data || !data->codec)
return NULL; return NULL;
if (data->codec->long_name) if (data->codec->long_name)
@ -932,12 +922,12 @@ const char* ffmpeg_get_codec_name(ffmpeg_codec_data * data) {
return NULL; return NULL;
} }
void ffmpeg_set_force_seek(ffmpeg_codec_data * data) { void ffmpeg_set_force_seek(ffmpeg_codec_data* data) {
/* some formats like Smacker are so buggy that any seeking is impossible (even on video players), /* some formats like Smacker are so buggy that any seeking is impossible (even on video players),
* or MPC with an incorrectly parsed seek table (using as 0 some non-0 seek offset). * or MPC with an incorrectly parsed seek table (using as 0 some non-0 seek offset).
* whatever, we'll just kill and reconstruct FFmpeg's config every time */ * whatever, we'll just kill and reconstruct FFmpeg's config every time */
data->force_seek = 1; data->force_seek = 1;
reset_ffmpeg_internal(data); /* reset state from trying to seek */ reset_ffmpeg(data); /* reset state from trying to seek */
//stream = data->formatCtx->streams[data->streamIndex]; //stream = data->formatCtx->streams[data->streamIndex];
} }
@ -959,4 +949,8 @@ const char* ffmpeg_get_metadata_value(ffmpeg_codec_data* data, const char* key)
return avde->value; return avde->value;
} }
STREAMFILE* ffmpeg_get_streamfile(ffmpeg_codec_data* data) {
if (!data) return NULL;
return data->streamfile;
}
#endif #endif

View file

@ -1,18 +1,17 @@
#include "coding.h" #include "coding.h"
#include <g719/g719.h>
#ifdef VGM_USE_G719 #ifdef VGM_USE_G719
#ifdef __MACOSX__
#include <g719/g719.h>
#else
#include <g719.h>
#endif
#define G719_MAX_CODES ((1280/8)) /* in int16, so max frame size is (value/8)*2 (0xF0=common, 0x140=decoder max 2560b, rare) */ #define G719_MAX_CODES ((1280/8)) /* in int16, so max frame size is (value/8)*2 (0xF0=common, 0x140=decoder max 2560b, rare) */
struct g719_codec_data {
sample_t buffer[960];
void *handle;
};
g719_codec_data *init_g719(int channel_count, int frame_size) { g719_codec_data* init_g719(int channel_count, int frame_size) {
int i; int i;
g719_codec_data *data = NULL; g719_codec_data* data = NULL;
if (frame_size / sizeof(int16_t) > G719_MAX_CODES) if (frame_size / sizeof(int16_t) > G719_MAX_CODES)
goto fail; goto fail;
@ -39,10 +38,10 @@ fail:
} }
void decode_g719(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) { void decode_g719(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t samples_to_do, int channel) {
VGMSTREAMCHANNEL *ch = &vgmstream->ch[channel]; VGMSTREAMCHANNEL* ch = &vgmstream->ch[channel];
g719_codec_data *data = vgmstream->codec_data; g719_codec_data* data = vgmstream->codec_data;
g719_codec_data *ch_data = &data[channel]; g719_codec_data* ch_data = &data[channel];
int i; int i;
if (0 == vgmstream->samples_into_block) { if (0 == vgmstream->samples_into_block) {
@ -58,7 +57,7 @@ void decode_g719(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int
} }
void reset_g719(g719_codec_data * data, int channels) { void reset_g719(g719_codec_data* data, int channels) {
int i; int i;
if (!data) return; if (!data) return;
@ -67,7 +66,7 @@ void reset_g719(g719_codec_data * data, int channels) {
} }
} }
void free_g719(g719_codec_data * data, int channels) { void free_g719(g719_codec_data* data, int channels) {
int i; int i;
if (!data) return; if (!data) return;

View file

@ -1,21 +1,36 @@
#include "coding.h" #include "coding.h"
struct hca_codec_data {
STREAMFILE* streamfile;
clHCA_stInfo info;
signed short* sample_buffer;
size_t samples_filled;
size_t samples_consumed;
size_t samples_to_discard;
void* data_buffer;
unsigned int current_block;
void* handle;
};
/* 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 *streamFile) { hca_codec_data* init_hca(STREAMFILE* sf) {
char filename[PATH_LIMIT];
uint8_t header_buffer[0x2000]; /* hca header buffer data (probable max ~0x400) */ uint8_t header_buffer[0x2000]; /* 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;
/* test header */ /* test header */
if (read_streamfile(header_buffer, 0x00, 0x08, streamFile) != 0x08) if (read_streamfile(header_buffer, 0x00, 0x08, sf) != 0x08)
goto fail; goto fail;
header_size = clHCA_isOurFile(header_buffer, 0x08); header_size = clHCA_isOurFile(header_buffer, 0x08);
if (header_size < 0 || header_size > 0x1000) if (header_size < 0 || header_size > 0x1000)
goto fail; goto fail;
if (read_streamfile(header_buffer, 0x00, header_size, streamFile) != header_size) if (read_streamfile(header_buffer, 0x00, header_size, sf) != header_size)
goto fail; goto fail;
/* init vgmstream context */ /* init vgmstream context */
@ -39,8 +54,7 @@ hca_codec_data * init_hca(STREAMFILE *streamFile) {
if (!data->sample_buffer) goto fail; if (!data->sample_buffer) goto fail;
/* load streamfile for reads */ /* load streamfile for reads */
get_streamfile_name(streamFile,filename, sizeof(filename)); data->streamfile = reopen_streamfile(sf, 0);
data->streamfile = open_streamfile(streamFile,filename);
if (!data->streamfile) goto fail; if (!data->streamfile) goto fail;
/* set initial values */ /* set initial values */
@ -53,7 +67,7 @@ fail:
return NULL; return NULL;
} }
void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do) { void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
int samples_done = 0; int samples_done = 0;
const unsigned int channels = data->info.channelCount; const unsigned int channels = data->info.channelCount;
const unsigned int blockSize = data->info.blockSize; const unsigned int blockSize = data->info.blockSize;
@ -120,7 +134,7 @@ void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do) {
} }
} }
void reset_hca(hca_codec_data * data) { void reset_hca(hca_codec_data* data) {
if (!data) return; if (!data) return;
clHCA_DecodeReset(data->handle); clHCA_DecodeReset(data->handle);
@ -130,7 +144,7 @@ void reset_hca(hca_codec_data * data) {
data->samples_to_discard = data->info.encoderDelay; data->samples_to_discard = data->info.encoderDelay;
} }
void loop_hca(hca_codec_data * data, int32_t num_sample) { void loop_hca(hca_codec_data* data, int32_t num_sample) {
if (!data) return; 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,
@ -149,7 +163,7 @@ void loop_hca(hca_codec_data * data, int32_t num_sample) {
data->samples_to_discard = data->info.loopStartDelay; data->samples_to_discard = data->info.loopStartDelay;
} }
void free_hca(hca_codec_data * data) { void free_hca(hca_codec_data* data) {
if (!data) return; if (!data) return;
close_streamfile(data->streamfile); close_streamfile(data->streamfile);
@ -175,7 +189,7 @@ void free_hca(hca_codec_data * data) {
/* Test a number of frames if key decrypts correctly. /* Test a number of frames if key decrypts correctly.
* Returns score: <0: error/wrong, 0: unknown/silent file, >0: good (the closest to 1 the better). */ * Returns score: <0: error/wrong, 0: unknown/silent file, >0: good (the closest to 1 the better). */
int test_hca_key(hca_codec_data * data, unsigned long long keycode) { int test_hca_key(hca_codec_data* data, unsigned long long keycode) {
size_t test_frames = 0, current_frame = 0, blank_frames = 0; size_t test_frames = 0, current_frame = 0, blank_frames = 0;
int total_score = 0, found_regular_frame = 0; int total_score = 0, found_regular_frame = 0;
const unsigned int blockSize = data->info.blockSize; const unsigned int blockSize = data->info.blockSize;
@ -242,3 +256,16 @@ int test_hca_key(hca_codec_data * data, unsigned long long keycode) {
clHCA_DecodeReset(data->handle); clHCA_DecodeReset(data->handle);
return total_score; return total_score;
} }
void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode) {
clHCA_SetKey(data->handle, (unsigned long long)keycode);
}
clHCA_stInfo* hca_get_info(hca_codec_data* data) {
return &data->info;
}
STREAMFILE* hca_get_streamfile(hca_codec_data* data) {
if (!data) return NULL;
return data->streamfile;
}

View file

@ -285,6 +285,60 @@ static void mtf_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset,
if (*step_index > 88) *step_index=88; if (*step_index > 88) *step_index=88;
} }
/* IMA table pre-modified like this:
for i=0..89
adpcm = clamp(adpcm[i], 0x1fff) * 4;
*/
static const int16_t mul_adpcm_table[89] = {
28, 32, 36, 40, 44, 48, 52, 56,
64, 68, 76, 84, 92, 100, 112, 124,
136, 148, 164, 180, 200, 220, 240, 264,
292, 320, 352, 388, 428, 472, 520, 572,
628, 692, 760, 836, 920, 1012, 1116, 1228,
1348, 1484, 1632, 1796, 1976, 2176, 2392, 2632,
2896, 3184, 3504, 3852, 4240, 4664, 5128, 5644,
6208, 6828, 7512, 8264, 9088, 9996, 10996, 12096,
13308, 14640, 16104, 17712, 19484, 21432, 23576, 25936,
28528, 31380, 32764, 32764, 32764, 32764, 32764, 32764,
32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764,
32764
};
/* step table is the same */
/* ops per code, generated like this:
for i=0..15
v = 0x800
if (i & 1) v = 0x1800
if (i & 2) v += 0x2000
if (i & 4) v += 0x4000
if (i & 8) v = -v;
mul_op_table[i] = v;
*/
static const int16_t mul_delta_table[16] = {
0x0800, 0x1800, 0x2800, 0x3800, 0x4800, 0x5800, 0x6800, 0x7800,
-0x0800,-0x1800,-0x2800,-0x3800,-0x4800,-0x5800,-0x6800,-0x7800
};
/* Crystal Dynamics IMA, reverse engineered from the exe, also info: https://github.com/sephiroth99/MulDeMu */
static void cd_ima_expand_nibble(uint8_t byte, int shift, int32_t* hist1, int32_t* index) {
int code, sample, step, delta;
/* could do the above table calcs during decode too */
code = (byte >> shift) & 0xf;
sample = *hist1;
step = mul_adpcm_table[*index];
delta = (int16_t)((step * mul_delta_table[code]) >> 16);
sample += delta;
*hist1 = clamp16(sample);
*index += IMA_IndexTable[code];
if (*index < 0) *index=0;
if (*index > 88) *index=88;
}
/* ************************************ */ /* ************************************ */
/* DVI/IMA */ /* DVI/IMA */
/* ************************************ */ /* ************************************ */
@ -1156,6 +1210,62 @@ void decode_h4m_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspa
stream->adpcm_step_index = step_index; stream->adpcm_step_index = step_index;
} }
/* test... */
static inline int _clamp_s32(int value, int min, int max) {
if (value < min)
return min;
else if (value > max)
return max;
else
return value;
}
/* Crystal Dynamics IMA. Original code uses mind-bending intrinsics, so this may not be fully accurate.
* Has another table with delta_table MMX combos, and uses header sample (first nibble is always 0). */
void decode_cd_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
uint8_t frame[0x24] = {0};
int i, frames_in, sample_pos = 0, block_samples, frame_size;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
off_t frame_offset;
/* external interleave (fixed size), mono */
frame_size = 0x24;
block_samples = (frame_size - 0x4) * 2;
frames_in = first_sample / block_samples;
first_sample = first_sample % block_samples;
frame_offset = stream->offset + frame_size * frames_in;
read_streamfile(frame, frame_offset, frame_size, stream->streamfile); /* ignore EOF errors */
/* normal header (hist+step+reserved), mono */
if (first_sample == 0) {
hist1 = get_s16le(frame + 0x00);
step_index = get_u8(frame + 0x02);
step_index = _clamp_s32(step_index, 0, 88);
/* write header sample (even samples per block, skips first nibble) */
outbuf[sample_pos] = (short)(hist1);
sample_pos += channelspacing;
first_sample += 1;
samples_to_do -= 1;
}
/* decode nibbles (layout: straight in mono) */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
int pos = 0x04 + (i/2);
int shift = (i&1 ? 4:0); /* low first, but first low nibble is skipped */
cd_ima_expand_nibble(frame[pos], shift, &hist1, &step_index);
outbuf[sample_pos] = (short)(hist1);
sample_pos += channelspacing;
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
}
/* ************************************************************* */ /* ************************************************************* */
size_t ima_bytes_to_samples(size_t bytes, int channels) { size_t ima_bytes_to_samples(size_t bytes, int channels) {

View file

@ -8,48 +8,59 @@ static const int32_t l5_scales[32] = {
0x00130B82, 0x00182B83, 0x001EAC92, 0x0026EDB2, 0x00316777, 0x003EB2E6, 0x004F9232, 0x0064FBD1 0x00130B82, 0x00182B83, 0x001EAC92, 0x0026EDB2, 0x00316777, 0x003EB2E6, 0x004F9232, 0x0064FBD1
}; };
void decode_l5_555(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { void decode_l5_555(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i=first_sample; uint8_t frame[0x12] = {0};
int32_t sample_count; off_t frame_offset;
int i, frames_in, sample_count = 0;
size_t bytes_per_frame, samples_per_frame;
uint16_t header;
uint8_t coef_index;
int framesin = first_sample/32;
uint16_t header = (uint16_t)read_16bitLE(framesin*0x12+stream->offset,stream->streamfile);
int32_t pos_scale = l5_scales[(header>>5)&0x1f];
int32_t neg_scale = l5_scales[header&0x1f];
int coef_index = (header >> 10) & 0x1f;
int16_t hist1 = stream->adpcm_history1_16; int16_t hist1 = stream->adpcm_history1_16;
int16_t hist2 = stream->adpcm_history2_16; int16_t hist2 = stream->adpcm_history2_16;
int16_t hist3 = stream->adpcm_history3_16; int16_t hist3 = stream->adpcm_history3_16;
int32_t coef1 = stream->adpcm_coef_3by32[coef_index*3]; int32_t coef1, coef2, coef3;
int32_t coef2 = stream->adpcm_coef_3by32[coef_index*3+1]; int32_t pos_scale, neg_scale;
int32_t coef3 = stream->adpcm_coef_3by32[coef_index*3+2];
/*printf("offset: %x\nscale: %d\nindex: %d (%lf,%lf)\nhist: %d %d\n",
(unsigned)stream->offset,scale,coef_index,coef1/2048.0,coef2/2048.0,hist1,hist2);*/
first_sample = first_sample%32; /* external interleave (fixed size), mono */
bytes_per_frame = 0x12;
samples_per_frame = (bytes_per_frame - 0x02) * 2; /* always 32 */
frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { /* parse frame header */
int sample_byte = read_8bit(framesin*0x12+stream->offset+2+i/2,stream->streamfile); frame_offset = stream->offset + bytes_per_frame * frames_in;
int nibble = (i&1? read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
get_low_nibble_signed(sample_byte): header = get_u32le(frame);
get_high_nibble_signed(sample_byte)); coef_index = (header >> 10) & 0x1f;
int32_t prediction = pos_scale = l5_scales[(header >> 5) & 0x1f];
-(hist1 * coef1 + hist2 * coef2 + hist3 * coef3); neg_scale = l5_scales[(header >> 0) & 0x1f];
if (nibble >= 0) coef1 = stream->adpcm_coef_3by32[coef_index * 3 + 0];
{ coef2 = stream->adpcm_coef_3by32[coef_index * 3 + 1];
outbuf[sample_count] = clamp16((prediction + nibble * pos_scale) >> 12); coef3 = stream->adpcm_coef_3by32[coef_index * 3 + 2];
}
for (i = first_sample; i < first_sample + samples_to_do; i++) {
int32_t prediction, sample = 0;
uint8_t nibbles = frame[0x02 + i/2];
sample = (i&1) ?
get_low_nibble_signed(nibbles):
get_high_nibble_signed(nibbles);
prediction = -(hist1 * coef1 + hist2 * coef2 + hist3 * coef3);
if (sample >= 0)
sample = (prediction + sample * pos_scale) >> 12;
else else
{ sample = (prediction + sample * neg_scale) >> 12;
outbuf[sample_count] = clamp16((prediction + nibble * neg_scale) >> 12); sample = clamp16(sample);
}
outbuf[sample_count] = sample;
sample_count += channelspacing;
hist3 = hist2; hist3 = hist2;
hist2 = hist1; hist2 = hist1;
hist1 = outbuf[sample_count]; hist1 = sample;
} }
stream->adpcm_history1_16 = hist1; stream->adpcm_history1_16 = hist1;

View file

@ -0,0 +1,91 @@
#ifndef _MPEG_BITREADER_H
#define _MPEG_BITREADER_H
/* Simple bitreader for MPEG/standard bit format.
* Kept in .h since it's slightly faster (compiler can optimize statics better) */
typedef struct {
uint8_t* buf; /* buffer to read/write */
size_t bufsize; /* max size of the buffer */
uint32_t b_off; /* current offset in bits inside the buffer */
} bitstream_t;
/* convenience util */
static void init_bitstream(bitstream_t* b, uint8_t* buf, size_t bufsize) {
b->buf = buf;
b->bufsize = bufsize;
b->b_off = 0;
}
/* Read bits (max 32) from buf and update the bit offset. Order is BE (MSF). */
static int rb_bits(bitstream_t* ib, uint32_t bits, uint32_t* value) {
uint32_t shift, pos, val;
int i, bit_buf, bit_val;
if (bits > 32 || ib->b_off + bits > ib->bufsize * 8)
goto fail;
pos = ib->b_off / 8; /* byte offset */
shift = ib->b_off % 8; /* bit sub-offset */
val = 0;
for (i = 0; i < bits; i++) {
bit_buf = (1U << (8-1-shift)) & 0xFF; /* bit check for buf */
bit_val = (1U << (bits-1-i)); /* bit to set in value */
if (ib->buf[pos] & bit_buf) /* is bit in buf set? */
val |= bit_val; /* set bit */
shift++;
if (shift % 8 == 0) { /* new byte starts */
shift = 0;
pos++;
}
}
*value = val;
ib->b_off += bits;
return 1;
fail:
VGM_LOG("BITREADER: read fail\n");
*value = 0;
return 0;
}
#ifndef BITSTREAM_READ_ONLY
/* Write bits (max 32) to buf and update the bit offset. Order is BE (MSF). */
static int wb_bits(bitstream_t* ob, uint32_t bits, uint32_t value) {
uint32_t shift, pos;
int i, bit_val, bit_buf;
if (bits > 32 || ob->b_off + bits > ob->bufsize * 8)
goto fail;
pos = ob->b_off / 8; /* byte offset */
shift = ob->b_off % 8; /* bit sub-offset */
for (i = 0; i < bits; i++) {
bit_val = (1U << (bits-1-i)); /* bit check for value */
bit_buf = (1U << (8-1-shift)) & 0xFF; /* bit to set in buf */
if (value & bit_val) /* is bit in val set? */
ob->buf[pos] |= bit_buf; /* set bit */
else
ob->buf[pos] &= ~bit_buf; /* unset bit */
shift++;
if (shift % 8 == 0) { /* new byte starts */
shift = 0;
pos++;
}
}
ob->b_off += bits;
return 1;
fail:
return 0;
}
#endif
#endif

View file

@ -1,4 +1,5 @@
#include "mpeg_decoder.h" #include "mpeg_decoder.h"
#include "mpeg_bitreader.h"
#ifdef VGM_USE_MPEG #ifdef VGM_USE_MPEG
@ -27,9 +28,9 @@
/* helper to pass around */ /* helper to pass around */
typedef struct { typedef struct {
STREAMFILE *sf; STREAMFILE* sf;
off_t offset; off_t offset;
vgm_bitstream is; bitstream_t is;
uint8_t buf[EALAYER3_MAX_EA_FRAME_SIZE]; uint8_t buf[EALAYER3_MAX_EA_FRAME_SIZE];
int leftover_bits; int leftover_bits;
} ealayer3_buffer_t; } ealayer3_buffer_t;
@ -82,21 +83,21 @@ typedef struct {
} ealayer3_frame_t; } ealayer3_frame_t;
static int ealayer3_parse_frame(mpeg_codec_data *data, int num_stream, ealayer3_buffer_t *ib, ealayer3_frame_t *eaf); static int ealayer3_parse_frame(mpeg_codec_data* data, int num_stream, ealayer3_buffer_t* ib, ealayer3_frame_t* eaf);
static int ealayer3_parse_frame_v1(ealayer3_buffer_t *ib, ealayer3_frame_t *eaf, int channels_per_frame, int is_v1b); static int ealayer3_parse_frame_v1(ealayer3_buffer_t* ib, ealayer3_frame_t* eaf, int channels_per_frame, int is_v1b);
static int ealayer3_parse_frame_v2(ealayer3_buffer_t *ib, ealayer3_frame_t *eaf); static int ealayer3_parse_frame_v2(ealayer3_buffer_t* ib, ealayer3_frame_t* eaf);
static int ealayer3_parse_frame_common(ealayer3_buffer_t *ib, ealayer3_frame_t *eaf); static int ealayer3_parse_frame_common(ealayer3_buffer_t* ib, ealayer3_frame_t* eaf);
static int ealayer3_rebuild_mpeg_frame(vgm_bitstream *is_0, ealayer3_frame_t *eaf_0, vgm_bitstream *is_1, ealayer3_frame_t *eaf_1, vgm_bitstream *os); static int ealayer3_rebuild_mpeg_frame(bitstream_t* is_0, ealayer3_frame_t* eaf_0, bitstream_t* is_1, ealayer3_frame_t* eaf_1, bitstream_t* os);
static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, ealayer3_frame_t *eaf); static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data, int num_stream, ealayer3_frame_t* eaf);
static int ealayer3_skip_data(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, int at_start); static int ealayer3_skip_data(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data, int num_stream, int at_start);
static int ealayer3_is_empty_frame_v2p(STREAMFILE *sf, off_t offset); static int ealayer3_is_empty_frame_v2p(STREAMFILE* sf, off_t offset);
/* **************************************************************************** */ /* **************************************************************************** */
/* EXTERNAL API */ /* EXTERNAL API */
/* **************************************************************************** */ /* **************************************************************************** */
/* init codec from an EALayer3 frame */ /* init codec from an EALayer3 frame */
int mpeg_custom_setup_init_ealayer3(STREAMFILE *streamfile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type) { int mpeg_custom_setup_init_ealayer3(STREAMFILE* streamfile, off_t start_offset, mpeg_codec_data* data, coding_t *coding_type) {
int ok; int ok;
ealayer3_buffer_t ib = {0}; ealayer3_buffer_t ib = {0};
ealayer3_frame_t eaf; ealayer3_frame_t eaf;
@ -130,7 +131,7 @@ fail:
} }
/* writes data to the buffer and moves offsets, transforming EALayer3 frames */ /* writes data to the buffer and moves offsets, transforming EALayer3 frames */
int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream) { int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data, int num_stream) {
mpeg_custom_stream *ms = data->streams[num_stream]; mpeg_custom_stream *ms = data->streams[num_stream];
int ok, granule_found; int ok, granule_found;
ealayer3_buffer_t ib_0 = {0}, ib_1 = {0}; ealayer3_buffer_t ib_0 = {0}, ib_1 = {0};
@ -219,10 +220,9 @@ int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *
/* rebuild EALayer3 frame to MPEG frame */ /* rebuild EALayer3 frame to MPEG frame */
{ {
vgm_bitstream os = {0}; bitstream_t os = {0};
os.buf = ms->buffer; init_bitstream(&os, ms->buffer, ms->buffer_size);
os.bufsize = ms->buffer_size;
ok = ealayer3_rebuild_mpeg_frame(&ib_0.is, &eaf_0, &ib_1.is, &eaf_1, &os); ok = ealayer3_rebuild_mpeg_frame(&ib_0.is, &eaf_0, &ib_1.is, &eaf_1, &os);
if (!ok) goto fail; if (!ok) goto fail;
@ -243,7 +243,7 @@ fail:
/* Read at most N bits from streamfile. This makes more smaller reads (not good) but /* Read at most N bits from streamfile. This makes more smaller reads (not good) but
* allows exact frame size reading (good), as reading over a frame then reading back * allows exact frame size reading (good), as reading over a frame then reading back
* is expensive in EALayer3 since it uses custom streamfiles. */ * is expensive in EALayer3 since it uses custom streamfiles. */
static void fill_buf(ealayer3_buffer_t *ib, int bits) { static void fill_buf(ealayer3_buffer_t* ib, int bits) {
size_t read_size, bytes_size; size_t read_size, bytes_size;
int mod; int mod;
@ -273,7 +273,7 @@ static void fill_buf(ealayer3_buffer_t *ib, int bits) {
ib->leftover_bits = (mod > 0 ? 8 - mod : 0); ib->leftover_bits = (mod > 0 ? 8 - mod : 0);
} }
static int ealayer3_parse_frame(mpeg_codec_data *data, int num_stream, ealayer3_buffer_t *ib, ealayer3_frame_t *eaf) { static int ealayer3_parse_frame(mpeg_codec_data* data, int num_stream, ealayer3_buffer_t* ib, ealayer3_frame_t* eaf) {
int ok; int ok;
/* We must pass this from state, as not all EA-frames have channel info. /* We must pass this from state, as not all EA-frames have channel info.
@ -302,14 +302,14 @@ fail:
/* read V1"a" (in SCHl) and V1"b" (in SNS) EALayer3 frame */ /* read V1"a" (in SCHl) and V1"b" (in SNS) EALayer3 frame */
static int ealayer3_parse_frame_v1(ealayer3_buffer_t *ib, ealayer3_frame_t *eaf, int channels_per_frame, int is_v1b) { static int ealayer3_parse_frame_v1(ealayer3_buffer_t* ib, ealayer3_frame_t* eaf, int channels_per_frame, int is_v1b) {
int ok; int ok;
vgm_bitstream *is = &ib->is; bitstream_t* is = &ib->is;
/* read EA-frame V1 header */ /* read EA-frame V1 header */
fill_buf(ib, 8); fill_buf(ib, 8);
r_bits(is, 8,&eaf->v1_pcm_flag); rb_bits(is, 8,&eaf->v1_pcm_flag);
eaf->pre_size = 1; /* 8b */ eaf->pre_size = 1; /* 8b */
@ -331,15 +331,15 @@ static int ealayer3_parse_frame_v1(ealayer3_buffer_t *ib, ealayer3_frame_t *eaf,
/* check PCM block */ /* check PCM block */
if (eaf->v1_pcm_flag == 0xEE) { if (eaf->v1_pcm_flag == 0xEE) {
fill_buf(ib, 32); fill_buf(ib, 32);
r_bits(is, 16,&eaf->v1_offset_samples); /* PCM block offset in the buffer */ rb_bits(is, 16,&eaf->v1_offset_samples); /* PCM block offset in the buffer */
r_bits(is, 16,&eaf->v1_pcm_samples); /* number of PCM samples, can be 0 */ rb_bits(is, 16,&eaf->v1_pcm_samples); /* number of PCM samples, can be 0 */
eaf->pre_size += 2+2; /* 16b+16b */ eaf->pre_size += 2+2; /* 16b+16b */
eaf->pcm_size = (2*eaf->v1_pcm_samples * channels_per_frame); eaf->pcm_size = (2*eaf->v1_pcm_samples * channels_per_frame);
if (is_v1b) { /* extra 32b in v1b */ if (is_v1b) { /* extra 32b in v1b */
fill_buf(ib, 32); fill_buf(ib, 32);
r_bits(is, 32,&eaf->v1_pcm_unknown); rb_bits(is, 32,&eaf->v1_pcm_unknown);
eaf->pre_size += 4; /* 32b */ eaf->pre_size += 4; /* 32b */
@ -356,26 +356,26 @@ fail:
/* read V2"PCM" and V2"Spike" EALayer3 frame (exactly the same but V2P seems to have bigger /* read V2"PCM" and V2"Spike" EALayer3 frame (exactly the same but V2P seems to have bigger
* PCM blocks and maybe smaller frames) */ * PCM blocks and maybe smaller frames) */
static int ealayer3_parse_frame_v2(ealayer3_buffer_t *ib, ealayer3_frame_t *eaf) { static int ealayer3_parse_frame_v2(ealayer3_buffer_t* ib, ealayer3_frame_t* eaf) {
int ok; int ok;
vgm_bitstream *is = &ib->is; bitstream_t* is = &ib->is;
/* read EA-frame V2 header */ /* read EA-frame V2 header */
fill_buf(ib, 16); fill_buf(ib, 16);
r_bits(is, 1,&eaf->v2_extended_flag); rb_bits(is, 1,&eaf->v2_extended_flag);
r_bits(is, 1,&eaf->v2_stereo_flag); rb_bits(is, 1,&eaf->v2_stereo_flag);
r_bits(is, 2,&eaf->v2_reserved); rb_bits(is, 2,&eaf->v2_reserved);
r_bits(is, 12,&eaf->v2_frame_size); rb_bits(is, 12,&eaf->v2_frame_size);
eaf->pre_size = 2; /* 16b */ eaf->pre_size = 2; /* 16b */
if (eaf->v2_extended_flag) { if (eaf->v2_extended_flag) {
fill_buf(ib, 32); fill_buf(ib, 32);
r_bits(is, 2,&eaf->v2_offset_mode); rb_bits(is, 2,&eaf->v2_offset_mode);
r_bits(is, 10,&eaf->v2_offset_samples); rb_bits(is, 10,&eaf->v2_offset_samples);
r_bits(is, 10,&eaf->v2_pcm_samples); rb_bits(is, 10,&eaf->v2_pcm_samples);
r_bits(is, 10,&eaf->v2_common_size); rb_bits(is, 10,&eaf->v2_common_size);
eaf->pre_size += 4; /* 32b */ eaf->pre_size += 4; /* 32b */
} }
@ -406,7 +406,7 @@ fail:
/* parses an EALayer3 frame (common part) */ /* parses an EALayer3 frame (common part) */
static int ealayer3_parse_frame_common(ealayer3_buffer_t *ib, ealayer3_frame_t *eaf) { static int ealayer3_parse_frame_common(ealayer3_buffer_t* ib, ealayer3_frame_t* eaf) {
/* index tables */ /* index tables */
static const int versions[4] = { /* MPEG 2.5 */ 3, /* reserved */ -1, /* MPEG 2 */ 2, /* MPEG 1 */ 1 }; static const int versions[4] = { /* MPEG 2.5 */ 3, /* reserved */ -1, /* MPEG 2 */ 2, /* MPEG 1 */ 1 };
static const int sample_rates[4][4] = { /* [version_index][sample rate index] */ static const int sample_rates[4][4] = { /* [version_index][sample rate index] */
@ -417,17 +417,17 @@ static int ealayer3_parse_frame_common(ealayer3_buffer_t *ib, ealayer3_frame_t *
}; };
static const int channels[4] = { 2,2,2, 1 }; /* [channel_mode] */ static const int channels[4] = { 2,2,2, 1 }; /* [channel_mode] */
vgm_bitstream *is = &ib->is; bitstream_t* is = &ib->is;
off_t start_b_off = is->b_off; off_t start_b_off = is->b_off;
int i, fill_bits, others_2_bits; int i, fill_bits, others_2_bits;
/* read main header */ /* read main header */
fill_buf(ib, 8); fill_buf(ib, 8);
r_bits(is, 2,&eaf->version_index); rb_bits(is, 2,&eaf->version_index);
r_bits(is, 2,&eaf->sample_rate_index); rb_bits(is, 2,&eaf->sample_rate_index);
r_bits(is, 2,&eaf->channel_mode); rb_bits(is, 2,&eaf->channel_mode);
r_bits(is, 2,&eaf->mode_extension); rb_bits(is, 2,&eaf->mode_extension);
/* check empty frame */ /* check empty frame */
@ -455,7 +455,7 @@ static int ealayer3_parse_frame_common(ealayer3_buffer_t *ib, ealayer3_frame_t *
/* read side info */ /* read side info */
fill_buf(ib, 1); fill_buf(ib, 1);
r_bits(is, 1,&eaf->granule_index); rb_bits(is, 1,&eaf->granule_index);
fill_bits = (eaf->mpeg1 && eaf->granule_index == 1) ? 4 * eaf->channels : 0; fill_bits = (eaf->mpeg1 && eaf->granule_index == 1) ? 4 * eaf->channels : 0;
fill_bits = fill_bits + (12 + 32 + others_2_bits) * eaf->channels; fill_bits = fill_bits + (12 + 32 + others_2_bits) * eaf->channels;
@ -463,15 +463,15 @@ static int ealayer3_parse_frame_common(ealayer3_buffer_t *ib, ealayer3_frame_t *
if (eaf->mpeg1 && eaf->granule_index == 1) { if (eaf->mpeg1 && eaf->granule_index == 1) {
for (i = 0; i < eaf->channels; i++) { for (i = 0; i < eaf->channels; i++) {
r_bits(is, 4,&eaf->scfsi[i]); rb_bits(is, 4,&eaf->scfsi[i]);
} }
} }
for (i = 0; i < eaf->channels; i++) { for (i = 0; i < eaf->channels; i++) {
r_bits(is, 12,&eaf->main_data_size[i]); rb_bits(is, 12,&eaf->main_data_size[i]);
/* divided in 47b=32+15 (MPEG1) or 51b=32+19 (MPEG2), arbitrarily */ /* divided in 47b=32+15 (MPEG1) or 51b=32+19 (MPEG2), arbitrarily */
r_bits(is, 32,&eaf->others_1[i]); rb_bits(is, 32,&eaf->others_1[i]);
r_bits(is, others_2_bits,&eaf->others_2[i]); rb_bits(is, others_2_bits,&eaf->others_2[i]);
} }
@ -496,7 +496,7 @@ fail:
/* converts an EALAYER3 frame to a standard MPEG frame from pre-parsed info */ /* converts an EALAYER3 frame to a standard MPEG frame from pre-parsed info */
static int ealayer3_rebuild_mpeg_frame(vgm_bitstream *is_0, ealayer3_frame_t *eaf_0, vgm_bitstream *is_1, ealayer3_frame_t *eaf_1, vgm_bitstream* os) { static int ealayer3_rebuild_mpeg_frame(bitstream_t* is_0, ealayer3_frame_t* eaf_0, bitstream_t* is_1, ealayer3_frame_t* eaf_1, bitstream_t* os) {
uint32_t c = 0; uint32_t c = 0;
int i, j; int i, j;
int expected_bitrate_index, expected_frame_size; int expected_bitrate_index, expected_frame_size;
@ -537,55 +537,55 @@ static int ealayer3_rebuild_mpeg_frame(vgm_bitstream *is_0, ealayer3_frame_t *ea
#endif #endif
/* write MPEG1/2 frame header */ /* write MPEG1/2 frame header */
w_bits(os, 11, 0x7FF); /* sync */ wb_bits(os, 11, 0x7FF); /* sync */
w_bits(os, 2, eaf_0->version_index); wb_bits(os, 2, eaf_0->version_index);
w_bits(os, 2, 0x01); /* layer III index */ wb_bits(os, 2, 0x01); /* layer III index */
w_bits(os, 1, 1); /* "no CRC" flag */ wb_bits(os, 1, 1); /* "no CRC" flag */
w_bits(os, 4, expected_bitrate_index); wb_bits(os, 4, expected_bitrate_index);
w_bits(os, 2, eaf_0->sample_rate_index); wb_bits(os, 2, eaf_0->sample_rate_index);
w_bits(os, 1, 0); /* padding */ wb_bits(os, 1, 0); /* padding */
w_bits(os, 1, 0); /* private */ wb_bits(os, 1, 0); /* private */
w_bits(os, 2, eaf_0->channel_mode); wb_bits(os, 2, eaf_0->channel_mode);
w_bits(os, 2, eaf_0->mode_extension); wb_bits(os, 2, eaf_0->mode_extension);
w_bits(os, 1, 1); /* copyrighted */ wb_bits(os, 1, 1); /* copyrighted */
w_bits(os, 1, 1); /* original */ wb_bits(os, 1, 1); /* original */
w_bits(os, 2, 0); /* emphasis */ wb_bits(os, 2, 0); /* emphasis */
if (eaf_0->mpeg1) { if (eaf_0->mpeg1) {
int private_bits = (eaf_0->channels==1 ? 5 : 3); int private_bits = (eaf_0->channels==1 ? 5 : 3);
/* write MPEG1 side info */ /* write MPEG1 side info */
w_bits(os, 9, 0); /* main data start (no bit reservoir) */ wb_bits(os, 9, 0); /* main data start (no bit reservoir) */
w_bits(os, private_bits, 0); wb_bits(os, private_bits, 0);
for (i = 0; i < eaf_1->channels; i++) { for (i = 0; i < eaf_1->channels; i++) {
w_bits(os, 4, eaf_1->scfsi[i]); /* saved in granule1 only */ wb_bits(os, 4, eaf_1->scfsi[i]); /* saved in granule1 only */
} }
for (i = 0; i < eaf_0->channels; i++) { /* granule0 */ for (i = 0; i < eaf_0->channels; i++) { /* granule0 */
w_bits(os, 12, eaf_0->main_data_size[i]); wb_bits(os, 12, eaf_0->main_data_size[i]);
w_bits(os, 32, eaf_0->others_1[i]); wb_bits(os, 32, eaf_0->others_1[i]);
w_bits(os, 47-32, eaf_0->others_2[i]); wb_bits(os, 47-32, eaf_0->others_2[i]);
} }
for (i = 0; i < eaf_1->channels; i++) { /* granule1 */ for (i = 0; i < eaf_1->channels; i++) { /* granule1 */
w_bits(os, 12, eaf_1->main_data_size[i]); wb_bits(os, 12, eaf_1->main_data_size[i]);
w_bits(os, 32, eaf_1->others_1[i]); wb_bits(os, 32, eaf_1->others_1[i]);
w_bits(os, 47-32, eaf_1->others_2[i]); wb_bits(os, 47-32, eaf_1->others_2[i]);
} }
/* write MPEG1 main data */ /* write MPEG1 main data */
is_0->b_off = eaf_0->data_offset_b; is_0->b_off = eaf_0->data_offset_b;
for (i = 0; i < eaf_0->channels; i++) { /* granule0 */ for (i = 0; i < eaf_0->channels; i++) { /* granule0 */
for (j = 0; j < eaf_0->main_data_size[i]; j++) { for (j = 0; j < eaf_0->main_data_size[i]; j++) {
r_bits(is_0, 1, &c); rb_bits(is_0, 1, &c);
w_bits(os, 1, c); wb_bits(os, 1, c);
} }
} }
is_1->b_off = eaf_1->data_offset_b; is_1->b_off = eaf_1->data_offset_b;
for (i = 0; i < eaf_1->channels; i++) { /* granule1 */ for (i = 0; i < eaf_1->channels; i++) { /* granule1 */
for (j = 0; j < eaf_1->main_data_size[i]; j++) { for (j = 0; j < eaf_1->main_data_size[i]; j++) {
r_bits(is_1, 1, &c); rb_bits(is_1, 1, &c);
w_bits(os, 1, c); wb_bits(os, 1, c);
} }
} }
} }
@ -593,21 +593,21 @@ static int ealayer3_rebuild_mpeg_frame(vgm_bitstream *is_0, ealayer3_frame_t *ea
int private_bits = (eaf_0->channels==1 ? 1 : 2); int private_bits = (eaf_0->channels==1 ? 1 : 2);
/* write MPEG2 side info */ /* write MPEG2 side info */
w_bits(os, 8, 0); /* main data start (no bit reservoir) */ wb_bits(os, 8, 0); /* main data start (no bit reservoir) */
w_bits(os, private_bits, 0); wb_bits(os, private_bits, 0);
for (i = 0; i < eaf_0->channels; i++) { for (i = 0; i < eaf_0->channels; i++) {
w_bits(os, 12, eaf_0->main_data_size[i]); wb_bits(os, 12, eaf_0->main_data_size[i]);
w_bits(os, 32, eaf_0->others_1[i]); wb_bits(os, 32, eaf_0->others_1[i]);
w_bits(os, 51-32, eaf_0->others_2[i]); wb_bits(os, 51-32, eaf_0->others_2[i]);
} }
/* write MPEG2 main data */ /* write MPEG2 main data */
is_0->b_off = eaf_0->data_offset_b; is_0->b_off = eaf_0->data_offset_b;
for (i = 0; i < eaf_0->channels; i++) { for (i = 0; i < eaf_0->channels; i++) {
for (j = 0; j < eaf_0->main_data_size[i]; j++) { for (j = 0; j < eaf_0->main_data_size[i]; j++) {
r_bits(is_0, 1, &c); rb_bits(is_0, 1, &c);
w_bits(os, 1, c); wb_bits(os, 1, c);
} }
} }
} }
@ -615,7 +615,7 @@ static int ealayer3_rebuild_mpeg_frame(vgm_bitstream *is_0, ealayer3_frame_t *ea
/* align to closest 8b */ /* align to closest 8b */
if (os->b_off % 8) { if (os->b_off % 8) {
int align_bits = 8 - (os->b_off % 8); int align_bits = 8 - (os->b_off % 8);
w_bits(os, align_bits, 0); wb_bits(os, align_bits, 0);
} }
@ -636,7 +636,7 @@ fail:
return 0; return 0;
} }
static void ealayer3_copy_pcm_block(uint8_t* outbuf, off_t pcm_offset, int pcm_number, int channels_per_frame, int is_packed, STREAMFILE *sf) { static void ealayer3_copy_pcm_block(uint8_t* outbuf, off_t pcm_offset, int pcm_number, int channels_per_frame, int is_packed, STREAMFILE* sf) {
int i, ch; int i, ch;
uint8_t pcm_block[1152 * 2 * 2]; /* assumed max: 1 MPEG frame samples * 16b * max channels */ uint8_t pcm_block[1152 * 2 * 2]; /* assumed max: 1 MPEG frame samples * 16b * max channels */
size_t pcm_size = pcm_number * 2 * channels_per_frame; size_t pcm_size = pcm_number * 2 * channels_per_frame;
@ -687,7 +687,7 @@ static void ealayer3_copy_pcm_block(uint8_t* outbuf, off_t pcm_offset, int pcm_n
/* write PCM block directly to sample buffer and setup decode discard (EALayer3 seems to use this as a prefetch of sorts). /* write PCM block directly to sample buffer and setup decode discard (EALayer3 seems to use this as a prefetch of sorts).
* Seems to alter decoded sample buffer to handle encoder delay/padding in a twisted way. */ * Seems to alter decoded sample buffer to handle encoder delay/padding in a twisted way. */
static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, ealayer3_frame_t *eaf) { static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data, int num_stream, ealayer3_frame_t* eaf) {
mpeg_custom_stream *ms = data->streams[num_stream]; mpeg_custom_stream *ms = data->streams[num_stream];
int channels_per_frame = ms->channels_per_frame; int channels_per_frame = ms->channels_per_frame;
size_t bytes_filled; size_t bytes_filled;
@ -817,7 +817,7 @@ fail:
* *
* EALayer3 v1 in SCHl uses external offsets and 1ch multichannel instead. * EALayer3 v1 in SCHl uses external offsets and 1ch multichannel instead.
*/ */
static int ealayer3_skip_data(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, int at_start) { static int ealayer3_skip_data(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data, int num_stream, int at_start) {
int ok, i; int ok, i;
ealayer3_buffer_t ib = {0}; ealayer3_buffer_t ib = {0};
ealayer3_frame_t eaf; ealayer3_frame_t eaf;
@ -845,7 +845,7 @@ fail:
return 0; return 0;
} }
static int ealayer3_is_empty_frame_v2p(STREAMFILE *sf, off_t offset) { static int ealayer3_is_empty_frame_v2p(STREAMFILE* sf, off_t offset) {
/* V2P frame header should contain a valid frame size (lower 12b) */ /* V2P frame header should contain a valid frame size (lower 12b) */
uint16_t v2_header = read_u16be(offset, sf); uint16_t v2_header = read_u16be(offset, sf);
return (v2_header % 0xFFF) == 0 || v2_header == 0xFFFF; return (v2_header % 0xFFF) == 0 || v2_header == 0xFFFF;

View file

@ -3,11 +3,7 @@
#include "../vgmstream.h" #include "../vgmstream.h"
#ifdef VGM_USE_MPEG #ifdef VGM_USE_MPEG
#ifdef __MACOSX__
#include <mpg123/mpg123.h> #include <mpg123/mpg123.h>
#else
#include <mpg123.h>
#endif
#include "mpeg_decoder.h" #include "mpeg_decoder.h"
@ -509,8 +505,7 @@ void free_mpeg(mpeg_codec_data *data) {
} }
/* seeks stream to 0 */ /* seeks stream to 0 */
void reset_mpeg(VGMSTREAM *vgmstream) { void reset_mpeg(mpeg_codec_data* data) {
mpeg_codec_data *data = vgmstream->codec_data;
if (!data) return; if (!data) return;
flush_mpeg(data); flush_mpeg(data);
@ -597,6 +592,10 @@ void flush_mpeg(mpeg_codec_data * data) {
data->buffer_used = 0; data->buffer_used = 0;
} }
int mpeg_get_sample_rate(mpeg_codec_data* data) {
return data->sample_rate_per_frame;
}
long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data *data) { long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data *data) {
/* if not found just return 0 and expect to fail (if used for num_samples) */ /* if not found just return 0 and expect to fail (if used for num_samples) */
if (!data->custom) { if (!data->custom) {

View file

@ -16,6 +16,59 @@ typedef struct {
int channels; int channels;
} mpeg_frame_info; } mpeg_frame_info;
/* represents a single MPEG stream */
typedef struct {
/* per stream as sometimes mpg123 must be fed in passes if data is big enough (ex. EALayer3 multichannel) */
uint8_t *buffer; /* raw data buffer */
size_t buffer_size;
size_t bytes_in_buffer;
int buffer_full; /* raw buffer has been filled */
int buffer_used; /* raw buffer has been fed to the decoder */
mpg123_handle *m; /* MPEG decoder */
uint8_t *output_buffer; /* decoded samples from this stream (in bytes for mpg123) */
size_t output_buffer_size;
size_t samples_filled; /* data in the buffer (in samples) */
size_t samples_used; /* data extracted from the buffer */
size_t current_size_count; /* data read (if the parser needs to know) */
size_t current_size_target; /* max data, until something happens */
size_t decode_to_discard; /* discard from this stream only (for EALayer3 or AWC) */
int channels_per_frame; /* for rare cases that streams don't share this */
} mpeg_custom_stream;
struct mpeg_codec_data {
/* regular/single MPEG internals */
uint8_t *buffer; /* raw data buffer */
size_t buffer_size;
size_t bytes_in_buffer;
int buffer_full; /* raw buffer has been filled */
int buffer_used; /* raw buffer has been fed to the decoder */
mpg123_handle *m; /* MPEG decoder */
struct mpg123_frameinfo mi; /* start info, so it's available even when resetting */
/* for internal use */
int channels_per_frame;
int samples_per_frame;
/* for some calcs */
int bitrate_per_frame;
int sample_rate_per_frame;
/* custom MPEG internals */
int custom; /* flag */
mpeg_custom_t type; /* mpeg subtype */
mpeg_custom_config config; /* config depending on the mode */
size_t default_buffer_size;
mpeg_custom_stream **streams; /* array of MPEG streams (ex. 2ch+2ch) */
size_t streams_size;
size_t skip_samples; /* base encoder delay */
size_t samples_to_discard; /* for custom mpeg looping */
};
int mpeg_get_frame_info(STREAMFILE *streamfile, off_t offset, mpeg_frame_info * info); int mpeg_get_frame_info(STREAMFILE *streamfile, off_t offset, mpeg_frame_info * info);
int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type); int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type);

View file

@ -31,8 +31,8 @@ void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t fir
streamfile = ch1->streamfile; streamfile = ch1->streamfile;
/* external interleave (variable size), stereo */ /* external interleave (variable size), stereo */
bytes_per_frame = get_vgmstream_frame_size(vgmstream); bytes_per_frame = vgmstream->frame_size;
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); samples_per_frame = (vgmstream->frame_size - 0x07*vgmstream->channels)*2 / vgmstream->channels + 2;
frames_in = first_sample / samples_per_frame; frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame; first_sample = first_sample % samples_per_frame;
@ -104,8 +104,8 @@ void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample_t * outbuf, int channelsp
off_t frame_offset; off_t frame_offset;
/* external interleave (variable size), mono */ /* external interleave (variable size), mono */
bytes_per_frame = get_vgmstream_frame_size(vgmstream); bytes_per_frame = vgmstream->frame_size;
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); samples_per_frame = (vgmstream->frame_size - 0x07)*2 + 2;
frames_in = first_sample / samples_per_frame; frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame; first_sample = first_sample % samples_per_frame;
@ -167,8 +167,8 @@ void decode_msadpcm_ck(VGMSTREAM * vgmstream, sample_t * outbuf, int channelspac
off_t frame_offset; off_t frame_offset;
/* external interleave (variable size), mono */ /* external interleave (variable size), mono */
bytes_per_frame = get_vgmstream_frame_size(vgmstream); bytes_per_frame = vgmstream->frame_size;
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); samples_per_frame = (vgmstream->frame_size - 0x07)*2 + 2;
frames_in = first_sample / samples_per_frame; frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame; first_sample = first_sample % samples_per_frame;

View file

@ -1,4 +1,33 @@
/* originally from nwatowav.cc 2007.7.28 version, which read: */ /* Originally from nwatowav.cc (2007.7.28 version) by jagarl.
* - http://www.creator.club.ne.jp/~jagarl/
*
* Converted to .c by hcs (redone as a lib without RIFF/main handling), some cleanup by bnnm.
*
* nwa format (abridged from the original)
* NWA Header
* data offset index
* data block<0>
* data block<1>
* ...
* data block<N>
*
* - NWA header: 0x2c with nwa info (channels, compression level, etc), no magic number
* - data offset index: pointers to data blocks
* - data block: variable sized DPCM blocks to fixed size PCM (a,b,c compresses to (a),b-a,c-b),
* DPCM codes use variable bits. Usually for 16-bit PCM ends ups using 6-8 bits.
* - Block format:
* - mono: initial PCM (8 or 16-bit) then bitstream
* - stereo: initial PCM for left + right channel then bitstream
* Differential accuracy isn't high so initial PCM is used to correct data in each block (?)
* - bitstream: Roughly each code has an 'exponent' (2 bits) + 'mantissa' (variable bits).
* Depending on compression level + type it configures final shift value and matissa bits.
* There is a run length encoding mode in some cases (Tomoyo After voice files).
* Bitstream bytes follow little endian.
* (some examples here in the original, see decoder).
*
* Original copyright:
*/
/* /*
* Copyright 2001-2007 jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp> * Copyright 2001-2007 jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp>
* All Rights Reserved. * All Rights Reserved.
@ -33,208 +62,196 @@
#include <stdlib.h> #include <stdlib.h>
#include "nwa_decoder.h" #include "nwa_decoder.h"
/* can serve up 8 bits at a time */
static int //NWAInfo::UseRunLength
getbits (STREAMFILE *file, off_t *offset, int *shift, int bits) static int is_use_runlength(NWAData* nwa) {
{ if (nwa->channels == 2 && nwa->bps == 16 && nwa->complevel == 2) {
int ret; return 0; /* sw2 */
if (*shift > 8)
{
++*offset;
*shift -= 8;
} }
ret = read_16bitLE(*offset,file) >> *shift;
*shift += bits; if (nwa->complevel == 5) {
return ret & ((1 << bits) - 1); /* mask */ if (nwa->channels == 2)
return 0; // BGM*.nwa in Little Busters!
return 1; // Tomoyo After (.nwk koe file)
}
return 0;
} }
NWAData * NWAData* nwalib_open(STREAMFILE* sf) {
open_nwa (STREAMFILE * streamFile, const char *filename) uint8_t header[0x2c] = {0};
{
int i; int i;
NWAData * const nwa = malloc(sizeof(NWAData)); NWAData* const nwa = malloc(sizeof(NWAData));
if (!nwa) goto fail; if (!nwa) goto fail;
nwa->channels = read_16bitLE(0x00,streamFile); //NWAData::ReadHeader
nwa->bps = read_16bitLE(0x02,streamFile);
nwa->freq = read_32bitLE(0x04,streamFile); read_streamfile(header, 0x00, sizeof(header), sf);
nwa->complevel = read_32bitLE(0x08,streamFile); nwa->channels = get_s16le(header+0x00);
nwa->blocks = read_32bitLE(0x10,streamFile); nwa->bps = get_s16le(header+0x02);
nwa->datasize = read_32bitLE(0x14,streamFile); nwa->freq = get_s32le(header+0x04);
nwa->compdatasize = read_32bitLE(0x18,streamFile); nwa->complevel = get_s32le(header+0x08);
nwa->samplecount = read_32bitLE(0x1c,streamFile); nwa->dummy = get_s32le(header+0x0c);
nwa->blocksize = read_32bitLE(0x20,streamFile); nwa->blocks = get_s32le(header+0x10);
nwa->restsize = read_32bitLE(0x24,streamFile); nwa->datasize = get_s32le(header+0x14);
nwa->compdatasize = get_s32le(header+0x18);
nwa->samplecount = get_s32le(header+0x1c);
nwa->blocksize = get_s32le(header+0x20);
nwa->restsize = get_s32le(header+0x24);
nwa->dummy2 = get_s32le(header+0x28);
nwa->offsets = NULL; nwa->offsets = NULL;
nwa->buffer = NULL; nwa->outdata = NULL;
nwa->buffer_readpos = NULL; nwa->outdata_readpos = NULL;
nwa->file = NULL; nwa->tmpdata = NULL;
nwa->filesize = get_streamfile_size(sf);
/* PCM not handled here */
if (nwa->complevel < 0 || nwa->complevel > 5) goto fail;
if (nwa->channels != 1 && nwa->channels != 2) goto fail; if (nwa->blocks <= 0 || nwa->blocks > 1000000)
/* 1時間を超える曲ってのはないでしょ*/ //surely there won't be songs over 1 hour
goto fail;
if (nwa->bps != 8 && nwa->bps != 16) goto fail; // NWAData::CheckHeader:
if (nwa->blocks <= 0) goto fail; if (nwa->channels != 1 && nwa->channels != 2)
goto fail;
if (nwa->compdatasize == 0 if (nwa->bps != 8 && nwa->bps != 16)
|| get_streamfile_size(streamFile) != nwa->compdatasize) goto fail; goto fail;
if (nwa->datasize != nwa->samplecount * (nwa->bps/8)) goto fail; // (PCM not handled)
if (nwa->samplecount != if (nwa->complevel < 0 || nwa->complevel > 5)
(nwa->blocks-1) * nwa->blocksize + nwa->restsize) goto fail; goto fail;
nwa->offsets = malloc(sizeof(off_t)*nwa->blocks); if (nwa->filesize != nwa->compdatasize)
goto fail;
if (nwa->datasize != nwa->samplecount * (nwa->bps / 8))
goto fail;
if (nwa->samplecount != (nwa->blocks - 1) * nwa->blocksize + nwa->restsize)
goto fail;
/* offset index 読み込み */ //read offset index
nwa->offsets = malloc(sizeof(off_t) * nwa->blocks);
if (!nwa->offsets) goto fail; if (!nwa->offsets) goto fail;
for (i = 0; i < nwa->blocks; i++) for (i = 0; i < nwa->blocks; i++) {
{ int32_t o = read_s32le(0x2c + i*4, sf);
int32_t o = read_32bitLE(0x2c+i*4,streamFile);
if (o < 0) goto fail; if (o < 0) goto fail;
nwa->offsets[i] = o; nwa->offsets[i] = o;
} }
if (nwa->offsets[nwa->blocks-1] >= nwa->compdatasize) goto fail; if (nwa->offsets[nwa->blocks-1] >= nwa->compdatasize)
goto fail;
if (nwa->restsize > nwa->blocksize) nwa->buffer =
malloc(sizeof(sample)*nwa->restsize);
else nwa->buffer =
malloc(sizeof(sample)*nwa->blocksize);
if (nwa->buffer == NULL) goto fail;
nwa->buffer_readpos = nwa->buffer;
nwa->samples_in_buffer = 0;
nwa->use_runlength = is_use_runlength(nwa);
nwa->curblock = 0; nwa->curblock = 0;
/* if we got this far, it's probably safe */
nwa->file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); //extra
if (!nwa->file) goto fail; if (nwa->restsize > nwa->blocksize) {
nwa->outdata = malloc(sizeof(int16_t) * nwa->restsize);
}
else {
nwa->outdata = malloc(sizeof(int16_t) * nwa->blocksize);
}
if (!nwa->outdata)
goto fail;
/* これ以上の大きさはないだろう、、、 */ //probably not over this size
nwa->tmpdata = malloc(sizeof(uint8_t) * nwa->blocksize * (nwa->bps / 8) * 2);
if (!nwa->tmpdata)
goto fail;
nwa->outdata_readpos = nwa->outdata;
nwa->samples_in_buffer = 0;
return nwa; return nwa;
fail: fail:
if (nwa) nwalib_close(nwa);
{
close_nwa(nwa);
}
return NULL; return NULL;
} }
void void nwalib_close(NWAData * nwa) {
close_nwa(NWAData * nwa)
{
if (!nwa) return; if (!nwa) return;
if (nwa->offsets) free(nwa->offsets);
free (nwa->offsets); free(nwa->outdata);
nwa->offsets = NULL; free(nwa->tmpdata);
if (nwa->buffer)
free (nwa->buffer);
nwa->buffer = NULL;
if (nwa->file)
close_streamfile (nwa->file);
nwa->file = NULL;
free(nwa); free(nwa);
} }
void //NWAData::Rewind
reset_nwa(NWAData *nwa) void nwalib_reset(NWAData* nwa) {
{
nwa->curblock = 0; nwa->curblock = 0;
nwa->buffer_readpos = nwa->buffer; nwa->outdata_readpos = nwa->outdata;
nwa->samples_in_buffer = 0; nwa->samples_in_buffer = 0;
} }
static int use_runlength(NWAData *nwa) // can serve up 8 bits at a time
{ static int getbits(const uint8_t** p_data, int* shift, int bits) {
if (nwa->channels == 2 && nwa->bps == 16 && nwa->complevel == 2) int ret;
{ if (*shift > 8) {
/* sw2 */ (*p_data)++;
return 0; *shift -= 8;
} }
if (nwa->complevel == 5)
{ ret = get_s16le(*p_data) >> *shift;
if (nwa->channels == 2) return 0; /* BGM*.nwa in Little Busters! */ *shift += bits;
return 1; /* Tomoyo After (.nwk koe file) */ return ret & ((1 << bits) - 1); /* mask */
}
return 0;
} }
static void // NWADecode
nwa_decode_block(NWAData *nwa) static void decode_block(NWAData* nwa, const uint8_t* data, int outdatasize) {
{
/* 今回読み込む/デコードするデータの大きさを得る */
int curblocksize;
if (nwa->curblock != nwa->blocks - 1)
{
curblocksize = nwa->blocksize * (nwa->bps / 8);
//curcompsize = nwa->offsets[nwa->curblock + 1] - nwa->offsets[nwa->curblock];
}
else
{
curblocksize = nwa->restsize * (nwa->bps / 8);
//curcompsize = nwa->blocksize * (nwa->bps / 8) * 2;
}
nwa->samples_in_buffer = 0;
nwa->buffer_readpos = nwa->buffer;
{
sample d[2]; sample d[2];
int i; int i;
int shift = 0; int shift = 0;
off_t offset = nwa->offsets[nwa->curblock];
int dsize = curblocksize / (nwa->bps / 8); int dsize = outdatasize / (nwa->bps / 8);
int flip_flag = 0; /* stereo 用 */ int flip_flag = 0; /* stereo 用 */ //for stereo
int runlength = 0; int runlength = 0;
/* read initial sample value */ /* 最初のデータを読み込む */ //read initial data
for (i=0;i<nwa->channels;i++) for (i = 0; i < nwa->channels; i++) {
{ if (nwa->bps == 8) {
if (nwa->bps == 8) { d[i] = read_8bit(offset,nwa->file); } d[i] = get_s8(data);
else /* bps == 16 */ data += 1;
{ }
d[i] = read_16bitLE(offset,nwa->file); else { /* nwa->bps == 16 */
offset += 2; d[i] = get_s16le(data);
data += 2;
} }
} }
for (i = 0; i < dsize; i++) for (i = 0; i < dsize; i++) {
{ if (runlength == 0) { /* コピーループ中でないならデータ読み込み */ //read data if not in the copy loop
if (runlength == 0) int type = getbits(&data, &shift, 3);
{ /* コピーループ中でないならデータ読み込み */
int type = getbits(nwa->file, &offset, &shift, 3); /* type により分岐0, 1-6, 7 */ //fork depending on type
/* type により分岐0, 1-6, 7 */ if (type == 7) {
if (type == 7) /* 7 : 大きな差分 */ //big diff
{ /* RunLength() 有効時CompLevel==5, 音声ファイル) では無効 */ //invalid when using RLE (comp=5, voice file)
/* 7 : 大きな差分 */ if (getbits(&data, &shift, 1) == 1) {
/* RunLength() 有効時CompLevel==5, 音声ファイル) では無効 */ d[flip_flag] = 0; /* 未使用 */ //unused
if (getbits(nwa->file, &offset, &shift, 1) == 1)
{
d[flip_flag] = 0; /* 未使用 */
} }
else else {
{
int BITS, SHIFT; int BITS, SHIFT;
if (nwa->complevel >= 3) if (nwa->complevel >= 3) {
{
BITS = 8; BITS = 8;
SHIFT = 9; SHIFT = 9;
} }
else else {
{
BITS = 8 - nwa->complevel; BITS = 8 - nwa->complevel;
SHIFT = 2 + 7 + nwa->complevel; SHIFT = 2 + 7 + nwa->complevel;
} }
{ {
const int MASK1 = (1 << (BITS - 1)); const int MASK1 = (1 << (BITS - 1));
const int MASK2 = (1 << (BITS - 1)) - 1; const int MASK2 = (1 << (BITS - 1)) - 1;
int b = getbits(nwa->file, &offset, &shift, BITS); int b = getbits(&data, &shift, BITS);
if (b & MASK1) if (b & MASK1)
d[flip_flag] -= (b & MASK2) << SHIFT; d[flip_flag] -= (b & MASK2) << SHIFT;
else else
@ -242,110 +259,183 @@ nwa_decode_block(NWAData *nwa)
} }
} }
} }
else if (type != 0) else if (type != 0) {
{ /* 1-6 : 通常の差分 */ //normal diff
/* 1-6 : 通常の差分 */
int BITS, SHIFT; int BITS, SHIFT;
if (nwa->complevel >= 3) if (nwa->complevel >= 3) {
{
BITS = nwa->complevel + 3; BITS = nwa->complevel + 3;
SHIFT = 1 + type; SHIFT = 1 + type;
} }
else else {
{
BITS = 5 - nwa->complevel; BITS = 5 - nwa->complevel;
SHIFT = 2 + type + nwa->complevel; SHIFT = 2 + type + nwa->complevel;
} }
{ {
const int MASK1 = (1 << (BITS - 1)); const int MASK1 = (1 << (BITS - 1));
const int MASK2 = (1 << (BITS - 1)) - 1; const int MASK2 = (1 << (BITS - 1)) - 1;
int b = getbits(nwa->file, &offset, &shift, BITS); int b = getbits(&data, &shift, BITS);
if (b & MASK1) if (b & MASK1)
d[flip_flag] -= (b & MASK2) << SHIFT; d[flip_flag] -= (b & MASK2) << SHIFT;
else else
d[flip_flag] += (b & MASK2) << SHIFT; d[flip_flag] += (b & MASK2) << SHIFT;
} }
} }
else else { /* type == 0 */
{ /* type == 0 */ /* ランレングス圧縮なしの場合はなにもしない */ //does nothing in case of no RLE compression
/* ランレングス圧縮なしの場合はなにもしない */ if (nwa->use_runlength) {
if (use_runlength(nwa)) /* ランレングス圧縮ありの場合 */ //in case of RLE compression
{ runlength = getbits(&data, &shift, 1);
/* ランレングス圧縮ありの場合 */ if (runlength == 1) {
runlength = getbits(nwa->file, &offset, &shift, 1); runlength = getbits(&data, &shift, 2);
if (runlength == 1) if (runlength == 3) {
{ runlength = getbits(&data, &shift, 8);
runlength = getbits(nwa->file, &offset, &shift, 2);
if (runlength == 3)
{
runlength = getbits(nwa->file, &offset, &shift, 8);
} }
} }
} }
} }
} }
else else {
{
runlength--; runlength--;
} }
if (nwa->bps == 8)
{ if (nwa->bps == 8) {
nwa->buffer[i] = d[flip_flag]*0x100; nwa->outdata[i] = d[flip_flag] * 256; //extra (original outputs 8-bit)
}
else
{
nwa->buffer[i] = d[flip_flag];
}
nwa->samples_in_buffer++;
if (nwa->channels == 2)
flip_flag ^= 1; /* channel 切り替え */
} }
else {
nwa->outdata[i] = d[flip_flag];
} }
nwa->curblock++; if (nwa->channels == 2)
return; flip_flag ^= 1; /* channel 切り替え */ //channel swap
}
nwa->samples_in_buffer = dsize;
} }
void //NWAData::Decode
seek_nwa(NWAData *nwa, int32_t seekpos) int nwalib_decode(STREAMFILE* sf, NWAData* nwa) {
{ /* some wav/pcm handling skipped here */
int dest_block = seekpos/(nwa->blocksize/nwa->channels);
int32_t remainder = seekpos%(nwa->blocksize/nwa->channels); /* 今回読み込む/デコードするデータの大きさを得る */ //get current read/decode data size
int curblocksize, curcompsize;
if (nwa->curblock != nwa->blocks - 1) {
curblocksize = nwa->blocksize * (nwa->bps / 8);
curcompsize = nwa->offsets[nwa->curblock + 1] - nwa->offsets[nwa->curblock];
if (curblocksize >= nwa->blocksize * (nwa->bps / 8) * 2) {
return -1; // Fatal error
}
}
else { //last block
curblocksize = nwa->restsize * (nwa->bps / 8);
curcompsize = nwa->blocksize * (nwa->bps / 8) * 2;
}
// (in practice compsize is ~200-400 and blocksize ~0x800, but last block can be different)
/* データ読み込み */ //data read (may read less on last block?)
read_streamfile(nwa->tmpdata, nwa->offsets[nwa->curblock], curcompsize, sf);
nwa->samples_in_buffer = 0;
nwa->outdata_readpos = nwa->outdata;
decode_block(nwa, nwa->tmpdata, curblocksize);
nwa->curblock++; //todo check not over max blocks?
return 0;
}
//NWAFILE::Seek (not too similar)
void nwalib_seek(STREAMFILE* sf, NWAData* nwa, int32_t seekpos) {
int dest_block = seekpos / (nwa->blocksize / nwa->channels);
int32_t remainder = seekpos % (nwa->blocksize / nwa->channels);
nwa->curblock = dest_block; nwa->curblock = dest_block;
nwa_decode_block(nwa); nwalib_decode(sf, nwa);
nwa->buffer_readpos = nwa->buffer + remainder*nwa->channels; nwa->outdata_readpos = nwa->outdata + remainder * nwa->channels;
nwa->samples_in_buffer -= remainder*nwa->channels; nwa->samples_in_buffer -= remainder*nwa->channels;
} }
/* interface to vgmstream */ /* ****************************************************************** */
void
decode_nwa(NWAData *nwa, sample *outbuf,
int32_t samples_to_do)
{
while (samples_to_do > 0)
{
int32_t samples_to_read;
if (nwa->samples_in_buffer > 0) #include "coding.h"
{
samples_to_read = nwa->samples_in_buffer/nwa->channels;
struct nwa_codec_data {
STREAMFILE* sf;
NWAData* nwa;
};
/* interface to vgmstream */
void decode_nwa(nwa_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
NWAData* nwa = data->nwa;
while (samples_to_do > 0) {
if (nwa->samples_in_buffer > 0) {
int32_t samples_to_read = nwa->samples_in_buffer / nwa->channels;
if (samples_to_read > samples_to_do) if (samples_to_read > samples_to_do)
samples_to_read = samples_to_do; samples_to_read = samples_to_do;
memcpy(outbuf,nwa->buffer_readpos, memcpy(outbuf, nwa->outdata_readpos, sizeof(sample_t) * samples_to_read * nwa->channels);
sizeof(sample)*samples_to_read*nwa->channels);
nwa->buffer_readpos += samples_to_read*nwa->channels; nwa->outdata_readpos += samples_to_read * nwa->channels;
nwa->samples_in_buffer -= samples_to_read*nwa->channels; nwa->samples_in_buffer -= samples_to_read * nwa->channels;
outbuf += samples_to_read*nwa->channels; outbuf += samples_to_read * nwa->channels;
samples_to_do -= samples_to_read; samples_to_do -= samples_to_read;
} }
else else {
{ int err = nwalib_decode(data->sf, nwa);
nwa_decode_block(nwa); if (err < 0) {
VGM_LOG("NWA: decoding error\n");
return;
}
} }
} }
} }
nwa_codec_data* init_nwa(STREAMFILE* sf) {
nwa_codec_data* data = NULL;
data = malloc(sizeof(nwa_codec_data));
if (!data) goto fail;
data->nwa = nwalib_open(sf);
if (!data->nwa) goto fail;
data->sf = reopen_streamfile(sf, 0);
if (!data->sf) goto fail;
return data;
fail:
free_nwa(data);
return NULL;
}
void seek_nwa(nwa_codec_data* data, int32_t sample) {
if (!data) return;
nwalib_seek(data->sf, data->nwa, sample);
}
void reset_nwa(nwa_codec_data* data) {
if (!data) return;
nwalib_reset(data->nwa);
}
void free_nwa(nwa_codec_data* data) {
if (!data) return;
close_streamfile(data->sf);
nwalib_close(data->nwa);
free(data);
}
STREAMFILE* nwa_get_streamfile(nwa_codec_data* data) {
if (!data) return NULL;
return data->sf;
}

View file

@ -1,4 +1,4 @@
/* originally from nwatowav.cc 2007.7.28 version, which read: */ /* derived from nwatowav.cc 2007.7.28 version, which read: */
/* /*
* Copyright 2001-2007 jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp> * Copyright 2001-2007 jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp>
* All Rights Reserved. * All Rights Reserved.
@ -39,33 +39,39 @@
#include "streamfile.h" #include "streamfile.h"
#endif #endif
typedef struct NWAData_s typedef struct NWAData_s {
{
int channels; int channels;
int bps; /* bits per sample */ int bps; /* bits per sample */
int freq; /* samples per second */ int freq; /* samples per second */
int complevel; /* compression level */ int complevel; /* compression level */
int dummy; /* ? : 0x00 */
int blocks; /* block count */ int blocks; /* block count */
int datasize; /* all data size */ int datasize; /* all data size */
int compdatasize; /* compressed data size */ int compdatasize; /* compressed data size */
int samplecount; /* all samples */ int samplecount; /* all samples */
int blocksize; /* samples per block */ int blocksize; /* samples per block */
int restsize; /* samples of the last block */ int restsize; /* samples of the last block */
int dummy2; /* ? : 0x89 */
int curblock; int curblock;
off_t *offsets; off_t* offsets;
int filesize;
STREAMFILE *file; int use_runlength; //extra
/* temporarily store samples */ uint8_t *tmpdata;
sample *buffer; int16_t *outdata;
sample *buffer_readpos; int16_t *outdata_readpos;
int samples_in_buffer; int samples_in_buffer;
} NWAData; } NWAData;
NWAData *open_nwa(STREAMFILE *streamFile, const char *filename); NWAData* nwalib_open(STREAMFILE* sf);
void close_nwa(NWAData *nwa); void nwalib_close(NWAData* nwa);
void reset_nwa(NWAData *nwa); int nwalib_decode(STREAMFILE* sf, NWAData* nwa);
void seek_nwa(NWAData *nwa, int32_t seekpos); void nwalib_seek(STREAMFILE* sf, NWAData* nwa, int32_t seekpos);
void nwalib_reset(NWAData* nwa);
#endif #endif

View file

@ -265,8 +265,7 @@ void reset_ogg_vorbis(VGMSTREAM *vgmstream) {
ov_pcm_seek(&data->ogg_vorbis_file, 0); ov_pcm_seek(&data->ogg_vorbis_file, 0);
} }
void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) { void seek_ogg_vorbis(ogg_vorbis_codec_data *data, int32_t num_sample) {
ogg_vorbis_codec_data *data = vgmstream->codec_data;
if (!data) return; if (!data) return;
/* this seek crosslaps to avoid possible clicks, so seeking to 0 will /* this seek crosslaps to avoid possible clicks, so seeking to 0 will

View file

@ -17,7 +17,7 @@ static const int stex_indexes[16] = { /* OKI table (also from IMA) */
}; };
static void pcfx_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index, int16_t *out_sample, int mode) { static void pcfx_expand_nibble(VGMSTREAMCHANNEL* stream, off_t byte_offset, int nibble_shift, int32_t* hist1, int32_t* step_index, int16_t* out_sample, int mode) {
int code, step, delta; int code, step, delta;
code = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift) & 0xf; code = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift) & 0xf;
@ -57,7 +57,7 @@ static void pcfx_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int
} }
} }
static void oki16_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index, int16_t *out_sample) { static void oki16_expand_nibble(VGMSTREAMCHANNEL* stream, off_t byte_offset, int nibble_shift, int32_t* hist1, int32_t* step_index, int16_t* out_sample) {
int code, step, delta; int code, step, delta;
code = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift) & 0xf; code = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift) & 0xf;
@ -79,7 +79,15 @@ static void oki16_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, in
*out_sample = *hist1; *out_sample = *hist1;
} }
static void oki4s_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index, int16_t *out_sample) { /* Possible variation for adp_konami (Viper hardware):
* delta = ((n&7) + 0.5) * stepsize / 4; clamps 2047,-2048; nigh nibble first
*
* Results are very similar, but can't verify actual decoding, and oki4s is used in
* Jubeat (also Konami) so it makes sense they would have reused it.
* Viper sound chip may be a YMZ280B though.
*/
static void oki4s_expand_nibble(VGMSTREAMCHANNEL* stream, off_t byte_offset, int nibble_shift, int32_t* hist1, int32_t* step_index, int16_t* out_sample) {
int code, step, delta; int code, step, delta;
code = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift) & 0xf; code = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift) & 0xf;
@ -116,7 +124,7 @@ static void oki4s_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, in
* so it's needs GENH/TXTH. Sample rate can only be base_value divided by 1/2/3/4, where * so it's needs GENH/TXTH. Sample rate can only be base_value divided by 1/2/3/4, where
* base_value is approximately ~31468.5 (follows hardware clocks), mono or interleaved for stereo. * base_value is approximately ~31468.5 (follows hardware clocks), mono or interleaved for stereo.
*/ */
void decode_pcfx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int mode) { void decode_pcfx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int mode) {
int i, sample_count = 0; int i, sample_count = 0;
int32_t hist1 = stream->adpcm_history1_32; int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index; int step_index = stream->adpcm_step_index;
@ -137,7 +145,7 @@ void decode_pcfx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacin
/* OKI variation with 16-bit output (vs standard's 12-bit), found in FrontWing's PS2 games (Sweet Legacy, Hooligan). /* OKI variation with 16-bit output (vs standard's 12-bit), found in FrontWing's PS2 games (Sweet Legacy, Hooligan).
* Reverse engineered from the ELF with help from the folks at hcs. */ * Reverse engineered from the ELF with help from the folks at hcs. */
void decode_oki16(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { void decode_oki16(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count = 0; int i, sample_count = 0;
int32_t hist1 = stream->adpcm_history1_32; int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index; int step_index = stream->adpcm_step_index;
@ -169,7 +177,7 @@ void decode_oki16(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspaci
/* OKI variation with 16-bit output (vs standard's 12-bit) and pre-adjusted tables (shifted by 4), found in Jubeat Clan (AC). /* OKI variation with 16-bit output (vs standard's 12-bit) and pre-adjusted tables (shifted by 4), found in Jubeat Clan (AC).
* Reverse engineered from the DLLs. */ * Reverse engineered from the DLLs. */
void decode_oki4s(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { void decode_oki4s(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count = 0; int i, sample_count = 0;
int32_t hist1 = stream->adpcm_history1_32; int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index; int step_index = stream->adpcm_step_index;

View file

@ -66,6 +66,8 @@ void decode_ptadpcm(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspaci
index = frame[0x04]; index = frame[0x04];
VGM_ASSERT_ONCE(index > 12, "PTADPCM: incorrect index at %x\n", (uint32_t)frame_offset); VGM_ASSERT_ONCE(index > 12, "PTADPCM: incorrect index at %x\n", (uint32_t)frame_offset);
if (index > 12)
index = 12;
/* write header samples (needed) */ /* write header samples (needed) */
if (sample_count >= first_sample && samples_done < samples_to_do) { if (sample_count >= first_sample && samples_done < samples_to_do) {
@ -108,5 +110,5 @@ void decode_ptadpcm(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspaci
size_t ptadpcm_bytes_to_samples(size_t bytes, int channels, size_t frame_size) { size_t ptadpcm_bytes_to_samples(size_t bytes, int channels, size_t frame_size) {
if (channels <= 0 || frame_size < 0x06) return 0; if (channels <= 0 || frame_size < 0x06) return 0;
return (bytes / channels / frame_size) * ((frame_size-0x05) * 2); return (bytes / (channels * frame_size)) * (2 + (frame_size-0x05) * 2);
} }

View file

@ -1,42 +1,47 @@
#include "coding.h" #include "coding.h"
/* Decodes SunPlus' ADPCM codec used on the Tiger Game.com. /* Decodes SunPlus' ADPCM codec used on the Tiger Game.com.
* Reverse engineered from the Game.com's BIOS. */ * Highly improved, optimised signed 16-bit version of the algorithm. */
static const int16_t slope_table[8][16] =
static uint16_t slopeTable[64] =
{ {
0x0000, 0x0100, 0x0200, 0x0400, 0x0610, 0x0810, 0x0C18, 0x1020, { 0, 0, 256, -256, 512, -512, 1024, -1024, 1536, -1536, 2048, -2048, 3072, -3072, 4096, -4096 },
0x0100, 0x0300, 0x0508, 0x0908, 0x0D18, 0x1118, 0x1920, 0x2128, { 256, -256, 768, -768, 1280, -1280, 2304, -2304, 3328, -3328, 4352, -4352, 6400, -6400, 8448, -8448 },
0x0208, 0x0508, 0x0810, 0x0E10, 0x1420, 0x1A20, 0x2628, 0x3230, { 512, -512, 1280, -1280, 2048, -2048, 3584, -3584, 5120, -5120, 6656, -6656, 9728, -9728, 12800, -12800 },
0x0310, 0x0710, 0x0B18, 0x1318, 0x1B28, 0x2328, 0x2930, 0x4338, { 768, -768, 1792, -1792, 2816, -2816, 4864, -4864, 6912, -6912, 8960, -8960, 10496, -10496, 17152, -17152 },
0x0418, 0x0918, 0x0E20, 0x1820, 0x2230, 0x2C30, 0x4038, 0x5438, { 1024, -1024, 2304, -2304, 3584, -3584, 6144, -6144, 8704, -8704, 11264, -11264, 16384, -16384, 21504, -21504 },
0x0520, 0x0B20, 0x1128, 0x1D28, 0x2938, 0x3538, 0x4D38, 0x6F38, { 1280, -1280, 2816, -2816, 4352, -4352, 7424, -7424, 10496, -10496, 13568, -13568, 19712, -19712, 28416, -28416 },
0x0628, 0x0D28, 0x1430, 0x2230, 0x3038, 0x3E38, 0x5A38, 0x7638, { 1536, -1536, 3328, -3328, 5120, -5120, 8704, -8704, 12288, -12288, 15872, -15872, 23040, -23040, 30208, -30208 },
0x0730, 0x0F30, 0x1738, 0x2738, 0x3738, 0x4738, 0x6738, 0x7D38 { 1792, -1792, 3840, -3840, 5888, -5888, 9984, -9984, 14080, -14080, 18176, -18176, 26368, -26368, 32000, -32000 },
};
static const uint8_t next_step[8][16] =
{
{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 4 },
{ 0, 0, 0, 0, 1, 1, 1, 1, 3, 3, 3, 3, 4, 4, 5, 5 },
{ 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 5, 5, 6, 6 },
{ 2, 2, 2, 2, 3, 3, 3, 3, 5, 5, 5, 5, 6, 6, 7, 7 },
{ 3, 3, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6, 7, 7, 7, 7 },
{ 4, 4, 4, 4, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7 },
{ 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7 },
{ 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }
}; };
void decode_tgc(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int32_t first_sample, int32_t samples_to_do) void decode_tgc(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int32_t first_sample, int32_t samples_to_do)
{ {
for (int i = first_sample, sample_count = 0; i < first_sample + samples_to_do; i++, sample_count++) for (int i = first_sample, sample_count = 0; i < first_sample + samples_to_do; i++, sample_count++)
{ {
uint8_t samp = ((uint8_t)read_8bit(i/2, stream->streamfile) >> uint8_t nibble = ((uint8_t)read_8bit(stream->offset + i/2, stream->streamfile) >>
(i & 1 ? 4 : 0)) & 0xf; (i & 1 ? 4 : 0)) & 0xf;
uint8_t slopeIndex = stream->adpcm_scale | (samp >> 1); stream->adpcm_history1_32 += slope_table[stream->adpcm_step_index][nibble];
stream->adpcm_step_index = next_step [stream->adpcm_step_index][nibble];
stream->adpcm_step_index = slopeTable[slopeIndex] >> 8; if (stream->adpcm_history1_32 < -32768)
stream->adpcm_scale = slopeTable[slopeIndex] & 0xff; stream->adpcm_history1_32 = -32768;
stream->adpcm_history1_16 += (samp & 1) ? if (stream->adpcm_history1_32 > 32767)
-stream->adpcm_step_index: stream->adpcm_history1_32 = 32767;
stream->adpcm_step_index;
if (stream->adpcm_history1_16 < 0) outbuf[sample_count] = (sample_t)stream->adpcm_history1_32;
stream->adpcm_history1_16 = 0;
if (stream->adpcm_history1_16 > 0xff)
stream->adpcm_history1_16 = 0xff;
outbuf[sample_count] = stream->adpcm_history1_16 * 0x100 - 0x8000;
} }
} }

View file

@ -0,0 +1,103 @@
#ifndef _VORBIS_BITREADER_H
#define _VORBIS_BITREADER_H
/* Simple bitreader for Vorbis' bit format.
* Kept in .h since it's slightly faster (compiler can optimize statics better) */
typedef struct {
uint8_t* buf; /* buffer to read/write */
size_t bufsize; /* max size of the buffer */
uint32_t b_off; /* current offset in bits inside the buffer */
} bitstream_t;
/* convenience util */
static void init_bitstream(bitstream_t* b, uint8_t* buf, size_t bufsize) {
b->buf = buf;
b->bufsize = bufsize;
b->b_off = 0;
}
/* same as (1 << bits) - 1, but that seems to trigger some nasty UB when bits = 32
* (though in theory (1 << 32) = 0, 0 - 1 = UINT_MAX, but gives 0 compiling in some cases, but not always) */
static const uint32_t MASK_TABLE[33] = {
0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 0x0001ffff,
0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff,
0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff
};
/* Read bits (max 32) from buf and update the bit offset. Vorbis packs values in LSB order and byte by byte.
* (ex. from 2 bytes 00100111 00000001 we can could read 4b=0111 and 6b=010010, 6b=remainder (second value is split into the 2nd byte) */
static int rv_bits(bitstream_t* ib, uint32_t bits, uint32_t* value) {
uint32_t shift, mask, pos, val;
if (bits > 32 || ib->b_off + bits > ib->bufsize * 8)
goto fail;
pos = ib->b_off / 8; /* byte offset */
shift = ib->b_off % 8; /* bit sub-offset */
mask = MASK_TABLE[bits]; /* to remove upper in highest byte */
val = ib->buf[pos+0] >> shift;
if (bits + shift > 8) {
val |= ib->buf[pos+1] << (8u - shift);
if (bits + shift > 16) {
val |= ib->buf[pos+2] << (16u - shift);
if (bits + shift > 24) {
val |= ib->buf[pos+3] << (24u - shift);
if (bits + shift > 32) {
val |= ib->buf[pos+4] << (32u - shift); /* upper bits are lost (shifting over 32) */
}
}
}
}
*value = (val & mask);
ib->b_off += bits;
return 1;
fail:
VGM_LOG_ONCE("BITREADER: read fail\n");
*value = 0;
return 0;
}
#ifndef BITSTREAM_READ_ONLY
/* Write bits (max 32) to buf and update the bit offset. Vorbis packs values in LSB order and byte by byte.
* (ex. writing 1101011010 from b_off 2 we get 01101011 00001101 (value split, and 11 in the first byte skipped)*/
static int wv_bits(bitstream_t* ob, uint32_t bits, uint32_t value) {
uint32_t shift, mask, pos;
if (bits > 32 || ob->b_off + bits > ob->bufsize*8)
goto fail;
pos = ob->b_off / 8; /* byte offset */
shift = ob->b_off % 8; /* bit sub-offset */
mask = (1 << shift) - 1; /* to keep lower bits in lowest byte */
ob->buf[pos+0] = (value << shift) | (ob->buf[pos+0] & mask);
if (bits + shift > 8) {
ob->buf[pos+1] = value >> (8 - shift);
if (bits + shift > 16) {
ob->buf[pos+2] = value >> (16 - shift);
if (bits + shift > 24) {
ob->buf[pos+3] = value >> (24 - shift);
if (bits + shift > 32) {
/* upper bits are set to 0 (shifting unsigned) but shouldn't matter */
ob->buf[pos+4] = value >> (32 - shift);
}
}
}
}
ob->b_off += bits;
return 1;
fail:
VGM_LOG_ONCE("BITREADER: write fail\n");
return 0;
}
#endif
#endif

View file

@ -7,7 +7,7 @@
#define VORBIS_DEFAULT_BUFFER_SIZE 0x8000 /* should be at least the size of the setup header, ~0x2000 */ #define VORBIS_DEFAULT_BUFFER_SIZE 0x8000 /* should be at least the size of the setup header, ~0x2000 */
static void pcm_convert_float_to_16(int channels, sample_t * outbuf, int samples_to_do, float ** pcm); static void pcm_convert_float_to_16(sample_t* outbuf, int samples_to_do, float** pcm, int channels);
/** /**
* Inits a vorbis stream of some custom variety. * Inits a vorbis stream of some custom variety.
@ -19,8 +19,8 @@ static void pcm_convert_float_to_16(int channels, sample_t * outbuf, int samples
* *
* Reference: https://www.xiph.org/vorbis/doc/libvorbis/overview.html * Reference: https://www.xiph.org/vorbis/doc/libvorbis/overview.html
*/ */
vorbis_custom_codec_data * init_vorbis_custom(STREAMFILE *streamFile, 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) {
vorbis_custom_codec_data * data = NULL; vorbis_custom_codec_data* data = NULL;
int ok; int ok;
/* init stuff */ /* init stuff */
@ -46,11 +46,11 @@ vorbis_custom_codec_data * init_vorbis_custom(STREAMFILE *streamFile, off_t star
/* init header */ /* init header */
switch(data->type) { switch(data->type) {
case VORBIS_FSB: ok = vorbis_custom_setup_init_fsb(streamFile, start_offset, data); break; case VORBIS_FSB: ok = vorbis_custom_setup_init_fsb(sf, start_offset, data); break;
case VORBIS_WWISE: ok = vorbis_custom_setup_init_wwise(streamFile, start_offset, data); break; case VORBIS_WWISE: ok = vorbis_custom_setup_init_wwise(sf, start_offset, data); break;
case VORBIS_OGL: ok = vorbis_custom_setup_init_ogl(streamFile, start_offset, data); break; case VORBIS_OGL: ok = vorbis_custom_setup_init_ogl(sf, start_offset, data); break;
case VORBIS_SK: ok = vorbis_custom_setup_init_sk(streamFile, 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(streamFile, start_offset, data); break; case VORBIS_VID1: ok = vorbis_custom_setup_init_vid1(sf, start_offset, data); break;
default: goto fail; default: goto fail;
} }
if(!ok) goto fail; if(!ok) goto fail;
@ -75,9 +75,9 @@ fail:
} }
/* Decodes Vorbis packets into a libvorbis sample buffer, and copies them to outbuf */ /* Decodes Vorbis packets into a libvorbis sample buffer, and copies them to outbuf */
void decode_vorbis_custom(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels) { void decode_vorbis_custom(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do, int channels) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0]; VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
vorbis_custom_codec_data * data = vgmstream->codec_data; vorbis_custom_codec_data* data = vgmstream->codec_data;
size_t stream_size = get_streamfile_size(stream->streamfile); size_t stream_size = get_streamfile_size(stream->streamfile);
//data->op.packet = data->buffer;/* implicit from init */ //data->op.packet = data->buffer;/* implicit from init */
int samples_done = 0; int samples_done = 0;
@ -112,7 +112,7 @@ void decode_vorbis_custom(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t samp
/* get max samples and convert from Vorbis float pcm to 16bit pcm */ /* get max samples and convert from Vorbis float pcm to 16bit pcm */
if (samples_to_get > samples_to_do - samples_done) if (samples_to_get > samples_to_do - samples_done)
samples_to_get = samples_to_do - samples_done; samples_to_get = samples_to_do - samples_done;
pcm_convert_float_to_16(data->vi.channels, outbuf + samples_done * channels, samples_to_get, pcm); pcm_convert_float_to_16(outbuf + samples_done * channels, samples_to_get, pcm, data->vi.channels);
samples_done += samples_to_get; samples_done += samples_to_get;
} }
@ -167,10 +167,10 @@ decode_fail:
} }
/* converts from internal Vorbis format to standard PCM (mostly from Xiph's decoder_example.c) */ /* converts from internal Vorbis format to standard PCM (mostly from Xiph's decoder_example.c) */
static void pcm_convert_float_to_16(int channels, sample_t * outbuf, int samples_to_do, float ** pcm) { static void pcm_convert_float_to_16(sample_t* outbuf, int samples_to_do, float** pcm, int channels) {
int ch, s; int ch, s;
sample_t *ptr; sample_t* ptr;
float *channel; float* channel;
/* convert float PCM (multichannel float array, with pcm[0]=ch0, pcm[1]=ch1, pcm[2]=ch0, etc) /* convert float PCM (multichannel float array, with pcm[0]=ch0, pcm[1]=ch1, pcm[2]=ch0, etc)
* to 16 bit signed PCM ints (host order) and interleave + fix clipping */ * to 16 bit signed PCM ints (host order) and interleave + fix clipping */
@ -191,7 +191,7 @@ static void pcm_convert_float_to_16(int channels, sample_t * outbuf, int samples
/* ********************************************** */ /* ********************************************** */
void free_vorbis_custom(vorbis_custom_codec_data * data) { void free_vorbis_custom(vorbis_custom_codec_data* data) {
if (!data) if (!data)
return; return;
@ -205,17 +205,15 @@ void free_vorbis_custom(vorbis_custom_codec_data * data) {
free(data); free(data);
} }
void reset_vorbis_custom(VGMSTREAM *vgmstream) { void reset_vorbis_custom(VGMSTREAM* vgmstream) {
vorbis_custom_codec_data *data = vgmstream->codec_data; vorbis_custom_codec_data *data = vgmstream->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.
* To avoid having to parse different formats we'll just discard until the expected sample */
vorbis_synthesis_restart(&data->vd); vorbis_synthesis_restart(&data->vd);
data->samples_to_discard = 0; data->samples_to_discard = 0;
} }
void seek_vorbis_custom(VGMSTREAM *vgmstream, int32_t num_sample) { void seek_vorbis_custom(VGMSTREAM* vgmstream, int32_t num_sample) {
vorbis_custom_codec_data *data = vgmstream->codec_data; vorbis_custom_codec_data *data = vgmstream->codec_data;
if (!data) return; if (!data) return;

View file

@ -6,17 +6,49 @@
/* used by vorbis_custom_decoder.c, but scattered in other .c files */ /* used by vorbis_custom_decoder.c, but scattered in other .c files */
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
int vorbis_custom_setup_init_fsb(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data);
int vorbis_custom_setup_init_wwise(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data);
int vorbis_custom_setup_init_ogl(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data);
int vorbis_custom_setup_init_sk(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data);
int vorbis_custom_setup_init_vid1(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data);
int vorbis_custom_parse_packet_fsb(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data); /* custom Vorbis without Ogg layer */
int vorbis_custom_parse_packet_wwise(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data); struct vorbis_custom_codec_data {
int vorbis_custom_parse_packet_ogl(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data); vorbis_info vi; /* stream settings */
int vorbis_custom_parse_packet_sk(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data); vorbis_comment vc; /* stream comments */
int vorbis_custom_parse_packet_vid1(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data); vorbis_dsp_state vd; /* decoder global state */
vorbis_block vb; /* decoder local state */
ogg_packet op; /* fake packet for internal use */
uint8_t* buffer; /* internal raw data buffer */
size_t buffer_size;
size_t samples_to_discard; /* for looping purposes */
int samples_full; /* flag, samples available in vorbis buffers */
vorbis_custom_t type; /* Vorbis subtype */
vorbis_custom_config config; /* config depending on the mode */
/* Wwise Vorbis: saved data to reconstruct modified packets */
uint8_t mode_blockflag[64+1]; /* max 6b+1; flags 'n stuff */
int mode_bits; /* bits to store mode_number */
uint8_t prev_blockflag; /* blockflag in the last decoded packet */
/* Ogg-style Vorbis: packet within a page */
int current_packet;
/* reference for page/blocks */
off_t block_offset;
size_t block_size;
int prev_block_samples; /* count for optimization */
};
int vorbis_custom_setup_init_fsb(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data);
int vorbis_custom_setup_init_wwise(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data);
int vorbis_custom_setup_init_ogl(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_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_ogl(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);
#endif/* VGM_USE_VORBIS */ #endif/* VGM_USE_VORBIS */
#endif/*_VORBIS_CUSTOM_DECODER_H_ */ #endif/*_VORBIS_CUSTOM_DECODER_H_ */

View file

@ -13,13 +13,13 @@
/* DEFS */ /* DEFS */
/* **************************************************************************** */ /* **************************************************************************** */
static int build_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_short, int blocksize_long); static int build_header_identification(uint8_t* buf, size_t bufsize, int channels, int sample_rate, int blocksize_short, int blocksize_long);
static int build_header_comment(uint8_t * buf, size_t bufsize); static int build_header_comment(uint8_t* buf, size_t bufsize);
static int build_header_setup(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile); static int build_header_setup(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf);
static int load_fvs_file_single(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile); static int load_fvs_file_single(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf);
static int load_fvs_file_multi(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile); static int load_fvs_file_multi(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf);
static int load_fvs_array(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile); static int load_fvs_array(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf);
/* **************************************************************************** */ /* **************************************************************************** */
@ -32,7 +32,7 @@ static int load_fvs_array(uint8_t * buf, size_t bufsize, uint32_t setup_id, STRE
* Format info from python-fsb5 (https://github.com/HearthSim/python-fsb5) and * Format info from python-fsb5 (https://github.com/HearthSim/python-fsb5) and
* 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 *streamFile, 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;
data->op.bytes = build_header_identification(data->buffer, data->buffer_size, cfg.channels, cfg.sample_rate, 256, 2048); /* FSB default block sizes */ data->op.bytes = build_header_identification(data->buffer, data->buffer_size, cfg.channels, cfg.sample_rate, 256, 2048); /* FSB default block sizes */
@ -43,7 +43,7 @@ int vorbis_custom_setup_init_fsb(STREAMFILE *streamFile, off_t start_offset, vor
if (!data->op.bytes) goto fail; if (!data->op.bytes) goto fail;
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) !=0 ) goto fail; /* parse comment header */ if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) !=0 ) goto fail; /* parse comment header */
data->op.bytes = build_header_setup(data->buffer, data->buffer_size, cfg.setup_id, streamFile); data->op.bytes = build_header_setup(data->buffer, data->buffer_size, cfg.setup_id, sf);
if (!data->op.bytes) goto fail; if (!data->op.bytes) goto fail;
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse setup header */ if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse setup header */
@ -54,7 +54,7 @@ fail:
} }
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) {
size_t bytes; size_t bytes;
/* get next packet size from the FSB 16b header (doesn't count this 16b) */ /* get next packet size from the FSB 16b header (doesn't count this 16b) */
@ -77,7 +77,7 @@ fail:
/* INTERNAL HELPERS */ /* INTERNAL HELPERS */
/* **************************************************************************** */ /* **************************************************************************** */
static int build_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_short, int blocksize_long) { static int build_header_identification(uint8_t* buf, size_t bufsize, int channels, int sample_rate, int blocksize_short, int blocksize_long) {
int bytes = 0x1e; int bytes = 0x1e;
uint8_t blocksizes, exp_blocksize_0, exp_blocksize_1; uint8_t blocksizes, exp_blocksize_0, exp_blocksize_1;
@ -122,7 +122,7 @@ static int build_header_identification(uint8_t * buf, size_t bufsize, int channe
return bytes; return bytes;
} }
static int build_header_comment(uint8_t * buf, size_t bufsize) { static int build_header_comment(uint8_t* buf, size_t bufsize) {
int bytes = 0x19; int bytes = 0x19;
if (bytes > bufsize) return 0; if (bytes > bufsize) return 0;
@ -137,20 +137,20 @@ static int build_header_comment(uint8_t * buf, size_t bufsize) {
return bytes; return bytes;
} }
static int build_header_setup(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile) { static int build_header_setup(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) {
int bytes; int bytes;
/* try to locate from the precompiled list */ /* try to locate from the precompiled list */
bytes = load_fvs_array(buf, bufsize, setup_id, streamFile); bytes = load_fvs_array(buf, bufsize, setup_id, sf);
if (bytes) if (bytes)
return bytes; return bytes;
/* try to load from external files */ /* try to load from external files */
bytes = load_fvs_file_single(buf, bufsize, setup_id, streamFile); bytes = load_fvs_file_single(buf, bufsize, setup_id, sf);
if (bytes) if (bytes)
return bytes; return bytes;
bytes = load_fvs_file_multi(buf, bufsize, setup_id, streamFile); bytes = load_fvs_file_multi(buf, bufsize, setup_id, sf);
if (bytes) if (bytes)
return bytes; return bytes;
@ -159,8 +159,8 @@ static int build_header_setup(uint8_t * buf, size_t bufsize, uint32_t setup_id,
return 0; return 0;
} }
static int load_fvs_file_single(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile) { static int load_fvs_file_single(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) {
STREAMFILE * streamFileSetup = NULL; STREAMFILE* sf_setup = NULL;
{ {
char setupname[PATH_LIMIT]; char setupname[PATH_LIMIT];
@ -168,7 +168,7 @@ static int load_fvs_file_single(uint8_t * buf, size_t bufsize, uint32_t setup_id
char *path; char *path;
/* read "(dir/).fvs_{setup_id}" */ /* read "(dir/).fvs_{setup_id}" */
streamFile->get_name(streamFile,pathname,sizeof(pathname)); sf->get_name(sf,pathname,sizeof(pathname));
path = strrchr(pathname,DIR_SEPARATOR); path = strrchr(pathname,DIR_SEPARATOR);
if (path) if (path)
*(path+1) = '\0'; *(path+1) = '\0';
@ -176,36 +176,36 @@ static int load_fvs_file_single(uint8_t * buf, size_t bufsize, uint32_t setup_id
pathname[0] = '\0'; pathname[0] = '\0';
snprintf(setupname,PATH_LIMIT,"%s.fvs_%08x", pathname, setup_id); snprintf(setupname,PATH_LIMIT,"%s.fvs_%08x", pathname, setup_id);
streamFileSetup = streamFile->open(streamFile,setupname,STREAMFILE_DEFAULT_BUFFER_SIZE); sf_setup = sf->open(sf,setupname,STREAMFILE_DEFAULT_BUFFER_SIZE);
} }
if (streamFileSetup) { if (sf_setup) {
/* file found, get contents into the buffer */ /* file found, get contents into the buffer */
size_t bytes = streamFileSetup->get_size(streamFileSetup); size_t bytes = sf_setup->get_size(sf_setup);
if (bytes > bufsize) goto fail; if (bytes > bufsize) goto fail;
if (read_streamfile(buf, 0, bytes, streamFileSetup) != bytes) if (read_streamfile(buf, 0, bytes, sf_setup) != bytes)
goto fail; goto fail;
streamFileSetup->close(streamFileSetup); sf_setup->close(sf_setup);
return bytes; return bytes;
} }
fail: fail:
if (streamFileSetup) streamFileSetup->close(streamFileSetup); if (sf_setup) sf_setup->close(sf_setup);
return 0; return 0;
} }
static int load_fvs_file_multi(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile) { static int load_fvs_file_multi(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) {
STREAMFILE * streamFileSetup = NULL; STREAMFILE* sf_setup = NULL;
{ {
char setupname[PATH_LIMIT]; char setupname[PATH_LIMIT];
char pathname[PATH_LIMIT]; char pathname[PATH_LIMIT];
char *path; char* path;
/* read "(dir/).fvs" */ /* read "(dir/).fvs" */
streamFile->get_name(streamFile,pathname,sizeof(pathname)); sf->get_name(sf,pathname,sizeof(pathname));
path = strrchr(pathname,DIR_SEPARATOR); path = strrchr(pathname,DIR_SEPARATOR);
if (path) if (path)
*(path+1) = '\0'; *(path+1) = '\0';
@ -213,41 +213,41 @@ static int load_fvs_file_multi(uint8_t * buf, size_t bufsize, uint32_t setup_id,
pathname[0] = '\0'; pathname[0] = '\0';
snprintf(setupname,PATH_LIMIT,"%s.fvs", pathname); snprintf(setupname,PATH_LIMIT,"%s.fvs", pathname);
streamFileSetup = streamFile->open(streamFile,setupname,STREAMFILE_DEFAULT_BUFFER_SIZE); sf_setup = sf->open(sf,setupname,STREAMFILE_DEFAULT_BUFFER_SIZE);
} }
if (streamFileSetup) { if (sf_setup) {
/* file found: read mini-header (format by bnnm, feel free to change) and locate FVS */ /* file found: read mini-header (format by bnnm, feel free to change) and locate FVS */
int entries, i; int entries, i;
uint32_t offset = 0, size = 0; uint32_t offset = 0, size = 0;
if (read_32bitBE(0x0, streamFileSetup) != 0x56465653) goto fail; /* "VFVS" */ if (read_32bitBE(0x0, sf_setup) != 0x56465653) goto fail; /* "VFVS" */
entries = read_32bitLE(0x08, streamFileSetup); /* 0x04=v0, 0x0c-0x20: reserved */ entries = read_32bitLE(0x08, sf_setup); /* 0x04=v0, 0x0c-0x20: reserved */
if (entries <= 0) goto fail; if (entries <= 0) goto fail;
for (i=0; i < entries; i++) { /* entry = id, offset, size, reserved */ for (i=0; i < entries; i++) { /* entry = id, offset, size, reserved */
if ((uint32_t)read_32bitLE(0x20 + i*0x10, streamFileSetup) == setup_id) { if ((uint32_t)read_32bitLE(0x20 + i*0x10, sf_setup) == setup_id) {
offset = read_32bitLE(0x24 + i*0x10, streamFileSetup); offset = read_32bitLE(0x24 + i*0x10, sf_setup);
size = read_32bitLE(0x28 + i*0x10, streamFileSetup); size = read_32bitLE(0x28 + i*0x10, sf_setup);
break; break;
} }
} }
if (!size || !offset || size > bufsize) goto fail; if (!size || !offset || size > bufsize) goto fail;
/* read into buf */ /* read into buf */
if (read_streamfile(buf, offset, size, streamFileSetup) != size) if (read_streamfile(buf, offset, size, sf_setup) != size)
goto fail; goto fail;
streamFileSetup->close(streamFileSetup); sf_setup->close(sf_setup);
return size; return size;
} }
fail: fail:
if (streamFileSetup) streamFileSetup->close(streamFileSetup); if (sf_setup) sf_setup->close(sf_setup);
return 0; return 0;
} }
static int load_fvs_array(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile) { static int load_fvs_array(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) {
#if FSB_VORBIS_USE_PRECOMPILED_FVS #if FSB_VORBIS_USE_PRECOMPILED_FVS
int i, list_length; int i, list_length;

View file

@ -12,30 +12,30 @@
* OGL removes the Ogg layer and uses 16b packet headers, that have the size of the next packet, but * OGL removes the Ogg layer and uses 16b packet headers, that have the size of the next packet, but
* the lower 2b need to be removed (usually 00 but 01 for the id packet, not sure about the meaning). * the lower 2b need to be removed (usually 00 but 01 for the id packet, not sure about the meaning).
*/ */
int vorbis_custom_setup_init_ogl(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data) { int vorbis_custom_setup_init_ogl(STREAMFILE* sf, off_t start_offset, vorbis_custom_codec_data* data) {
off_t offset = start_offset; off_t offset = start_offset;
size_t packet_size; size_t packet_size;
/* read 3 packets with triad (id/comment/setup), each with an OGL header */ /* read 3 packets with triad (id/comment/setup), each with an OGL header */
/* normal identificacion packet */ /* normal identificacion packet */
packet_size = (uint16_t)read_16bitLE(offset, streamFile) >> 2; packet_size = (uint16_t)read_16bitLE(offset, sf) >> 2;
if (packet_size > data->buffer_size) goto fail; if (packet_size > data->buffer_size) goto fail;
data->op.bytes = read_streamfile(data->buffer,offset+2,packet_size, streamFile); data->op.bytes = read_streamfile(data->buffer,offset+2,packet_size, sf);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse identification header */ if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse identification header */
offset += 2+packet_size; offset += 2+packet_size;
/* normal comment packet */ /* normal comment packet */
packet_size = (uint16_t)read_16bitLE(offset, streamFile) >> 2; packet_size = (uint16_t)read_16bitLE(offset, sf) >> 2;
if (packet_size > data->buffer_size) goto fail; if (packet_size > data->buffer_size) goto fail;
data->op.bytes = read_streamfile(data->buffer,offset+2,packet_size, streamFile); data->op.bytes = read_streamfile(data->buffer,offset+2,packet_size, sf);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) !=0 ) goto fail; /* parse comment header */ if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) !=0 ) goto fail; /* parse comment header */
offset += 2+packet_size; offset += 2+packet_size;
/* normal setup packet */ /* normal setup packet */
packet_size = (uint16_t)read_16bitLE(offset, streamFile) >> 2; packet_size = (uint16_t)read_16bitLE(offset, sf) >> 2;
if (packet_size > data->buffer_size) goto fail; if (packet_size > data->buffer_size) goto fail;
data->op.bytes = read_streamfile(data->buffer,offset+2,packet_size, streamFile); data->op.bytes = read_streamfile(data->buffer,offset+2,packet_size, sf);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse setup header */ if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse setup header */
offset += 2+packet_size; offset += 2+packet_size;
@ -49,7 +49,7 @@ fail:
} }
int vorbis_custom_parse_packet_ogl(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data) { int vorbis_custom_parse_packet_ogl(VGMSTREAMCHANNEL* stream, vorbis_custom_codec_data* data) {
size_t bytes; size_t bytes;
/* get next packet size from the OGL 16b header (upper 14b) */ /* get next packet size from the OGL 16b header (upper 14b) */

View file

@ -7,8 +7,8 @@
/* DEFS */ /* DEFS */
/* **************************************************************************** */ /* **************************************************************************** */
static int get_page_info(STREAMFILE *streamFile, off_t page_offset, off_t *out_packet_offset, size_t *out_packet_size, int *out_page_packets, int target_packet); static int get_page_info(STREAMFILE* sf, off_t page_offset, off_t* p_packet_offset, size_t* p_packet_size, int* p_page_packets, int target_packet);
static int build_header(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile, off_t packet_offset, size_t packet_size); static int build_header(uint8_t* buf, size_t bufsize, STREAMFILE* sf, off_t packet_offset, size_t packet_size);
/* **************************************************************************** */ /* **************************************************************************** */
@ -21,7 +21,7 @@ static int build_header(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile, o
* *
* A simpler way to implement this would be in ogg_vorbis_file with read callbacks (pretend this is proof of concept). * A simpler way to implement this would be in ogg_vorbis_file with read callbacks (pretend this is proof of concept).
*/ */
int vorbis_custom_setup_init_sk(STREAMFILE *streamFile, 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) {
off_t offset = start_offset; off_t offset = start_offset;
off_t id_offset = 0, comment_offset = 0, setup_offset = 0; off_t id_offset = 0, comment_offset = 0, setup_offset = 0;
size_t id_size = 0, comment_size = 0, setup_size = 0; size_t id_size = 0, comment_size = 0, setup_size = 0;
@ -30,28 +30,28 @@ int vorbis_custom_setup_init_sk(STREAMFILE *streamFile, off_t start_offset, vorb
/* rebuild header packets, they are standard except the "vorbis" keyword is replaced by "SK" */ /* rebuild header packets, they are standard except the "vorbis" keyword is replaced by "SK" */
/* first page has the id packet */ /* first page has the id packet */
if (!get_page_info(streamFile, offset, &id_offset, &id_size, &page_packets, 0)) goto fail; if (!get_page_info(sf, offset, &id_offset, &id_size, &page_packets, 0)) goto fail;
if (page_packets != 1) goto fail; if (page_packets != 1) goto fail;
offset = id_offset + id_size; offset = id_offset + id_size;
/* second page has the comment and setup packets */ /* second page has the comment and setup packets */
if (!get_page_info(streamFile, offset, &comment_offset, &comment_size, &page_packets, 0)) goto fail; if (!get_page_info(sf, offset, &comment_offset, &comment_size, &page_packets, 0)) goto fail;
if (page_packets != 2) goto fail; if (page_packets != 2) goto fail;
if (!get_page_info(streamFile, offset, &setup_offset, &setup_size, &page_packets, 1)) goto fail; if (!get_page_info(sf, offset, &setup_offset, &setup_size, &page_packets, 1)) goto fail;
if (page_packets != 2) goto fail; if (page_packets != 2) goto fail;
offset = comment_offset + comment_size + setup_size; offset = comment_offset + comment_size + setup_size;
/* init with all offsets found */ /* init with all offsets found */
data->op.bytes = build_header(data->buffer, data->buffer_size, streamFile, id_offset, id_size); data->op.bytes = build_header(data->buffer, data->buffer_size, sf, id_offset, id_size);
if (!data->op.bytes) goto fail; if (!data->op.bytes) goto fail;
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse identification header */ if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse identification header */
data->op.bytes = build_header(data->buffer, data->buffer_size, streamFile, comment_offset, comment_size); data->op.bytes = build_header(data->buffer, data->buffer_size, sf, comment_offset, comment_size);
if (!data->op.bytes) goto fail; if (!data->op.bytes) goto fail;
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) !=0 ) goto fail; /* parse comment header */ if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) !=0 ) goto fail; /* parse comment header */
data->op.bytes = build_header(data->buffer, data->buffer_size, streamFile, setup_offset, setup_size); data->op.bytes = build_header(data->buffer, data->buffer_size, sf, setup_offset, setup_size);
if (!data->op.bytes) goto fail; if (!data->op.bytes) goto fail;
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse setup header */ if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse setup header */
@ -65,7 +65,7 @@ fail:
} }
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) {
off_t packet_offset = 0; off_t packet_offset = 0;
size_t packet_size = 0; size_t packet_size = 0;
int page_packets; int page_packets;
@ -113,7 +113,7 @@ fail:
* 0x--(n): data * 0x--(n): data
* Reference: https://xiph.org/ogg/doc/framing.html * Reference: https://xiph.org/ogg/doc/framing.html
*/ */
static int get_page_info(STREAMFILE *streamFile, off_t page_offset, off_t *out_packet_offset, size_t *out_packet_size, int *out_page_packets, int target_packet) { static int get_page_info(STREAMFILE* sf, off_t page_offset, off_t* p_packet_offset, size_t* p_packet_size, int* p_page_packets, int target_packet) {
off_t table_offset, current_packet_offset, target_packet_offset = 0; off_t table_offset, current_packet_offset, target_packet_offset = 0;
size_t total_packets_size = 0, current_packet_size = 0, target_packet_size = 0; size_t total_packets_size = 0, current_packet_size = 0, target_packet_size = 0;
int page_packets = 0; int page_packets = 0;
@ -121,18 +121,18 @@ static int get_page_info(STREAMFILE *streamFile, off_t page_offset, off_t *out_p
int i; int i;
if (read_32bitBE(page_offset+0x00, streamFile) != 0x11534B10) /* \11"SK"\10 */ if (read_32bitBE(page_offset+0x00, sf) != 0x11534B10) /* \11"SK"\10 */
goto fail; /* not a valid page */ goto fail; /* not a valid page */
/* No point on validating other stuff, but they look legal enough (CRC too it seems) */ /* No point on validating other stuff, but they look legal enough (CRC too it seems) */
segments = (uint8_t)read_8bit(page_offset+0x1a, streamFile); segments = (uint8_t)read_8bit(page_offset+0x1a, sf);
table_offset = page_offset + 0x1b; table_offset = page_offset + 0x1b;
current_packet_offset = page_offset + 0x1b + segments; /* first packet starts after segments */ current_packet_offset = page_offset + 0x1b + segments; /* first packet starts after segments */
/* process segments */ /* process segments */
for (i = 0; i < segments; i++) { for (i = 0; i < segments; i++) {
uint8_t segment_size = (uint8_t)read_8bit(table_offset, streamFile); uint8_t segment_size = (uint8_t)read_8bit(table_offset, sf);
total_packets_size += segment_size; total_packets_size += segment_size;
current_packet_size += segment_size; current_packet_size += segment_size;
table_offset += 0x01; table_offset += 0x01;
@ -158,9 +158,9 @@ static int get_page_info(STREAMFILE *streamFile, off_t page_offset, off_t *out_p
target_packet_size = total_packets_size; target_packet_size = total_packets_size;
} }
if (out_packet_offset) *out_packet_offset = target_packet_offset; if (p_packet_offset) *p_packet_offset = target_packet_offset;
if (out_packet_size) *out_packet_size = target_packet_size; if (p_packet_size) *p_packet_size = target_packet_size;
if (out_page_packets) *out_page_packets = page_packets; if (p_page_packets) *p_page_packets = page_packets;
return 1; return 1;
@ -170,14 +170,14 @@ fail:
} }
/* rebuild a "SK" header packet to a "vorbis" one */ /* rebuild a "SK" header packet to a "vorbis" one */
static int build_header(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile, off_t packet_offset, size_t packet_size) { static int build_header(uint8_t* buf, size_t bufsize, STREAMFILE* sf, off_t packet_offset, size_t packet_size) {
int bytes; int bytes;
if (0x07+packet_size-0x03 > bufsize) return 0; if (0x07+packet_size-0x03 > bufsize) return 0;
put_8bit (buf+0x00, read_8bit(packet_offset,streamFile)); /* packet_type */ put_8bit (buf+0x00, read_8bit(packet_offset,sf)); /* packet_type */
memcpy (buf+0x01, "vorbis", 6); /* id */ memcpy (buf+0x01, "vorbis", 6); /* id */
bytes = read_streamfile(buf+0x07,packet_offset+0x03, packet_size-0x03,streamFile); /* copy rest (all except id+"SK") */ bytes = read_streamfile(buf+0x07,packet_offset+0x03, packet_size-0x03,sf); /* copy rest (all except id+"SK") */
if (packet_size-0x03 != bytes) if (packet_size-0x03 != bytes)
return 0; return 0;

View file

@ -1,5 +1,8 @@
#include "vorbis_custom_decoder.h" #include "vorbis_custom_decoder.h"
#define BITSTREAM_READ_ONLY /* config */
#include "vorbis_bitreader.h"
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
#include <vorbis/codec.h> #include <vorbis/codec.h>
@ -8,8 +11,8 @@
/* DEFS */ /* DEFS */
/* **************************************************************************** */ /* **************************************************************************** */
static int get_packet_header(STREAMFILE *streamFile, off_t *offset, size_t *size); static int get_packet_header(STREAMFILE* sf, off_t* offset, size_t* size);
static int build_header_comment(uint8_t * buf, size_t bufsize); static int build_header_comment(uint8_t* buf, size_t bufsize);
/* **************************************************************************** */ /* **************************************************************************** */
@ -21,16 +24,16 @@ static int build_header_comment(uint8_t * buf, size_t bufsize);
* *
* Info from hcs's vid1_2ogg: https://github.com/hcs64/vgm_ripping/tree/master/demux/vid1_2ogg * Info from hcs's vid1_2ogg: https://github.com/hcs64/vgm_ripping/tree/master/demux/vid1_2ogg
*/ */
int vorbis_custom_setup_init_vid1(STREAMFILE *streamFile, 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) {
off_t offset = start_offset; off_t offset = start_offset;
size_t packet_size = 0; size_t packet_size = 0;
/* read header packets (id/setup), each with an VID1 header */ /* read header packets (id/setup), each with an VID1 header */
/* normal identificacion packet */ /* normal identificacion packet */
get_packet_header(streamFile, &offset, &packet_size); get_packet_header(sf, &offset, &packet_size);
if (packet_size > data->buffer_size) goto fail; if (packet_size > data->buffer_size) goto fail;
data->op.bytes = read_streamfile(data->buffer,offset,packet_size, streamFile); data->op.bytes = read_streamfile(data->buffer,offset,packet_size, sf);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse identification header */ if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse identification header */
offset += packet_size; offset += packet_size;
@ -40,9 +43,9 @@ int vorbis_custom_setup_init_vid1(STREAMFILE *streamFile, off_t start_offset, vo
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) !=0 ) goto fail; /* parse comment header */ if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) !=0 ) goto fail; /* parse comment header */
/* normal setup packet */ /* normal setup packet */
get_packet_header(streamFile, &offset, &packet_size); get_packet_header(sf, &offset, &packet_size);
if (packet_size > data->buffer_size) goto fail; if (packet_size > data->buffer_size) goto fail;
data->op.bytes = read_streamfile(data->buffer,offset,packet_size, streamFile); data->op.bytes = read_streamfile(data->buffer,offset,packet_size, sf);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse setup header */ if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse setup header */
offset += packet_size; offset += packet_size;
@ -53,7 +56,7 @@ fail:
} }
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) {
size_t bytes; size_t bytes;
@ -100,7 +103,7 @@ fail:
/* INTERNAL HELPERS */ /* INTERNAL HELPERS */
/* **************************************************************************** */ /* **************************************************************************** */
static int build_header_comment(uint8_t * buf, size_t bufsize) { static int build_header_comment(uint8_t* buf, size_t bufsize) {
int bytes = 0x19; int bytes = 0x19;
if (bytes > bufsize) return 0; if (bytes > bufsize) return 0;
@ -116,26 +119,24 @@ static int build_header_comment(uint8_t * buf, size_t bufsize) {
} }
/* read header in Vorbis bitpacking format */ /* read header in Vorbis bitpacking format */
static int get_packet_header(STREAMFILE *streamFile, off_t *offset, size_t *size) { static int get_packet_header(STREAMFILE* sf, off_t* offset, size_t* size) {
uint8_t ibuf[0x04]; /* header buffer */ uint8_t ibuf[0x04]; /* header buffer */
size_t ibufsize = 0x04; /* header ~max */ size_t ibufsize = 0x04; /* header ~max */
vgm_bitstream ib = {0}; bitstream_t ib = {0};
uint32_t size_bits; uint32_t size_bits;
if (read_streamfile(ibuf,(*offset),ibufsize, streamFile) != ibufsize) if (read_streamfile(ibuf,(*offset),ibufsize, sf) != ibufsize)
goto fail; goto fail;
ib.buf = ibuf;
ib.bufsize = ibufsize; init_bitstream(&ib, ibuf, ibufsize);
ib.b_off = 0;
ib.mode = BITSTREAM_VORBIS;
/* read using Vorbis weird LSF */ /* read using Vorbis weird LSF */
r_bits(&ib, 4,&size_bits); rv_bits(&ib, 4,&size_bits);
r_bits(&ib, (size_bits+1),(uint32_t*)size); rv_bits(&ib, (size_bits+1),(uint32_t*)size);
/* special meaning, seen in silent frames */ /* special meaning, seen in silent frames */
if (size_bits == 0 && *size == 0 && (uint8_t)read_8bit(*offset, streamFile)==0x80) { if (size_bits == 0 && *size == 0 && (uint8_t)read_8bit(*offset, sf) == 0x80) {
*size = 0x01; *size = 0x01;
} }

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,32 @@
#ifndef _DECODE_H
#define _DECODE_H
#include "vgmstream.h"
void free_codec(VGMSTREAM* vgmstream);
void seek_codec(VGMSTREAM* vgmstream);
void reset_codec(VGMSTREAM* vgmstream);
/* Decode samples into the buffer. Assume that we have written samples_written into the
* buffer already, and we have samples_to_do consecutive samples ahead of us. */
void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_do, sample_t* buffer);
/* Detect loop start and save values, or detect loop end and restore (loop back). Returns 1 if loop was done. */
int vgmstream_do_loop(VGMSTREAM* vgmstream);
/* Calculate number of consecutive samples to do (taking into account stopping for loop start and end) */
int get_vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMSTREAM* vgmstream);
/* Get the number of samples of a single frame (smallest self-contained sample group, 1/N channels) */
int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream);
/* Get the number of bytes of a single frame (smallest self-contained byte group, 1/N channels) */
int get_vgmstream_frame_size(VGMSTREAM* vgmstream);
/* In NDS IMA the frame size is the block size, but last one is shorter */
int get_vgmstream_samples_per_shortframe(VGMSTREAM* vgmstream);
int get_vgmstream_shortframe_size(VGMSTREAM* vgmstream);
#endif

View file

@ -138,7 +138,7 @@ static const char* extension_list[] = {
"cxs", "cxs",
"da", "da",
"dat", //"dat", //common
"data", "data",
"dax", "dax",
"dbm", "dbm",
@ -150,6 +150,7 @@ static const char* extension_list[] = {
"diva", "diva",
"dmsg", "dmsg",
"ds2", //txth/reserved [Star Wars Bounty Hunter (GC)] "ds2", //txth/reserved [Star Wars Bounty Hunter (GC)]
"dsb",
"dsf", "dsf",
"dsp", "dsp",
"dspw", "dspw",
@ -242,7 +243,6 @@ static const char* extension_list[] = {
"kat", "kat",
"kces", "kces",
"kcey", //fake extension/header id for .pcm (renamed, to be removed) "kcey", //fake extension/header id for .pcm (renamed, to be removed)
"khv", //fake extension/header id for .vas (renamed, to be removed)
"km9", "km9",
"kovs", //fake extension/header id for .kvs "kovs", //fake extension/header id for .kvs
"kns", "kns",
@ -395,6 +395,7 @@ static const char* extension_list[] = {
"rsd", "rsd",
"rsf", "rsf",
"rsm", "rsm",
"rsp",
"rstm", //fake extension/header id for .rstm (in bigfiles) "rstm", //fake extension/header id for .rstm (in bigfiles)
"rvws", "rvws",
"rwar", "rwar",
@ -559,6 +560,7 @@ static const char* extension_list[] = {
"wem", "wem",
"wii", "wii",
"wip", //txth/reserved [Colin McRae DiRT (PC)] "wip", //txth/reserved [Colin McRae DiRT (PC)]
"wlv", //txth/reserved [ToeJam & Earl III: Mission to Earth (DC)]
"wma", //common "wma", //common
"wmus", "wmus",
"wp2", "wp2",
@ -609,6 +611,7 @@ static const char* extension_list[] = {
"zsm", "zsm",
"zss", "zss",
"zwdsp", "zwdsp",
"zwv",
"vgmstream" /* fake extension, catch-all for FFmpeg/txth/etc */ "vgmstream" /* fake extension, catch-all for FFmpeg/txth/etc */
@ -621,6 +624,7 @@ static const char* common_extension_list[] = {
"aif", //common "aif", //common
"aiff", //common "aiff", //common
"bin", //common "bin", //common
"dat", //common
"flac", //common "flac", //common
"m4a", //common "m4a", //common
"m4v", //common "m4v", //common
@ -666,6 +670,8 @@ typedef struct {
static const coding_info coding_info_list[] = { static const coding_info coding_info_list[] = {
{coding_SILENCE, "Silence"},
{coding_PCM16LE, "Little Endian 16-bit PCM"}, {coding_PCM16LE, "Little Endian 16-bit PCM"},
{coding_PCM16BE, "Big Endian 16-bit PCM"}, {coding_PCM16BE, "Big Endian 16-bit PCM"},
{coding_PCM16_int, "16-bit PCM with 2 byte interleave (block)"}, {coding_PCM16_int, "16-bit PCM with 2 byte interleave (block)"},
@ -737,6 +743,7 @@ static const coding_info coding_info_list[] = {
{coding_AWC_IMA, "Rockstar AWC 4-bit IMA ADPCM"}, {coding_AWC_IMA, "Rockstar AWC 4-bit IMA ADPCM"},
{coding_UBI_IMA, "Ubisoft 4-bit IMA ADPCM"}, {coding_UBI_IMA, "Ubisoft 4-bit IMA ADPCM"},
{coding_H4M_IMA, "Hudson HVQM4 4-bit IMA ADPCM"}, {coding_H4M_IMA, "Hudson HVQM4 4-bit IMA ADPCM"},
{coding_CD_IMA, "Crystal Dynamics 4-bit IMA ADPCM"},
{coding_MSADPCM, "Microsoft 4-bit ADPCM"}, {coding_MSADPCM, "Microsoft 4-bit ADPCM"},
{coding_MSADPCM_int, "Microsoft 4-bit ADPCM (mono/interleave)"}, {coding_MSADPCM_int, "Microsoft 4-bit ADPCM (mono/interleave)"},
@ -863,6 +870,7 @@ static const layout_info layout_info_list[] = {
}; };
static const meta_info meta_info_list[] = { static const meta_info meta_info_list[] = {
{meta_SILENCE, "Silence"},
{meta_RSTM, "Nintendo RSTM header"}, {meta_RSTM, "Nintendo RSTM header"},
{meta_STRM, "Nintendo STRM header"}, {meta_STRM, "Nintendo STRM header"},
{meta_ADX_03, "CRI ADX header type 03"}, {meta_ADX_03, "CRI ADX header type 03"},
@ -896,7 +904,7 @@ static const meta_info meta_info_list[] = {
{meta_PS2_OMU, "Alter Echo OMU Header"}, {meta_PS2_OMU, "Alter Echo OMU Header"},
{meta_DSP_STM, "Intelligent Systems STM header"}, {meta_DSP_STM, "Intelligent Systems STM header"},
{meta_PS2_EXST, "Sony EXST header"}, {meta_PS2_EXST, "Sony EXST header"},
{meta_PS2_SVAG, "Konami SVAG header"}, {meta_SVAG_KCET, "Konami SVAG header"},
{meta_PS_HEADERLESS, "Headerless PS-ADPCM raw header"}, {meta_PS_HEADERLESS, "Headerless PS-ADPCM raw header"},
{meta_PS2_MIB_MIH, "Sony MultiStream MIH+MIB header"}, {meta_PS2_MIB_MIH, "Sony MultiStream MIH+MIB header"},
{meta_DSP_MPDSP, "Single DSP header stereo by .mpdsp extension"}, {meta_DSP_MPDSP, "Single DSP header stereo by .mpdsp extension"},
@ -945,11 +953,11 @@ static const meta_info meta_info_list[] = {
{meta_EA_1SNH, "Electronic Arts 1SNh header"}, {meta_EA_1SNH, "Electronic Arts 1SNh header"},
{meta_EA_EACS, "Electronic Arts EACS header"}, {meta_EA_EACS, "Electronic Arts EACS header"},
{meta_SL3, "Atari Melbourne House SL3 header"}, {meta_SL3, "Atari Melbourne House SL3 header"},
{meta_FSB1, "FMOD Sample Bank (FSB1) Header"}, {meta_FSB1, "FMOD FSB1 header"},
{meta_FSB2, "FMOD Sample Bank (FSB2) Header"}, {meta_FSB2, "FMOD FSB2 header"},
{meta_FSB3, "FMOD Sample Bank (FSB3) Header"}, {meta_FSB3, "FMOD FSB3 header"},
{meta_FSB4, "FMOD Sample Bank (FSB4) Header"}, {meta_FSB4, "FMOD FSB4 header"},
{meta_FSB5, "FMOD Sample Bank (FSB5) Header"}, {meta_FSB5, "FMOD FSB5 header"},
{meta_RWX, "RWX Header"}, {meta_RWX, "RWX Header"},
{meta_XWB, "Microsoft XWB header"}, {meta_XWB, "Microsoft XWB header"},
{meta_PS2_XA30, "Reflections XA30 PS2 header"}, {meta_PS2_XA30, "Reflections XA30 PS2 header"},
@ -1062,7 +1070,7 @@ static const meta_info meta_info_list[] = {
{meta_NGC_SCK_DSP, "The Scorpion King SCK Header"}, {meta_NGC_SCK_DSP, "The Scorpion King SCK Header"},
{meta_CAFF, "Apple Core Audio Format File header"}, {meta_CAFF, "Apple Core Audio Format File header"},
{meta_PC_MXST, "Lego Island MxSt Header"}, {meta_PC_MXST, "Lego Island MxSt Header"},
{meta_SAB, "Team17 SAB header"}, {meta_SAB, "Sensaura SAB header"},
{meta_MAXIS_XA, "Maxis XAI/XAJ Header"}, {meta_MAXIS_XA, "Maxis XAI/XAJ Header"},
{meta_EXAKT_SC, "assumed Activision / EXAKT SC by extension"}, {meta_EXAKT_SC, "assumed Activision / EXAKT SC by extension"},
{meta_WII_BNS, "Nintendo BNS header"}, {meta_WII_BNS, "Nintendo BNS header"},
@ -1152,7 +1160,7 @@ static const meta_info meta_info_list[] = {
{meta_MCA, "Capcom MCA header"}, {meta_MCA, "Capcom MCA header"},
{meta_XB3D_ADX, "Xenoblade 3D ADX header"}, {meta_XB3D_ADX, "Xenoblade 3D ADX header"},
{meta_HCA, "CRI HCA header"}, {meta_HCA, "CRI HCA header"},
{meta_PS2_SVAG_SNK, "SNK SVAG header"}, {meta_SVAG_SNK, "SNK SVAG header"},
{meta_PS2_VDS_VDM, "Procyon Studio VDS/VDM header"}, {meta_PS2_VDS_VDM, "Procyon Studio VDS/VDM header"},
{meta_FFMPEG, "FFmpeg supported file format"}, {meta_FFMPEG, "FFmpeg supported file format"},
{meta_X360_CXS, "tri-Crescendo CXS header"}, {meta_X360_CXS, "tri-Crescendo CXS header"},
@ -1300,9 +1308,10 @@ static const meta_info meta_info_list[] = {
{meta_KTSR, "Koei Tecmo KTSR header"}, {meta_KTSR, "Koei Tecmo KTSR header"},
{meta_KAT, "Sega KAT header"}, {meta_KAT, "Sega KAT header"},
{meta_PCM_SUCCESS, "Success PCM header"}, {meta_PCM_SUCCESS, "Success PCM header"},
{meta_ADP_KONAMI, "Konami ADP 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) {
int i, list_length; int i, list_length;
const char *description; const char *description;
@ -1313,7 +1322,8 @@ void get_vgmstream_coding_description(VGMSTREAM *vgmstream, char *out, size_t ou
layered_layout_data* layout_data = vgmstream->layout_data; layered_layout_data* layout_data = vgmstream->layout_data;
get_vgmstream_coding_description(layout_data->layers[0], out, out_size); get_vgmstream_coding_description(layout_data->layers[0], out, out_size);
return; return;
} else if (vgmstream->layout_type == layout_segmented) { }
else if (vgmstream->layout_type == layout_segmented) {
segmented_layout_data* layout_data = vgmstream->layout_data; segmented_layout_data* layout_data = vgmstream->layout_data;
get_vgmstream_coding_description(layout_data->segments[0], out, out_size); get_vgmstream_coding_description(layout_data->segments[0], out, out_size);
return; return;
@ -1342,7 +1352,8 @@ void get_vgmstream_coding_description(VGMSTREAM *vgmstream, char *out, size_t ou
strncpy(out, description, out_size); strncpy(out, description, out_size);
} }
const char * get_vgmstream_layout_name(layout_t layout_type) {
static const char* get_layout_name(layout_t layout_type) {
int i, list_length; int i, list_length;
list_length = sizeof(layout_info_list) / sizeof(layout_info); list_length = sizeof(layout_info_list) / sizeof(layout_info);
@ -1353,40 +1364,103 @@ const char * get_vgmstream_layout_name(layout_t layout_type) {
return NULL; return NULL;
} }
void get_vgmstream_layout_description(VGMSTREAM *vgmstream, char *out, size_t out_size) {
char temp[256];
VGMSTREAM* vgmstreamsub = NULL;
const char* description;
description = get_vgmstream_layout_name(vgmstream->layout_type); static int has_sublayouts(VGMSTREAM** vgmstreams, int count) {
int i;
for (i = 0; i < count; i++) {
if (vgmstreams[i]->layout_type == layout_segmented || vgmstreams[i]->layout_type == layout_layered)
return 1;
}
return 0;
}
/* Makes a mixed description, considering a segments/layers can contain segments/layers infinitely, like:
*
* "(L3[S2L2]S3)" "(S3[L2[S2S2]])"
* L3 S3
* S2 L2
* file S2
* file file
* file file
* L2 file
* file file
* file file
*
* ("mixed" is added externally)
*/
static int get_layout_mixed_description(VGMSTREAM* vgmstream, char* dst, int dst_size) {
int i, count, done = 0;
VGMSTREAM** vgmstreams = NULL;
if (vgmstream->layout_type == layout_layered) {
layered_layout_data* data = vgmstream->layout_data;
vgmstreams = data->layers;
count = data->layer_count;
done = snprintf(dst, dst_size, "L%i", count);
}
else if (vgmstream->layout_type == layout_segmented) {
segmented_layout_data* data = vgmstream->layout_data;
vgmstreams = data->segments;
count = data->segment_count;
done = snprintf(dst, dst_size, "S%i", count);
}
if (!vgmstreams || done == 0 || done >= dst_size)
return 0;
if (!has_sublayouts(vgmstreams, count))
return done;
if (done + 1 < dst_size) {
dst[done++] = '[';
}
for (i = 0; i < count; i++) {
done += get_layout_mixed_description(vgmstreams[i], dst + done, dst_size - done);
}
if (done + 1 < dst_size) {
dst[done++] = ']';
}
return done;
}
void get_vgmstream_layout_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {
const char* description;
int mixed = 0;
description = get_layout_name(vgmstream->layout_type);
if (!description) description = "INCONCEIVABLE"; if (!description) description = "INCONCEIVABLE";
if (vgmstream->layout_type == layout_layered) { if (vgmstream->layout_type == layout_layered) {
vgmstreamsub = ((layered_layout_data*)vgmstream->layout_data)->layers[0]; layered_layout_data* data = vgmstream->layout_data;
snprintf(temp, sizeof(temp), "%s (%i layers)", description, ((layered_layout_data*)vgmstream->layout_data)->layer_count); mixed = has_sublayouts(data->layers, data->layer_count);
} else if (vgmstream->layout_type == layout_segmented) { if (!mixed)
snprintf(temp, sizeof(temp), "%s (%i segments)", description, ((segmented_layout_data*)vgmstream->layout_data)->segment_count); snprintf(out, out_size, "%s (%i layers)", description, data->layer_count);
vgmstreamsub = ((segmented_layout_data*)vgmstream->layout_data)->segments[0]; }
} else { else if (vgmstream->layout_type == layout_segmented) {
snprintf(temp, sizeof(temp), "%s", description); segmented_layout_data* data = vgmstream->layout_data;
mixed = has_sublayouts(data->segments, data->segment_count);
if (!mixed)
snprintf(out, out_size, "%s (%i segments)", description, data->segment_count);
}
else {
snprintf(out, out_size, "%s", description);
} }
strncpy(out, temp, out_size);
/* layouts can contain layouts infinitely let's leave it at one level deep (most common) */ if (mixed) {
/* TODO: improve this somehow */ char tmp[256] = {0};
if (vgmstreamsub && vgmstreamsub->layout_type == layout_layered) {
description = get_vgmstream_layout_name(vgmstreamsub->layout_type); get_layout_mixed_description(vgmstream, tmp, sizeof(tmp) - 1);
snprintf(temp, sizeof(temp), " + %s (%i layers)", description, ((layered_layout_data*)vgmstreamsub->layout_data)->layer_count); snprintf(out, out_size, "mixed (%s)", tmp);
concatn(out_size, out, temp); return;
} else if (vgmstreamsub && vgmstreamsub->layout_type == layout_segmented) {
description = get_vgmstream_layout_name(vgmstreamsub->layout_type);
snprintf(temp, sizeof(temp), " + %s (%i segments)", description, ((segmented_layout_data*)vgmstream->layout_data)->segment_count);
concatn(out_size, out, temp);
} }
} }
void get_vgmstream_meta_description(VGMSTREAM *vgmstream, char *out, size_t out_size) {
void get_vgmstream_meta_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {
int i, list_length; int i, list_length;
const char *description; const char* description;
description = "THEY SHOULD HAVE SENT A POET"; description = "THEY SHOULD HAVE SENT A POET";

View file

@ -1,11 +1,12 @@
#include "layout.h" #include "layout.h"
#include "../vgmstream.h" #include "../vgmstream.h"
#include "../decode.h"
/* Decodes samples for blocked streams. /* Decodes samples for blocked streams.
* Data is divided into headered blocks with a bunch of data. The layout calls external helper functions * Data is divided into headered blocks with a bunch of data. The layout calls external helper functions
* when a block is decoded, and those must parse the new block and move offsets accordingly. */ * when a block is decoded, and those must parse the new block and move offsets accordingly. */
void render_vgmstream_blocked(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { void render_vgmstream_blocked(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream) {
int samples_written = 0; int samples_written = 0;
int frame_size, samples_per_frame, samples_this_block; int frame_size, samples_per_frame, samples_this_block;
@ -52,7 +53,7 @@ void render_vgmstream_blocked(sample_t * buffer, int32_t sample_count, VGMSTREAM
break; break;
} }
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream); samples_to_do = get_vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
if (samples_to_do > sample_count - samples_written) if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written; samples_to_do = sample_count - samples_written;

View file

@ -6,9 +6,10 @@ void block_update_ast(off_t block_offset, VGMSTREAM * vgmstream) {
STREAMFILE* streamFile = vgmstream->ch[0].streamfile; STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
int i; int i;
size_t block_data, header_size; size_t block_data, header_size;
int32_t(*read_32bit)(off_t, STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE;
/* 0x00: "BLCK", rest: null */ /* 0x00: "BLCK", rest: null */
block_data = read_32bitBE(block_offset+0x04,streamFile); block_data = read_32bit(block_offset+0x04,streamFile);
header_size = 0x20; header_size = 0x20;
vgmstream->current_block_offset = block_offset; vgmstream->current_block_offset = block_offset;

View file

@ -1,10 +1,11 @@
#include "layout.h" #include "layout.h"
#include "../vgmstream.h" #include "../vgmstream.h"
#include "../decode.h"
/* Decodes samples for flat streams. /* Decodes samples for flat streams.
* Data forms a single stream, and the decoder may internally skip chunks and move offsets as needed. */ * Data forms a single stream, and the decoder may internally skip chunks and move offsets as needed. */
void render_vgmstream_flat(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { void render_vgmstream_flat(sample_t* outbuf, int32_t sample_count, VGMSTREAM* vgmstream) {
int samples_written = 0; int samples_written = 0;
int samples_per_frame, samples_this_block; int samples_per_frame, samples_this_block;
@ -20,21 +21,23 @@ void render_vgmstream_flat(sample_t * buffer, int32_t sample_count, VGMSTREAM *
continue; continue;
} }
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream); samples_to_do = get_vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
if (samples_to_do > sample_count - samples_written) if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written; samples_to_do = sample_count - samples_written;
if (samples_to_do == 0) { if (samples_to_do == 0) { /* when decoding more than num_samples */
VGM_LOG("layout_flat: wrong samples_to_do 0 found\n"); /* could happen when calling render at EOF? */ VGM_LOG("FLAT: samples_to_do 0\n");
//VGM_LOG("layout_flat: tb=%i sib=%i, spf=%i\n", samples_this_block, vgmstream->samples_into_block, samples_per_frame); goto decode_fail;
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t));
break;
} }
decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer); decode_vgmstream(vgmstream, samples_written, samples_to_do, outbuf);
samples_written += samples_to_do; samples_written += samples_to_do;
vgmstream->current_sample += samples_to_do; vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block += samples_to_do; vgmstream->samples_into_block += samples_to_do;
} }
return;
decode_fail:
memset(outbuf + samples_written * vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t));
} }

View file

@ -1,5 +1,6 @@
#include "layout.h" #include "layout.h"
#include "../vgmstream.h" #include "../vgmstream.h"
#include "../decode.h"
/* Decodes samples for interleaved streams. /* Decodes samples for interleaved streams.
@ -82,7 +83,7 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR
continue; continue;
} }
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream); samples_to_do = get_vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
if (samples_to_do > sample_count - samples_written) if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written; samples_to_do = sample_count - samples_written;

View file

@ -1,34 +1,49 @@
#include "layout.h" #include "layout.h"
#include "../vgmstream.h" #include "../vgmstream.h"
#include "../decode.h"
#include "../mixing.h" #include "../mixing.h"
#include "../plugins.h"
/* NOTE: if loop settings change the layered vgmstreams must be notified (preferably using vgmstream_force_loop) */
#define VGMSTREAM_MAX_LAYERS 255 #define VGMSTREAM_MAX_LAYERS 255
#define VGMSTREAM_LAYER_SAMPLE_BUFFER 8192 #define VGMSTREAM_LAYER_SAMPLE_BUFFER 8192
/* Decodes samples for layered streams. /* Decodes samples for layered streams.
* Similar to interleave layout, but decodec samples are mixed from complete vgmstreams, each * Similar to flat layout, but decoded vgmstream are mixed into a final buffer, each vgmstream
* with custom codecs and different number of channels, creating a single super-vgmstream. * may have different codecs and number of channels, creating a single super-vgmstream.
* Usually combined with custom streamfiles to handle data interleaved in weird ways. */ * Usually combined with custom streamfiles to handle data interleaved in weird ways. */
void render_vgmstream_layered(sample_t * outbuf, int32_t sample_count, VGMSTREAM * vgmstream) { void render_vgmstream_layered(sample_t* outbuf, int32_t sample_count, VGMSTREAM* vgmstream) {
int samples_written = 0; int samples_written = 0;
layered_layout_data *data = vgmstream->layout_data; layered_layout_data* data = vgmstream->layout_data;
int samples_per_frame, samples_this_block;
samples_per_frame = VGMSTREAM_LAYER_SAMPLE_BUFFER;
samples_this_block = vgmstream->num_samples; /* do all samples if possible */
while (samples_written < sample_count) { while (samples_written < sample_count) {
int samples_to_do = VGMSTREAM_LAYER_SAMPLE_BUFFER; int samples_to_do;
int layer, ch = 0; int layer, ch;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
/* handle looping (loop_layout has been called below) */
continue;
}
samples_to_do = get_vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
if (samples_to_do > sample_count - samples_written) if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written; samples_to_do = sample_count - samples_written;
if (samples_to_do <= 0) { /* when decoding more than num_samples */
VGM_LOG("LAYERED: samples_to_do 0\n");
goto decode_fail;
}
/* decode all layers */
ch = 0;
for (layer = 0; layer < data->layer_count; layer++) { for (layer = 0; layer < data->layer_count; layer++) {
int s, layer_ch, layer_channels; int s, layer_ch, layer_channels;
/* each layer will handle its own looping/mixing internally */
/* layers may have its own number of channels */ /* layers may have its own number of channels */
mixing_info(data->layers[layer], NULL, &layer_channels); mixing_info(data->layers[layer], NULL, &layer_channels);
@ -49,12 +64,48 @@ void render_vgmstream_layered(sample_t * outbuf, int32_t sample_count, VGMSTREAM
} }
} }
samples_written += samples_to_do; samples_written += samples_to_do;
/* needed for info (ex. for mixing) */ vgmstream->current_sample += samples_to_do;
vgmstream->current_sample = data->layers[0]->current_sample; vgmstream->samples_into_block += samples_to_do;
vgmstream->loop_count = data->layers[0]->loop_count;
//vgmstream->samples_into_block = 0; /* handled in each layer */
} }
return;
decode_fail:
memset(outbuf + samples_written * data->output_channels, 0, (sample_count - samples_written) * data->output_channels * sizeof(sample_t));
}
void loop_layout_layered(VGMSTREAM* vgmstream, int32_t loop_sample) {
int layer;
layered_layout_data* data = vgmstream->layout_data;
for (layer = 0; layer < data->layer_count; layer++) {
if (data->external_looping) {
/* looping is applied over resulting decode, as each layer is its own "solid" block with
* config and needs 'external' seeking */
seek_vgmstream(data->layers[layer], loop_sample);
}
else {
/* looping is aplied as internal loops. normally each layer does it automatically, but
* just calls do_loop manually to behave a bit more controlled, and so that manual
* calls to do_loop work (used in seek_vgmstream) */
if (data->layers[layer]->loop_flag) { /* mixing looping and non-looping layers is allowed */
data->layers[layer]->current_sample = data->layers[layer]->loop_end_sample; /* forces do loop */
vgmstream_do_loop(data->layers[layer]); /* guaranteed to work should loop_layout be called */
}
else {
/* needed when mixing non-looping layers and installing loop externally */
seek_vgmstream(data->layers[layer], loop_sample);
}
}
}
/* could always call seek_vgmstream, but it's not optimized to loop non-config vgmstreams ATM */
vgmstream->current_sample = loop_sample;
vgmstream->samples_into_block = loop_sample;
} }
@ -88,12 +139,12 @@ int setup_layout_layered(layered_layout_data* data) {
int layer_input_channels, layer_output_channels; int layer_input_channels, layer_output_channels;
if (data->layers[i] == NULL) { if (data->layers[i] == NULL) {
VGM_LOG("layered: no vgmstream in %i\n", i); VGM_LOG("LAYERED: no vgmstream in %i\n", i);
goto fail; goto fail;
} }
if (data->layers[i]->num_samples <= 0) { if (data->layers[i]->num_samples <= 0) {
VGM_LOG("layered: no samples in %i\n", i); VGM_LOG("LAYERED: no samples in %i\n", i);
goto fail; goto fail;
} }
@ -107,21 +158,25 @@ int setup_layout_layered(layered_layout_data* data) {
if (i > 0) { if (i > 0) {
/* a bit weird, but no matter */ /* a bit weird, but no matter */
if (data->layers[i]->sample_rate != data->layers[i-1]->sample_rate) { if (data->layers[i]->sample_rate != data->layers[i-1]->sample_rate) {
VGM_LOG("layered: layer %i has different sample rate\n", i); VGM_LOG("LAYERED: layer %i has different sample rate\n", i);
} }
/* also weird */ /* also weird */
if (data->layers[i]->coding_type != data->layers[i-1]->coding_type) { if (data->layers[i]->coding_type != data->layers[i-1]->coding_type) {
VGM_LOG("layered: layer %i has different coding type\n", i); VGM_LOG("LAYERED: layer %i has different coding type\n", i);
} }
} }
/* loops and other values could be mismatched but hopefully not */ /* loops and other values could be mismatched, but should be handled on allocate */
/* init mixing */
mixing_setup(data->layers[i], VGMSTREAM_LAYER_SAMPLE_BUFFER);
setup_vgmstream(data->layers[i]); /* final setup in case the VGMSTREAM was created manually */ /* allow config if set for fine-tuned parts (usually TXTP only) */
data->layers[i]->config_enabled = data->layers[i]->config.config_set;
mixing_setup(data->layers[i], VGMSTREAM_LAYER_SAMPLE_BUFFER); /* init mixing */ /* final setup in case the VGMSTREAM was created manually */
setup_vgmstream(data->layers[i]);
} }
if (max_output_channels > VGMSTREAM_MAX_CHANNELS || max_input_channels > VGMSTREAM_MAX_CHANNELS) if (max_output_channels > VGMSTREAM_MAX_CHANNELS || max_input_channels > VGMSTREAM_MAX_CHANNELS)
@ -168,29 +223,66 @@ void reset_layout_layered(layered_layout_data *data) {
} }
/* helper for easier creation of layers */ /* helper for easier creation of layers */
VGMSTREAM *allocate_layered_vgmstream(layered_layout_data* data) { VGMSTREAM* allocate_layered_vgmstream(layered_layout_data* data) {
VGMSTREAM *vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
int i, channels, loop_flag; int i, channels, loop_flag, sample_rate, external_looping;
int32_t num_samples, loop_start, loop_end;
int delta = 1024;
/* get data */ /* get data */
channels = data->output_channels; channels = data->output_channels;
num_samples = 0;
loop_flag = 1; loop_flag = 1;
loop_start = data->layers[0]->loop_start_sample;
loop_end = data->layers[0]->loop_end_sample;
external_looping = 0;
sample_rate = 0;
for (i = 0; i < data->layer_count; i++) { for (i = 0; i < data->layer_count; i++) {
if (loop_flag && !data->layers[i]->loop_flag) int32_t layer_samples = vgmstream_get_samples(data->layers[i]);
int layer_loop = data->layers[i]->loop_flag;
int32_t layer_loop_start = data->layers[i]->loop_start_sample;
int32_t layer_loop_end = data->layers[i]->loop_end_sample;
int layer_rate = data->layers[i]->sample_rate;
/* internal has own config (and maybe looping), looping now must be done on layout level
* (instead of on each layer, that is faster) */
if (data->layers[i]->config_enabled) {
loop_flag = 0; loop_flag = 0;
layer_loop = 0;
external_looping = 1;
} }
/* all layers should share loop pointsto consider looping enabled,
* but allow some leeway (ex. Dragalia Lost bgm+vocals ~12 samples) */
if (!layer_loop
|| !(loop_start >= layer_loop_start - delta && loop_start <= layer_loop_start + delta)
|| !(loop_end >= layer_loop_end - delta && loop_start <= layer_loop_end + delta)) {
loop_flag = 0;
loop_start = 0;
loop_end = 0;
}
if (num_samples < layer_samples) /* max */
num_samples = layer_samples;
if (sample_rate < layer_rate)
sample_rate = layer_rate;
}
data->external_looping = external_looping;
/* build the VGMSTREAM */ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag); vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->meta_type = data->layers[0]->meta_type; vgmstream->sample_rate = sample_rate;
vgmstream->sample_rate = data->layers[0]->sample_rate; vgmstream->num_samples = num_samples;
vgmstream->num_samples = data->layers[0]->num_samples; vgmstream->loop_start_sample = loop_start;
vgmstream->loop_start_sample = data->layers[0]->loop_start_sample; vgmstream->loop_end_sample = loop_end;
vgmstream->loop_end_sample = data->layers[0]->loop_end_sample; vgmstream->meta_type = data->layers[0]->meta_type; /* info */
vgmstream->coding_type = data->layers[0]->coding_type; vgmstream->coding_type = data->layers[0]->coding_type; /* info */
vgmstream->layout_type = layout_layered; vgmstream->layout_type = layout_layered;
vgmstream->layout_data = data; vgmstream->layout_data = data;

View file

@ -5,67 +5,69 @@
#include "../vgmstream.h" #include "../vgmstream.h"
/* blocked layouts */ /* blocked layouts */
void render_vgmstream_blocked(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream); void render_vgmstream_blocked(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
void block_update(off_t block_offset, VGMSTREAM * vgmstream); void block_update(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_ast(off_t block_ofset, VGMSTREAM * vgmstream); void block_update_ast(off_t block_ofset, VGMSTREAM* vgmstream);
void block_update_mxch(off_t block_ofset, VGMSTREAM * vgmstream); void block_update_mxch(off_t block_ofset, VGMSTREAM* vgmstream);
void block_update_halpst(off_t block_ofset, VGMSTREAM * vgmstream); void block_update_halpst(off_t block_ofset, VGMSTREAM* vgmstream);
void block_update_xa(off_t block_offset, VGMSTREAM * vgmstream); void block_update_xa(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream); void block_update_ea_schl(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_ea_1snh(off_t block_offset, VGMSTREAM * vgmstream); void block_update_ea_1snh(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_caf(off_t block_offset, VGMSTREAM * vgmstream); void block_update_caf(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_wsi(off_t block_offset, VGMSTREAM * vgmstream); void block_update_wsi(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_str_snds(off_t block_offset, VGMSTREAM * vgmstream); void block_update_str_snds(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_ws_aud(off_t block_offset, VGMSTREAM * vgmstream); void block_update_ws_aud(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_matx(off_t block_offset, VGMSTREAM * vgmstream); void block_update_matx(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_dec(off_t block_offset, VGMSTREAM * vgmstream); void block_update_dec(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_vs(off_t block_offset, VGMSTREAM * vgmstream); void block_update_vs(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_mul(off_t block_offset, VGMSTREAM * vgmstream); void block_update_mul(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_gsb(off_t block_offset, VGMSTREAM * vgmstream); void block_update_gsb(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_xvas(off_t block_offset, VGMSTREAM * vgmstream); void block_update_xvas(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_thp(off_t block_offset, VGMSTREAM * vgmstream); void block_update_thp(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_filp(off_t block_offset, VGMSTREAM * vgmstream); void block_update_filp(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_ivaud(off_t block_offset, VGMSTREAM * vgmstream); void block_update_ivaud(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_ea_swvr(off_t block_offset, VGMSTREAM * vgmstream); void block_update_ea_swvr(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_adm(off_t block_offset, VGMSTREAM * vgmstream); void block_update_adm(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_bdsp(off_t block_offset, VGMSTREAM * vgmstream); void block_update_bdsp(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_tra(off_t block_offset, VGMSTREAM * vgmstream); void block_update_tra(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_ps2_iab(off_t block_offset, VGMSTREAM * vgmstream); void block_update_ps2_iab(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_vs_str(off_t block_offset, VGMSTREAM * vgmstream); void block_update_vs_str(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_rws(off_t block_offset, VGMSTREAM * vgmstream); void block_update_rws(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_hwas(off_t block_offset, VGMSTREAM * vgmstream); void block_update_hwas(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream); void block_update_ea_sns(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream); void block_update_awc(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_vgs(off_t block_offset, VGMSTREAM * vgmstream); void block_update_vgs(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_vawx(off_t block_offset, VGMSTREAM * vgmstream); void block_update_vawx(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_xvag_subsong(off_t block_offset, VGMSTREAM * vgmstream); void block_update_xvag_subsong(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_ea_wve_au00(off_t block_offset, VGMSTREAM * vgmstream); void block_update_ea_wve_au00(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_ea_wve_ad10(off_t block_offset, VGMSTREAM * vgmstream); void block_update_ea_wve_ad10(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_sthd(off_t block_offset, VGMSTREAM * vgmstream); void block_update_sthd(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_h4m(off_t block_offset, VGMSTREAM * vgmstream); void block_update_h4m(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_xa_aiff(off_t block_offset, VGMSTREAM * vgmstream); void block_update_xa_aiff(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_vs_square(off_t block_offset, VGMSTREAM * vgmstream); void block_update_vs_square(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_vid1(off_t block_offset, VGMSTREAM* vgmstream); void block_update_vid1(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_ubi_sce(off_t block_offset, VGMSTREAM* vgmstream); void block_update_ubi_sce(off_t block_offset, VGMSTREAM* vgmstream);
/* other layouts */ /* other layouts */
void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream); void render_vgmstream_interleave(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
void render_vgmstream_flat(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream); void render_vgmstream_flat(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
void render_vgmstream_segmented(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream); void render_vgmstream_segmented(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
segmented_layout_data* init_layout_segmented(int segment_count); segmented_layout_data* init_layout_segmented(int segment_count);
int setup_layout_segmented(segmented_layout_data* data); int setup_layout_segmented(segmented_layout_data* data);
void free_layout_segmented(segmented_layout_data *data); void free_layout_segmented(segmented_layout_data* data);
void reset_layout_segmented(segmented_layout_data *data); void reset_layout_segmented(segmented_layout_data* data);
void loop_layout_segmented(VGMSTREAM* vgmstream, int32_t seek_sample);
VGMSTREAM *allocate_segmented_vgmstream(segmented_layout_data* data, int loop_flag, int loop_start_segment, int loop_end_segment); VGMSTREAM *allocate_segmented_vgmstream(segmented_layout_data* data, int loop_flag, int loop_start_segment, int loop_end_segment);
void render_vgmstream_layered(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream); void render_vgmstream_layered(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
layered_layout_data* init_layout_layered(int layer_count); layered_layout_data* init_layout_layered(int layer_count);
int setup_layout_layered(layered_layout_data* data); int setup_layout_layered(layered_layout_data* data);
void free_layout_layered(layered_layout_data *data); void free_layout_layered(layered_layout_data* data);
void reset_layout_layered(layered_layout_data *data); void reset_layout_layered(layered_layout_data* data);
void loop_layout_layered(VGMSTREAM* vgmstream, int32_t seek_sample);
VGMSTREAM *allocate_layered_vgmstream(layered_layout_data* data); VGMSTREAM *allocate_layered_vgmstream(layered_layout_data* data);
#endif #endif

View file

@ -1,6 +1,8 @@
#include "layout.h" #include "layout.h"
#include "../vgmstream.h" #include "../vgmstream.h"
#include "../decode.h"
#include "../mixing.h" #include "../mixing.h"
#include "../plugins.h"
#define VGMSTREAM_MAX_SEGMENTS 1024 #define VGMSTREAM_MAX_SEGMENTS 1024
#define VGMSTREAM_SEGMENT_SAMPLE_BUFFER 8192 #define VGMSTREAM_SEGMENT_SAMPLE_BUFFER 8192
@ -9,88 +11,67 @@
/* Decodes samples for segmented streams. /* Decodes samples for segmented streams.
* Chains together sequential vgmstreams, for data divided into separate sections or files * Chains together sequential vgmstreams, for data divided into separate sections or files
* (like one part for intro and other for loop segments, which may even use different codecs). */ * (like one part for intro and other for loop segments, which may even use different codecs). */
void render_vgmstream_segmented(sample_t * outbuf, int32_t sample_count, VGMSTREAM * vgmstream) { void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREAM* vgmstream) {
int samples_written = 0, loop_samples_skip = 0; int samples_written = 0, samples_this_block;
segmented_layout_data *data = vgmstream->layout_data; segmented_layout_data* data = vgmstream->layout_data;
int use_internal_buffer = 0; int use_internal_buffer = 0;
/* normally uses outbuf directly (faster?) but could need internal buffer if downmixing */
/* normally uses outbuf directly (faster) but could need internal buffer if downmixing */
if (vgmstream->channels != data->input_channels) { if (vgmstream->channels != data->input_channels) {
use_internal_buffer = 1; use_internal_buffer = 1;
} }
if (data->current_segment >= data->segment_count) {
VGM_LOG("SEGMENT: wrong current segment\n");
goto decode_fail;
}
samples_this_block = vgmstream_get_samples(data->segments[data->current_segment]);
while (samples_written < sample_count) { while (samples_written < sample_count) {
int samples_to_do; int samples_to_do;
int samples_this_segment = data->segments[data->current_segment]->num_samples;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
int segment, loop_segment, total_samples; /* handle looping (loop_layout has been called below, changes segments/state) */
samples_this_block = vgmstream_get_samples(data->segments[data->current_segment]);
/* handle looping by finding loop segment and loop_start inside that segment */ continue;
loop_segment = 0;
total_samples = 0;
while (total_samples < vgmstream->num_samples) {
int32_t segment_samples = data->segments[loop_segment]->num_samples;
if (vgmstream->loop_sample >= total_samples && vgmstream->loop_sample < total_samples + segment_samples) {
loop_samples_skip = vgmstream->loop_sample - total_samples;
break; /* loop_start falls within loop_segment's samples */
}
total_samples += segment_samples;
loop_segment++;
} }
if (loop_segment == data->segment_count) { /* detect segment change and restart (after loop, but before decode, to allow looping to kick in) */
VGM_LOG("segmented_layout: can't find loop segment\n"); if (vgmstream->samples_into_block >= samples_this_block) {
loop_segment = 0; data->current_segment++;
if (data->current_segment >= data->segment_count) { /* when decoding more than num_samples */
VGM_LOG("SEGMENTED: reached last segment\n");
goto decode_fail;
} }
data->current_segment = loop_segment; /* in case of looping spanning multiple segments */
reset_vgmstream(data->segments[data->current_segment]);
/* loops can span multiple segments */
for (segment = loop_segment; segment < data->segment_count; segment++) {
reset_vgmstream(data->segments[segment]);
}
samples_this_block = vgmstream_get_samples(data->segments[data->current_segment]);
vgmstream->samples_into_block = 0; vgmstream->samples_into_block = 0;
continue; continue;
} }
samples_to_do = vgmstream_samples_to_do(samples_this_segment, sample_count, vgmstream);
samples_to_do = get_vgmstream_samples_to_do(samples_this_block, sample_count, vgmstream);
if (samples_to_do > sample_count - samples_written) if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written; samples_to_do = sample_count - samples_written;
if (samples_to_do > VGMSTREAM_SEGMENT_SAMPLE_BUFFER /*&& use_internal_buffer*/) /* always for fade/etc mixes */ if (samples_to_do > VGMSTREAM_SEGMENT_SAMPLE_BUFFER /*&& use_internal_buffer*/) /* always for fade/etc mixes */
samples_to_do = VGMSTREAM_SEGMENT_SAMPLE_BUFFER; samples_to_do = VGMSTREAM_SEGMENT_SAMPLE_BUFFER;
/* segment looping: discard until actual start */ if (samples_to_do < 0) { /* 0 is ok? */
if (loop_samples_skip > 0) { VGM_LOG("SEGMENTED: wrong samples_to_do %i found\n", samples_to_do);
if (samples_to_do > loop_samples_skip) goto decode_fail;
samples_to_do = loop_samples_skip;
}
/* detect segment change and restart */
if (samples_to_do == 0) {
data->current_segment++;
reset_vgmstream(data->segments[data->current_segment]);
vgmstream->samples_into_block = 0;
continue;
} }
render_vgmstream( render_vgmstream(
use_internal_buffer ? use_internal_buffer ?
data->buffer : data->buffer : &outbuf[samples_written * data->output_channels],
&outbuf[samples_written * data->output_channels],
samples_to_do, samples_to_do,
data->segments[data->current_segment]); data->segments[data->current_segment]);
if (loop_samples_skip > 0) {
loop_samples_skip -= samples_to_do;
vgmstream->samples_into_block += samples_to_do;
continue;
}
if (use_internal_buffer) { if (use_internal_buffer) {
int s; int s;
for (s = 0; s < samples_to_do * data->output_channels; s++) { for (s = 0; s < samples_to_do * data->output_channels; s++) {
@ -102,11 +83,42 @@ void render_vgmstream_segmented(sample_t * outbuf, int32_t sample_count, VGMSTRE
vgmstream->current_sample += samples_to_do; vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block += samples_to_do; vgmstream->samples_into_block += samples_to_do;
} }
return;
decode_fail:
memset(outbuf + samples_written * data->output_channels, 0, (sample_count - samples_written) * data->output_channels * sizeof(sample_t));
}
void loop_layout_segmented(VGMSTREAM* vgmstream, int32_t loop_sample) {
int segment, total_samples;
segmented_layout_data* data = vgmstream->layout_data;
segment = 0;
total_samples = 0;
while (total_samples < vgmstream->num_samples) {
int32_t segment_samples = vgmstream_get_samples(data->segments[segment]);
/* find if loop falls within segment's samples */
if (loop_sample >= total_samples && loop_sample < total_samples + segment_samples) {
int32_t loop_relative = loop_sample - total_samples;
seek_vgmstream(data->segments[segment], loop_relative);
data->current_segment = segment;
vgmstream->samples_into_block = loop_relative;
break;
}
total_samples += segment_samples;
segment++;
}
if (segment == data->segment_count) {
VGM_LOG("SEGMENTED: can't find loop segment\n");
}
} }
segmented_layout_data* init_layout_segmented(int segment_count) { segmented_layout_data* init_layout_segmented(int segment_count) {
segmented_layout_data *data = NULL; segmented_layout_data* data = NULL;
if (segment_count <= 0 || segment_count > VGMSTREAM_MAX_SEGMENTS) if (segment_count <= 0 || segment_count > VGMSTREAM_MAX_SEGMENTS)
goto fail; goto fail;
@ -135,23 +147,28 @@ int setup_layout_segmented(segmented_layout_data* data) {
for (i = 0; i < data->segment_count; i++) { for (i = 0; i < data->segment_count; i++) {
int segment_input_channels, segment_output_channels; int segment_input_channels, segment_output_channels;
/* allow config if set for fine-tuned parts (usually TXTP only) */
data->segments[i]->config_enabled = data->segments[i]->config.config_set;
if (data->segments[i] == NULL) { if (data->segments[i] == NULL) {
VGM_LOG("segmented: no vgmstream in segment %i\n", i); VGM_LOG("SEGMENTED: no vgmstream in segment %i\n", i);
goto fail; goto fail;
} }
if (data->segments[i]->num_samples <= 0) { if (data->segments[i]->num_samples <= 0) {
VGM_LOG("segmented: no samples in segment %i\n", i); VGM_LOG("SEGMENTED: no samples in segment %i\n", i);
goto fail; goto fail;
} }
/* disable so that looping is controlled by render_vgmstream_segmented */ /* disable so that looping is controlled by render_vgmstream_segmented */
if (data->segments[i]->loop_flag != 0) { if (data->segments[i]->loop_flag != 0) {
VGM_LOG("segmented: segment %i is looped\n", i); VGM_LOG("SEGMENTED: segment %i is looped\n", i);
/* config allows internal loops */
if (!data->segments[i]->config_enabled) {
data->segments[i]->loop_flag = 0; data->segments[i]->loop_flag = 0;
} }
}
/* different segments may have different input channels, though output should be /* different segments may have different input channels, though output should be
* the same for all (ex. 2ch + 1ch segments, but 2ch segment is downmixed to 1ch) */ * the same for all (ex. 2ch + 1ch segments, but 2ch segment is downmixed to 1ch) */
@ -166,13 +183,13 @@ int setup_layout_segmented(segmented_layout_data* data) {
mixing_info(data->segments[i-1], NULL, &prev_output_channels); mixing_info(data->segments[i-1], NULL, &prev_output_channels);
if (segment_output_channels != prev_output_channels) { if (segment_output_channels != prev_output_channels) {
VGM_LOG("segmented: segment %i has wrong channels %i vs prev channels %i\n", i, segment_output_channels, prev_output_channels); VGM_LOG("SEGMENTED: segment %i has wrong channels %i vs prev channels %i\n", i, segment_output_channels, prev_output_channels);
goto fail; goto fail;
} }
/* a bit weird, but no matter */ /* a bit weird, but no matter */
if (data->segments[i]->sample_rate != data->segments[i-1]->sample_rate) { if (data->segments[i]->sample_rate != data->segments[i-1]->sample_rate) {
VGM_LOG("segmented: segment %i has different sample rate\n", i); VGM_LOG("SEGMENTED: segment %i has different sample rate\n", i);
} }
/* perfectly acceptable */ /* perfectly acceptable */
@ -180,10 +197,11 @@ int setup_layout_segmented(segmented_layout_data* data) {
// goto fail; // goto fail;
} }
/* init mixing */
mixing_setup(data->segments[i], VGMSTREAM_SEGMENT_SAMPLE_BUFFER);
setup_vgmstream(data->segments[i]); /* final setup in case the VGMSTREAM was created manually */ /* final setup in case the VGMSTREAM was created manually */
setup_vgmstream(data->segments[i]);
mixing_setup(data->segments[i], VGMSTREAM_SEGMENT_SAMPLE_BUFFER); /* init mixing */
} }
if (max_output_channels > VGMSTREAM_MAX_CHANNELS || max_input_channels > VGMSTREAM_MAX_CHANNELS) if (max_output_channels > VGMSTREAM_MAX_CHANNELS || max_input_channels > VGMSTREAM_MAX_CHANNELS)
@ -202,7 +220,7 @@ fail:
return 0; /* caller is expected to free */ return 0; /* caller is expected to free */
} }
void free_layout_segmented(segmented_layout_data *data) { void free_layout_segmented(segmented_layout_data* data) {
int i, j; int i, j;
if (!data) if (!data)
@ -228,7 +246,7 @@ void free_layout_segmented(segmented_layout_data *data) {
free(data); free(data);
} }
void reset_layout_segmented(segmented_layout_data *data) { void reset_layout_segmented(segmented_layout_data* data) {
int i; int i;
if (!data) if (!data)
@ -241,21 +259,27 @@ void reset_layout_segmented(segmented_layout_data *data) {
} }
/* helper for easier creation of segments */ /* helper for easier creation of segments */
VGMSTREAM *allocate_segmented_vgmstream(segmented_layout_data* data, int loop_flag, int loop_start_segment, int loop_end_segment) { VGMSTREAM* allocate_segmented_vgmstream(segmented_layout_data* data, int loop_flag, int loop_start_segment, int loop_end_segment) {
VGMSTREAM *vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
int channel_layout; int channel_layout;
int i, num_samples, loop_start, loop_end; int i, sample_rate;
int32_t num_samples, loop_start, loop_end;
/* save data */ /* save data */
channel_layout = data->segments[0]->channel_layout; channel_layout = data->segments[0]->channel_layout;
num_samples = 0; num_samples = 0;
loop_start = 0; loop_start = 0;
loop_end = 0; loop_end = 0;
sample_rate = 0;
for (i = 0; i < data->segment_count; i++) { for (i = 0; i < data->segment_count; i++) {
/* needs get_samples since element may use play settings */
int32_t segment_samples = vgmstream_get_samples(data->segments[i]);
int segment_rate = data->segments[i]->sample_rate;
if (loop_flag && i == loop_start_segment) if (loop_flag && i == loop_start_segment)
loop_start = num_samples; loop_start = num_samples;
num_samples += data->segments[i]->num_samples; num_samples += segment_samples;
if (loop_flag && i == loop_end_segment) if (loop_flag && i == loop_end_segment)
loop_end = num_samples; loop_end = num_samples;
@ -263,6 +287,9 @@ VGMSTREAM *allocate_segmented_vgmstream(segmented_layout_data* data, int loop_fl
/* inherit first segment's layout but only if all segments' layout match */ /* inherit first segment's layout but only if all segments' layout match */
if (channel_layout != 0 && channel_layout != data->segments[i]->channel_layout) if (channel_layout != 0 && channel_layout != data->segments[i]->channel_layout)
channel_layout = 0; channel_layout = 0;
if (sample_rate < segment_rate)
sample_rate = segment_rate;
} }
/* respect loop_flag even when no loop_end found as it's possible file loops are set outside */ /* respect loop_flag even when no loop_end found as it's possible file loops are set outside */

View file

@ -75,6 +75,7 @@ fail:
//TODO: could pre-load all sections first, but needs cache for multiple subsongs (+semaphs, if multiple read the same thing) //TODO: could pre-load all sections first, but needs cache for multiple subsongs (+semaphs, if multiple read the same thing)
#define ACB_TABLE_BUFFER_CUENAME 0x8000 #define ACB_TABLE_BUFFER_CUENAME 0x8000
#define ACB_TABLE_BUFFER_CUE 0x40000 #define ACB_TABLE_BUFFER_CUE 0x40000
#define ACB_TABLE_BUFFER_BLOCKSEQUENCE 0x8000
#define ACB_TABLE_BUFFER_BLOCK 0x8000 #define ACB_TABLE_BUFFER_BLOCK 0x8000
#define ACB_TABLE_BUFFER_SEQUENCE 0x40000 #define ACB_TABLE_BUFFER_SEQUENCE 0x40000
#define ACB_TABLE_BUFFER_TRACK 0x10000 #define ACB_TABLE_BUFFER_TRACK 0x10000
@ -106,6 +107,7 @@ typedef struct {
utf_context *CueNameTable; utf_context *CueNameTable;
utf_context *CueTable; utf_context *CueTable;
utf_context *BlockSequenceTable;
utf_context *BlockTable; utf_context *BlockTable;
utf_context *SequenceTable; utf_context *SequenceTable;
utf_context *TrackTable; utf_context *TrackTable;
@ -115,6 +117,7 @@ typedef struct {
STREAMFILE* CueNameSf; STREAMFILE* CueNameSf;
STREAMFILE* CueSf; STREAMFILE* CueSf;
STREAMFILE* BlockSequenceSf;
STREAMFILE* BlockSf; STREAMFILE* BlockSf;
STREAMFILE* SequenceSf; STREAMFILE* SequenceSf;
STREAMFILE* TrackSf; STREAMFILE* TrackSf;
@ -158,7 +161,6 @@ static int open_utf_subtable(acb_header* acb, STREAMFILE* *TableSf, utf_context*
if (!*Table) goto fail; if (!*Table) goto fail;
//;VGM_LOG("ACB: loaded table %s\n", TableName); //;VGM_LOG("ACB: loaded table %s\n", TableName);
//;VGM_LOG("ACB: sf=%x\n", (uint32_t)*TableSf);
return 1; return 1;
fail: fail:
return 0; return 0;
@ -179,7 +181,7 @@ static void acb_cpy(char* dst, int dst_max, const char* src) {
strcpy(dst, src); strcpy(dst, src);
} }
static void add_acb_name(acb_header* acb, int8_t Waveform_Streaming) { static void add_acb_name(acb_header* acb, int8_t Streaming) {
/* ignore name repeats */ /* ignore name repeats */
if (acb->awbname_count) { if (acb->awbname_count) {
@ -198,7 +200,7 @@ static void add_acb_name(acb_header* acb, int8_t Waveform_Streaming) {
else { else {
acb_cpy(acb->name, sizeof(acb->name), acb->cuename_name); acb_cpy(acb->name, sizeof(acb->name), acb->cuename_name);
} }
if (Waveform_Streaming == 2 && acb->is_memory) { if (Streaming == 2 && acb->is_memory) {
acb_cat(acb->name, sizeof(acb->name), " [pre]"); acb_cat(acb->name, sizeof(acb->name), " [pre]");
} }
@ -211,35 +213,38 @@ static void add_acb_name(acb_header* acb, int8_t Waveform_Streaming) {
} }
/*******************************************************************************/
/* OBJECT HANDLERS */
static int load_acb_waveform(acb_header* acb, int16_t Index) { static int load_acb_waveform(acb_header* acb, int16_t Index) {
uint16_t Waveform_Id; uint16_t Id;
uint8_t Waveform_Streaming; uint8_t Streaming;
/* read Waveform[Index] */ /* read Waveform[Index] */
if (!open_utf_subtable(acb, &acb->WaveformSf, &acb->WaveformTable, "WaveformTable", NULL, ACB_TABLE_BUFFER_WAVEFORM)) if (!open_utf_subtable(acb, &acb->WaveformSf, &acb->WaveformTable, "WaveformTable", NULL, ACB_TABLE_BUFFER_WAVEFORM))
goto fail; goto fail;
if (!utf_query_u16(acb->WaveformTable, Index, "Id", &Waveform_Id)) { /* older versions use Id */ if (!utf_query_u16(acb->WaveformTable, Index, "Id", &Id)) { /* older versions use Id */
if (acb->is_memory) { if (acb->is_memory) {
if (!utf_query_u16(acb->WaveformTable, Index, "MemoryAwbId", &Waveform_Id)) if (!utf_query_u16(acb->WaveformTable, Index, "MemoryAwbId", &Id))
goto fail; goto fail;
} else { } else {
if (!utf_query_u16(acb->WaveformTable, Index, "StreamAwbId", &Waveform_Id)) if (!utf_query_u16(acb->WaveformTable, Index, "StreamAwbId", &Id))
goto fail; goto fail;
} }
} }
if (!utf_query_u8(acb->WaveformTable, Index, "Streaming", &Waveform_Streaming)) if (!utf_query_u8(acb->WaveformTable, Index, "Streaming", &Streaming))
goto fail; goto fail;
//;VGM_LOG("ACB: Waveform[%i]: Id=%i, Streaming=%i\n", Index, Waveform_Id, Waveform_Streaming); //;VGM_LOG("ACB: Waveform[%i]: Id=%i, Streaming=%i\n", Index, Id, Streaming);
/* not found but valid */ /* not found but valid */
if (Waveform_Id != acb->target_waveid) if (Id != acb->target_waveid)
return 1; return 1;
/* must match our target's (0=memory, 1=streaming, 2=memory (prefetch)+stream) */ /* must match our target's (0=memory, 1=streaming, 2=memory (prefetch)+stream) */
if ((acb->is_memory && Waveform_Streaming == 1) || (!acb->is_memory && Waveform_Streaming == 0)) if ((acb->is_memory && Streaming == 1) || (!acb->is_memory && Streaming == 0))
return 1; return 1;
/* aaand finally get name (phew) */ /* aaand finally get name (phew) */
add_acb_name(acb, Waveform_Streaming); add_acb_name(acb, Streaming);
return 1; return 1;
fail: fail:
@ -251,19 +256,18 @@ static int load_acb_sequence(acb_header* acb, int16_t Index);
static int load_acb_synth(acb_header* acb, int16_t Index) { static int load_acb_synth(acb_header* acb, int16_t Index) {
int i, count; int i, count;
uint8_t Synth_Type; uint8_t Type;
uint32_t Synth_ReferenceItems_offset; uint32_t ReferenceItems_offset, ReferenceItems_size;
uint32_t Synth_ReferenceItems_size;
/* read Synth[Index] */ /* read Synth[Index] */
if (!open_utf_subtable(acb, &acb->SynthSf, &acb->SynthTable, "SynthTable", NULL, ACB_TABLE_BUFFER_SYNTH)) if (!open_utf_subtable(acb, &acb->SynthSf, &acb->SynthTable, "SynthTable", NULL, ACB_TABLE_BUFFER_SYNTH))
goto fail; goto fail;
if (!utf_query_u8(acb->SynthTable, Index, "Type", &Synth_Type)) if (!utf_query_u8(acb->SynthTable, Index, "Type", &Type))
goto fail; goto fail;
if (!utf_query_data(acb->SynthTable, Index, "ReferenceItems", &Synth_ReferenceItems_offset, &Synth_ReferenceItems_size)) if (!utf_query_data(acb->SynthTable, Index, "ReferenceItems", &ReferenceItems_offset, &ReferenceItems_size))
goto fail; goto fail;
//;VGM_LOG("ACB: Synth[%i]: Type=%x, ReferenceItems={%x,%x}\n", Index, Synth_Type, Synth_ReferenceItems_offset, Synth_ReferenceItems_size); //;VGM_LOG("ACB: Synth[%i]: Type=%x, ReferenceItems={%x,%x}\n", Index, Type, ReferenceItems_offset, ReferenceItems_size);
acb->synth_depth++; acb->synth_depth++;
@ -272,6 +276,9 @@ static int load_acb_synth(acb_header* acb, int16_t Index) {
goto fail; /* max Synth > Synth > Waveform (ex. Yakuza 6) */ goto fail; /* max Synth > Synth > Waveform (ex. Yakuza 6) */
} }
//todo .CommandIndex > CommandTable
//todo .TrackValues > TrackTable?
/* Cue.ReferenceType 2 uses Synth.Type, while 3 always sets it to 0 and uses Sequence.Type instead /* Cue.ReferenceType 2 uses Synth.Type, while 3 always sets it to 0 and uses Sequence.Type instead
* Both look the same and probably affect which item in the ReferenceItems list is picked: * Both look the same and probably affect which item in the ReferenceItems list is picked:
* - 0: polyphonic (1 item) * - 0: polyphonic (1 item)
@ -287,35 +294,37 @@ static int load_acb_synth(acb_header* acb, int16_t Index) {
* Since we want to find all possible Waveforms that could match our id, we ignore Type and just parse all ReferenceItems. * Since we want to find all possible Waveforms that could match our id, we ignore Type and just parse all ReferenceItems.
*/ */
count = Synth_ReferenceItems_size / 0x04; count = ReferenceItems_size / 0x04;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
uint16_t Synth_ReferenceItem_type = read_u16be(Synth_ReferenceItems_offset + i*0x04 + 0x00, acb->SynthSf); uint16_t item_type = read_u16be(ReferenceItems_offset + i*0x04 + 0x00, acb->SynthSf);
uint16_t Synth_ReferenceItem_index = read_u16be(Synth_ReferenceItems_offset + i*0x04 + 0x02, acb->SynthSf); uint16_t item_index = read_u16be(ReferenceItems_offset + i*0x04 + 0x02, acb->SynthSf);
//;VGM_LOG("ACB: Synth.ReferenceItem: type=%x, index=%x\n", Synth_ReferenceItem_type, Synth_ReferenceItem_index); //;VGM_LOG("ACB: Synth.ReferenceItem: type=%x, index=%x\n", item_type, item_index);
switch(Synth_ReferenceItem_type) { switch(item_type) {
case 0x00: /* no reference */ case 0x00: /* no reference */
count = 0; count = 0;
break; break;
case 0x01: /* Waveform (most common) */ case 0x01: /* Waveform (most common) */
if (!load_acb_waveform(acb, Synth_ReferenceItem_index)) if (!load_acb_waveform(acb, item_index))
goto fail; goto fail;
break; break;
case 0x02: /* Synth, possibly random (rare, found in Sonic Lost World with ReferenceType 2) */ case 0x02: /* Synth, possibly random (rare, found in Sonic Lost World with ReferenceType 2) */
if (!load_acb_synth(acb, Synth_ReferenceItem_index)) if (!load_acb_synth(acb, item_index))
goto fail; goto fail;
break; break;
case 0x03: /* Sequence of Synths w/ % in Synth.TrackValues (rare, found in Sonic Lost World with ReferenceType 2) */ case 0x03: /* Sequence of Synths w/ % in Synth.TrackValues (rare, found in Sonic Lost World with ReferenceType 2) */
if (!load_acb_sequence(acb, Synth_ReferenceItem_index)) if (!load_acb_sequence(acb, item_index))
goto fail; goto fail;
break; break;
/* others: same as cue's ReferenceType? */
case 0x06: /* this seems to point to Synth but results don't make sense (rare, from Sonic Lost World) */ case 0x06: /* this seems to point to Synth but results don't make sense (rare, from Sonic Lost World) */
default: /* undefined/crashes AtomViewer */ default: /* undefined/crashes AtomViewer */
VGM_LOG("ACB: unknown Synth.ReferenceItem type %x at %x + %x\n", Synth_ReferenceItem_type, Synth_ReferenceItems_offset, Synth_ReferenceItems_size); VGM_LOG("ACB: unknown Synth.ReferenceItem type %x at %x + %x\n", item_type, ReferenceItems_offset, ReferenceItems_size);
count = 0; /* force end without failing */ count = 0; /* force end without failing */
break; break;
} }
@ -328,98 +337,133 @@ fail:
return 0; return 0;
} }
static int load_acb_command_tlvs(acb_header* acb, STREAMFILE* sf, uint32_t Command_offset, uint32_t Command_size) {
uint32_t offset = Command_offset;
uint32_t max_offset = Command_offset + Command_size;
uint16_t tlv_code, tlv_type, tlv_index;
uint8_t tlv_size;
//todo read full offsets
/* read a (name)Command multiple TLV data */
while (offset < max_offset) {
tlv_code = read_u16be(offset + 0x00, sf);
tlv_size = read_u8 (offset + 0x02, sf);
offset += 0x03;
/* There are around 160 codes (some unused), with things like set volume, pan, stop, mute, and so on.
* Multiple commands are linked and only "note on" seems to point so other objects, so maybe others
* apply to current object (since there is "note off" without reference. */
switch(tlv_code) {
case 2000: /* noteOn */
case 2003: /* noteOnWithNo plus 16b (null?) [rare, ex. PES 2014] */
if (tlv_size < 0x04) {
VGM_LOG("ACB: TLV with unknown size\n");
break;
}
tlv_type = read_u16be(offset + 0x00, sf); /* ReferenceItem */
tlv_index = read_u16be(offset + 0x02, sf);
//;VGM_LOG("ACB: TLV at %x: type %x, index=%x\n", offset, tlv_type, tlv_index);
/* same as Synth's ReferenceItem type? */
switch(tlv_type) {
case 0x02: /* Synth (common) */
if (!load_acb_synth(acb, tlv_index))
goto fail;
break;
case 0x03: /* Sequence (common, ex. Yakuza 6, Yakuza Kiwami 2) */
if (!load_acb_sequence(acb, tlv_index))
goto fail;
break;
default:
VGM_LOG("ACB: unknown TLV type %x at %x + %x\n", tlv_type, offset, tlv_size);
max_offset = 0; /* force end without failing */
break;
}
break;
case 2004: /* noteOnWithDuration */
/* same as the above plus extra field */
//;VGM_LOG("ACB: TLV at %x: usable code %i?\n", offset-0x03, tlv_code);
break;
case 33: /* mute */
case 124: /* stopAtLoopEnd */
case 1000: /* noteOff */
case 1251: /* sequenceCallbackWithId */
case 1252: /* sequenceCallbackWithString */
case 1253: /* sequenceCallbackWithIdAndString */
case 2002: /* setSynthOrWaveform */
case 4051: /* transitionTrack */
case 7102: /* muteTrackAction */
case 7100: /* startAction */
case 7101: /* stopAction */
/* may be needed? */
//;VGM_LOG("ACB: TLV at %x: check code %i?\n", offset-0x03, tlv_code);
break;
case 0: /* no-op */
case 998: /* sequenceStartRandom (plays following note ons in random?)*/
case 999: /* sequenceStart (plays following note ons in sequence?) */
default: /* ignore others */
break;
}
offset += tlv_size;
}
return 1;
fail:
return 0;
}
static int load_acb_track_event_command(acb_header* acb, int16_t Index) { static int load_acb_track_event_command(acb_header* acb, int16_t Index) {
uint16_t Track_EventIndex; uint16_t EventIndex;
uint32_t Track_Command_offset; uint32_t Command_offset, Command_size;
uint32_t Track_Command_size;
/* read Track[Index] */ /* read Track[Index] */
if (!open_utf_subtable(acb, &acb->TrackSf, &acb->TrackTable, "TrackTable", NULL, ACB_TABLE_BUFFER_TRACK )) if (!open_utf_subtable(acb, &acb->TrackSf, &acb->TrackTable, "TrackTable", NULL, ACB_TABLE_BUFFER_TRACK ))
goto fail; goto fail;
if (!utf_query_u16(acb->TrackTable, Index, "EventIndex", &Track_EventIndex)) if (!utf_query_u16(acb->TrackTable, Index, "EventIndex", &EventIndex))
goto fail; goto fail;
//;VGM_LOG("ACB: Track[%i]: EventIndex=%i\n", Index, Track_EventIndex); //;VGM_LOG("ACB: Track[%i]: EventIndex=%i\n", Index, EventIndex);
//todo CommandIndex?
/* happens with some odd track without anything useful */
if (EventIndex == 65535)
return 1;
/* next link varies with version, check by table existence */ /* next link varies with version, check by table existence */
if (acb->has_CommandTable) { /* <=v1.27 */ if (acb->has_CommandTable) { /* <=v1.27 */
/* read Command[EventIndex] */ /* read Command[EventIndex] */
if (!open_utf_subtable(acb, &acb->TrackCommandSf, &acb->TrackCommandTable, "CommandTable", NULL, ACB_TABLE_BUFFER_TRACKCOMMAND)) if (!open_utf_subtable(acb, &acb->TrackCommandSf, &acb->TrackCommandTable, "CommandTable", NULL, ACB_TABLE_BUFFER_TRACKCOMMAND))
goto fail; goto fail;
if (!utf_query_data(acb->TrackCommandTable, Track_EventIndex, "Command", &Track_Command_offset, &Track_Command_size)) if (!utf_query_data(acb->TrackCommandTable, EventIndex, "Command", &Command_offset, &Command_size))
goto fail; goto fail;
//;VGM_LOG("ACB: Command[%i]: Command={%x,%x}\n", Track_EventIndex, Track_Command_offset,Track_Command_size); //;VGM_LOG("ACB: Command[%i]: Command={%x,%x}\n", EventIndex, Command_offset,Command_size);
} }
else if (acb->has_TrackEventTable) { /* >=v1.28 */ else if (acb->has_TrackEventTable) { /* >=v1.28 */
/* read TrackEvent[EventIndex] */ /* read TrackEvent[EventIndex] */
if (!open_utf_subtable(acb, &acb->TrackCommandSf, &acb->TrackCommandTable, "TrackEventTable", NULL, ACB_TABLE_BUFFER_TRACKCOMMAND)) if (!open_utf_subtable(acb, &acb->TrackCommandSf, &acb->TrackCommandTable, "TrackEventTable", NULL, ACB_TABLE_BUFFER_TRACKCOMMAND))
goto fail; goto fail;
if (!utf_query_data(acb->TrackCommandTable, Track_EventIndex, "Command", &Track_Command_offset, &Track_Command_size)) if (!utf_query_data(acb->TrackCommandTable, EventIndex, "Command", &Command_offset, &Command_size))
goto fail; goto fail;
//;VGM_LOG("ACB: TrackEvent[%i]: Command={%x,%x}\n", Track_EventIndex, Track_Command_offset,Track_Command_size); //;VGM_LOG("ACB: TrackEvent[%i]: Command={%x,%x}\n", EventIndex, Command_offset,Command_size);
} }
else { else {
VGM_LOG("ACB: unknown command table\n"); VGM_LOG("ACB: unknown command table\n");
goto fail; goto fail;
} }
/* read Command (some kind of multiple TLVs, this seems ok) */ /* read Command's TLVs */
{ if (!load_acb_command_tlvs(acb, acb->TrackCommandSf, Command_offset, Command_size))
uint32_t offset = Track_Command_offset;
uint32_t max_offset = Track_Command_offset + Track_Command_size;
uint16_t tlv_code, tlv_type, tlv_index;
uint8_t tlv_size;
while (offset < max_offset) {
tlv_code = read_u16be(offset + 0x00, acb->TrackCommandSf);
tlv_size = read_u8 (offset + 0x02, acb->TrackCommandSf);
offset += 0x03;
if (tlv_code == 0x07D0) {
if (tlv_size < 0x04) {
VGM_LOG("ACB: TLV with unknown size\n");
break;
}
tlv_type = read_u16be(offset + 0x00, acb->TrackCommandSf);
tlv_index = read_u16be(offset + 0x02, acb->TrackCommandSf);
//;VGM_LOG("ACB: TLV at %x: type %x, index=%x\n", offset, tlv_type, tlv_index);
/* probably same as Synth_ReferenceItem_type */
switch(tlv_type) {
case 0x02: /* Synth (common) */
if (!load_acb_synth(acb, tlv_index))
goto fail; goto fail;
break;
case 0x03: /* Sequence of Synths (common, ex. Yakuza 6, Yakuza Kiwami 2) */
if (!load_acb_sequence(acb, tlv_index))
goto fail;
break;
/* possible values? (from debug):
* - sequence
* - track
* - synth
* - trackEvent
* - seqParameterPallet,
* - trackParameterPallet,
* - synthParameterPallet,
*/
default:
VGM_LOG("ACB: unknown TLV type %x at %x + %x\n", tlv_type, offset, tlv_size);
max_offset = 0; /* force end without failing */
break;
}
}
/* 0x07D1 comes suspiciously often paired with 0x07D0 too */
offset += tlv_size;
}
}
return 1; return 1;
fail: fail:
@ -428,19 +472,20 @@ fail:
static int load_acb_sequence(acb_header* acb, int16_t Index) { static int load_acb_sequence(acb_header* acb, int16_t Index) {
int i; int i;
uint16_t Sequence_NumTracks; uint16_t NumTracks;
uint32_t Sequence_TrackIndex_offset; uint32_t TrackIndex_offset, TrackIndex_size;
uint32_t Sequence_TrackIndex_size;
/* read Sequence[Index] */ /* read Sequence[Index] */
if (!open_utf_subtable(acb, &acb->SequenceSf, &acb->SequenceTable, "SequenceTable", NULL, ACB_TABLE_BUFFER_SEQUENCE)) if (!open_utf_subtable(acb, &acb->SequenceSf, &acb->SequenceTable, "SequenceTable", NULL, ACB_TABLE_BUFFER_SEQUENCE))
goto fail; goto fail;
if (!utf_query_u16(acb->SequenceTable, Index, "NumTracks", &Sequence_NumTracks)) if (!utf_query_u16(acb->SequenceTable, Index, "NumTracks", &NumTracks))
goto fail; goto fail;
if (!utf_query_data(acb->SequenceTable, Index, "TrackIndex", &Sequence_TrackIndex_offset, &Sequence_TrackIndex_size)) if (!utf_query_data(acb->SequenceTable, Index, "TrackIndex", &TrackIndex_offset, &TrackIndex_size))
goto fail; goto fail;
//;VGM_LOG("ACB: Sequence[%i]: NumTracks=%i, TrackIndex={%x, %x}\n", Index, Sequence_NumTracks, Sequence_TrackIndex_offset,Sequence_TrackIndex_size); //;VGM_LOG("ACB: Sequence[%i]: NumTracks=%i, TrackIndex={%x, %x}\n", Index, NumTracks, TrackIndex_offset,TrackIndex_size);
//todo .CommandIndex > SequenceCommand?
acb->sequence_depth++; acb->sequence_depth++;
@ -449,16 +494,16 @@ static int load_acb_sequence(acb_header* acb, int16_t Index) {
goto fail; /* max Sequence > Sequence > Sequence > Synth > Waveform (ex. Yakuza 6) */ goto fail; /* max Sequence > Sequence > Sequence > Synth > Waveform (ex. Yakuza 6) */
} }
if (Sequence_NumTracks * 0x02 > Sequence_TrackIndex_size) { /* padding may exist */ if (NumTracks * 0x02 > TrackIndex_size) { /* padding may exist */
VGM_LOG("ACB: wrong Sequence.TrackIndex size\n"); VGM_LOG("ACB: wrong Sequence.TrackIndex size\n");
goto fail; goto fail;
} }
/* read Tracks inside Sequence */ /* read Tracks inside Sequence */
for (i = 0; i < Sequence_NumTracks; i++) { for (i = 0; i < NumTracks; i++) {
int16_t Sequence_TrackIndex_index = read_s16be(Sequence_TrackIndex_offset + i*0x02, acb->SequenceSf); int16_t TrackIndex_index = read_s16be(TrackIndex_offset + i*0x02, acb->SequenceSf);
if (!load_acb_track_event_command(acb, Sequence_TrackIndex_index)) if (!load_acb_track_event_command(acb, TrackIndex_index))
goto fail; goto fail;
} }
@ -471,75 +516,129 @@ fail:
static int load_acb_block(acb_header* acb, int16_t Index) { static int load_acb_block(acb_header* acb, int16_t Index) {
int i; int i;
uint16_t Block_NumTracks; uint16_t NumTracks;
uint32_t Block_TrackIndex_offset; uint32_t TrackIndex_offset, TrackIndex_size;
uint32_t Block_TrackIndex_size;
/* read Block[Index] */ /* read Block[Index] */
if (!open_utf_subtable(acb, &acb->BlockSf, &acb->BlockTable, "BlockTable", NULL, ACB_TABLE_BUFFER_BLOCK)) if (!open_utf_subtable(acb, &acb->BlockSf, &acb->BlockTable, "BlockTable", NULL, ACB_TABLE_BUFFER_BLOCK))
goto fail; goto fail;
if (!utf_query_u16(acb->BlockTable, Index, "NumTracks", &Block_NumTracks)) if (!utf_query_u16(acb->BlockTable, Index, "NumTracks", &NumTracks))
goto fail; goto fail;
if (!utf_query_data(acb->BlockTable, Index, "TrackIndex", &Block_TrackIndex_offset, &Block_TrackIndex_size)) if (!utf_query_data(acb->BlockTable, Index, "TrackIndex", &TrackIndex_offset, &TrackIndex_size))
goto fail; goto fail;
//;VGM_LOG("ACB: Block[%i]: NumTracks=%i, TrackIndex={%x, %x}\n", Index, Block_NumTracks, Block_TrackIndex_offset,Block_TrackIndex_size); //;VGM_LOG("ACB: Block[%i]: NumTracks=%i, TrackIndex={%x, %x}\n", Index, NumTracks, TrackIndex_offset,TrackIndex_size);
if (Block_NumTracks * 0x02 > Block_TrackIndex_size) { /* padding may exist */ if (NumTracks * 0x02 > TrackIndex_size) { /* padding may exist */
VGM_LOG("ACB: wrong Block.TrackIndex size\n"); VGM_LOG("ACB: wrong Block.TrackIndex size\n");
goto fail; goto fail;
} }
/* read Tracks inside Block */ //todo .ActionTrackStartIndex/NumActionTracks > ?
for (i = 0; i < Block_NumTracks; i++) {
int16_t Block_TrackIndex_index = read_s16be(Block_TrackIndex_offset + i*0x02, acb->BlockSf);
if (!load_acb_track_event_command(acb, Block_TrackIndex_index)) /* read Tracks inside Block */
for (i = 0; i < NumTracks; i++) {
int16_t TrackIndex_index = read_s16be(TrackIndex_offset + i*0x02, acb->BlockSf);
if (!load_acb_track_event_command(acb, TrackIndex_index))
goto fail; goto fail;
} }
return 1; return 1;
fail: fail:
return 0; return 0;
}
static int load_acb_blocksequence(acb_header* acb, int16_t Index) {
int i;
uint16_t NumTracks;
uint32_t TrackIndex_offset, TrackIndex_size;
uint16_t NumBlocks;
uint32_t BlockIndex_offset, BlockIndex_size;
/* read BlockSequence[Index] */
if (!open_utf_subtable(acb, &acb->BlockSequenceSf, &acb->BlockSequenceTable, "BlockSequenceTable", NULL, ACB_TABLE_BUFFER_BLOCKSEQUENCE))
goto fail;
if (!utf_query_u16(acb->BlockSequenceTable, Index, "NumTracks", &NumTracks))
goto fail;
if (!utf_query_data(acb->BlockSequenceTable, Index, "TrackIndex", &TrackIndex_offset, &TrackIndex_size))
goto fail;
if (!utf_query_u16(acb->BlockSequenceTable, Index, "NumBlocks", &NumBlocks))
goto fail;
if (!utf_query_data(acb->BlockSequenceTable, Index, "BlockIndex", &BlockIndex_offset, &BlockIndex_size))
goto fail;
//;VGM_LOG("ACB: BlockSequence[%i]: NumTracks=%i, TrackIndex={%x, %x}, NumBlocks=%i, BlockIndex={%x, %x}\n", Index, NumTracks, TrackIndex_offset,TrackIndex_size, NumBlocks, BlockIndex_offset,BlockIndex_size);
if (NumTracks * 0x02 > TrackIndex_size) { /* padding may exist */
VGM_LOG("ACB: wrong BlockSequence.TrackIndex size\n");
goto fail;
}
/* read Tracks inside BlockSequence */
for (i = 0; i < NumTracks; i++) {
int16_t TrackIndex_index = read_s16be(TrackIndex_offset + i*0x02, acb->BlockSequenceSf);
if (!load_acb_track_event_command(acb, TrackIndex_index))
goto fail;
}
if (NumBlocks * 0x02 > BlockIndex_size) {
VGM_LOG("ACB: wrong BlockSequence.BlockIndex size\n");
goto fail;
}
/* read Blocks inside BlockSequence */
for (i = 0; i < NumBlocks; i++) {
int16_t BlockIndex_index = read_s16be(BlockIndex_offset + i*0x02, acb->BlockSequenceSf);
if (!load_acb_block(acb, BlockIndex_index))
goto fail;
}
return 1;
fail:
return 0;
} }
static int load_acb_cue(acb_header* acb, int16_t Index) { static int load_acb_cue(acb_header* acb, int16_t Index) {
uint8_t Cue_ReferenceType; uint8_t ReferenceType;
uint16_t Cue_ReferenceIndex; uint16_t ReferenceIndex;
/* read Cue[Index] */ /* read Cue[Index] */
if (!open_utf_subtable(acb, &acb->CueSf, &acb->CueTable, "CueTable", NULL, ACB_TABLE_BUFFER_CUE)) if (!open_utf_subtable(acb, &acb->CueSf, &acb->CueTable, "CueTable", NULL, ACB_TABLE_BUFFER_CUE))
goto fail; goto fail;
if (!utf_query_u8(acb->CueTable, Index, "ReferenceType", &Cue_ReferenceType)) if (!utf_query_u8(acb->CueTable, Index, "ReferenceType", &ReferenceType))
goto fail; goto fail;
if (!utf_query_u16(acb->CueTable, Index, "ReferenceIndex", &Cue_ReferenceIndex)) if (!utf_query_u16(acb->CueTable, Index, "ReferenceIndex", &ReferenceIndex))
goto fail; goto fail;
//;VGM_LOG("ACB: Cue[%i]: ReferenceType=%i, ReferenceIndex=%i\n", Index, Cue_ReferenceType, Cue_ReferenceIndex); //;VGM_LOG("ACB: Cue[%i]: ReferenceType=%i, ReferenceIndex=%i\n", Index, ReferenceType, ReferenceIndex);
/* usually older games use older references but not necessarily */ /* usually older games use older references but not necessarily */
switch(Cue_ReferenceType) { switch(ReferenceType) {
case 0x01: /* Cue > Waveform (ex. PES 2015) */ case 0x01: /* Cue > Waveform (ex. PES 2015) */
if (!load_acb_waveform(acb, Cue_ReferenceIndex)) if (!load_acb_waveform(acb, ReferenceIndex))
goto fail; goto fail;
break; break;
case 0x02: /* Cue > Synth > Waveform (ex. Ukiyo no Roushi) */ case 0x02: /* Cue > Synth > Waveform (ex. Ukiyo no Roushi) */
if (!load_acb_synth(acb, Cue_ReferenceIndex)) if (!load_acb_synth(acb, ReferenceIndex))
goto fail; goto fail;
break; break;
case 0x03: /* Cue > Sequence > Track > Command > Synth > Waveform (ex. Valkyrie Profile anatomia, Yakuza Kiwami 2) */ case 0x03: /* Cue > Sequence > Track > Command > Synth > Waveform (ex. Valkyrie Profile anatomia, Yakuza Kiwami 2) */
if (!load_acb_sequence(acb, Cue_ReferenceIndex)) if (!load_acb_sequence(acb, ReferenceIndex))
goto fail; goto fail;
break; break;
//todo "blockSequence"? case 0x08: /* Cue > BlockSequence > Track / Block > Track > Command > Synth > Waveform (ex. Sonic Lost World, Kandagawa Jet Girls, rare) */
case 0x08: /* Cue > Block > Track > Command > Synth > Waveform (ex. Sonic Lost World, rare) */ if (!load_acb_blocksequence(acb, ReferenceIndex))
if (!load_acb_block(acb, Cue_ReferenceIndex))
goto fail; goto fail;
break; break;
@ -552,7 +651,7 @@ static int load_acb_cue(acb_header* acb, int16_t Index) {
case 0x0a: /* "eventCue_UnUse" */ case 0x0a: /* "eventCue_UnUse" */
case 0x0b: /* "soundGenerator" */ case 0x0b: /* "soundGenerator" */
default: default:
VGM_LOG("ACB: unknown Cue.ReferenceType=%x, Cue.ReferenceIndex=%x\n", Cue_ReferenceType, Cue_ReferenceIndex); VGM_LOG("ACB: unknown Cue.ReferenceType=%x, Cue.ReferenceIndex=%x\n", ReferenceType, ReferenceIndex);
break; /* ignore and continue */ break; /* ignore and continue */
} }
@ -560,29 +659,28 @@ static int load_acb_cue(acb_header* acb, int16_t Index) {
return 1; return 1;
fail: fail:
return 0; return 0;
} }
static int load_acb_cuename(acb_header* acb, int16_t Index) { static int load_acb_cuename(acb_header* acb, int16_t Index) {
uint16_t CueName_CueIndex; uint16_t CueIndex;
const char* CueName_CueName; const char* CueName;
/* read CueName[Index] */ /* read CueName[Index] */
if (!open_utf_subtable(acb, &acb->CueNameSf, &acb->CueNameTable, "CueNameTable", NULL, ACB_TABLE_BUFFER_CUENAME)) if (!open_utf_subtable(acb, &acb->CueNameSf, &acb->CueNameTable, "CueNameTable", NULL, ACB_TABLE_BUFFER_CUENAME))
goto fail; goto fail;
if (!utf_query_u16(acb->CueNameTable, Index, "CueIndex", &CueName_CueIndex)) if (!utf_query_u16(acb->CueNameTable, Index, "CueIndex", &CueIndex))
goto fail; goto fail;
if (!utf_query_string(acb->CueNameTable, Index, "CueName", &CueName_CueName)) if (!utf_query_string(acb->CueNameTable, Index, "CueName", &CueName))
goto fail; goto fail;
//;VGM_LOG("ACB: CueName[%i]: CueIndex=%i, CueName=%s\n", Index, CueName_CueIndex, CueName_CueName); //;VGM_LOG("ACB: CueName[%i]: CueIndex=%i, CueName=%s\n", Index, CueIndex, CueName);
/* save as will be needed if references waveform */ /* save as will be needed if references waveform */
acb->cuename_index = Index; acb->cuename_index = Index;
acb->cuename_name = CueName_CueName; acb->cuename_name = CueName;
if (!load_acb_cue(acb, CueName_CueIndex)) if (!load_acb_cue(acb, CueIndex))
goto fail; goto fail;
return 1; return 1;
@ -615,10 +713,10 @@ void load_acb_wave_name(STREAMFILE* sf, VGMSTREAM* vgmstream, int waveid, int is
* - CueName > Cue > Sequence > Track > TrackEvent > Command > Synth > Synth > Waveform (type 3, >=v1.28) * - CueName > Cue > Sequence > Track > TrackEvent > Command > Synth > Synth > Waveform (type 3, >=v1.28)
* - CueName > Cue > Sequence > Track > TrackEvent > Command > Sequence > (...) > Synth > Waveform (type 3, >=v1.28) * - CueName > Cue > Sequence > Track > TrackEvent > Command > Sequence > (...) > Synth > Waveform (type 3, >=v1.28)
* - CueName > Cue > Block > Track > Command > Synth > Synth > Waveform (type 8) * - CueName > Cue > Block > Track > Command > Synth > Synth > Waveform (type 8)
* - others should be possible but haven't been observed * - others should be possible
* Atom Craft may only target certain .acb versions so some links are later removed * Atom Craft may only target certain .acb versions so some links are later removed
* Not all cues to point to though Waveforms, as some are just config events/commands. * Not all cues to point to Waveforms, some are just config events/commands.
* .acb link to .awb by name (loaded manually), though they have a checksum/hash to validate. * .acb link to .awb by name (loaded manually), though they have a checksum/hash/header to validate.
*/ */
//;VGM_LOG("ACB: find waveid=%i\n", waveid); //;VGM_LOG("ACB: find waveid=%i\n", waveid);
@ -654,6 +752,8 @@ fail:
utf_close(acb.CueNameTable); utf_close(acb.CueNameTable);
utf_close(acb.CueTable); utf_close(acb.CueTable);
utf_close(acb.BlockSequenceTable);
utf_close(acb.BlockTable);
utf_close(acb.SequenceTable); utf_close(acb.SequenceTable);
utf_close(acb.TrackTable); utf_close(acb.TrackTable);
utf_close(acb.TrackCommandTable); utf_close(acb.TrackCommandTable);
@ -662,6 +762,8 @@ fail:
close_streamfile(acb.CueNameSf); close_streamfile(acb.CueNameSf);
close_streamfile(acb.CueSf); close_streamfile(acb.CueSf);
close_streamfile(acb.BlockSequenceSf);
close_streamfile(acb.BlockSf);
close_streamfile(acb.SequenceSf); close_streamfile(acb.SequenceSf);
close_streamfile(acb.TrackSf); close_streamfile(acb.TrackSf);
close_streamfile(acb.TrackCommandSf); close_streamfile(acb.TrackCommandSf);

View file

@ -0,0 +1,51 @@
#include "meta.h"
#include "../coding/coding.h"
/* ADP - from Konami Viper arcade games [ParaParaParadise 2ndMIX (AC)] */
VGMSTREAM* init_vgmstream_adp_konami(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channels;
size_t data_size, file_size;
/* checks */
if (!check_extensions(sf, "adp"))
goto fail;
if (read_u32be(0x00,sf) != 0x41445002) /* "ADP\2" */
goto fail;
start_offset = 0x10;
channels = 2; /* probably @0x03 */
loop_flag = 0;
data_size = read_u32be(0x04,sf);
file_size = get_streamfile_size(sf);
if (!(data_size + start_offset - 0x04 <= file_size &&
data_size + start_offset + 0x04 >= file_size)) /* 1 byte padding in some files */
goto fail;
if (read_u32be(0x08,sf) != 0 || read_u32be(0x0c,sf) != 0) /* maybe reserved for loop points */
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_ADP_KONAMI;
vgmstream->sample_rate = 44100;
vgmstream->num_samples = oki_bytes_to_samples(data_size, channels);
vgmstream->coding_type = coding_OKI4S;
vgmstream->layout_type = layout_none;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -79,12 +79,14 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
coding_type = coding_CRI_ADX_enc_8; coding_type = coding_CRI_ADX_enc_8;
version = 0x0400; version = 0x0400;
} }
VGM_ASSERT(version != 0x0400, "ADX: keystring not found\n");
} }
else if (version == 0x0409) { else if (version == 0x0409) {
if (find_adx_key(streamFile, 9, &xor_start, &xor_mult, &xor_add)) { if (find_adx_key(streamFile, 9, &xor_start, &xor_mult, &xor_add)) {
coding_type = coding_CRI_ADX_enc_9; coding_type = coding_CRI_ADX_enc_9;
version = 0x0400; version = 0x0400;
} }
VGM_ASSERT(version != 0x0400, "ADX: keycode not found\n");
} }
/* version + extra data */ /* version + extra data */

View file

@ -196,6 +196,9 @@ static const adxkey_info adxkey8_list[] = {
/* 428: Fuusasareta Shibuya de (PS3) */ /* 428: Fuusasareta Shibuya de (PS3) */
{0x52ff,0x649f,0x448f, "hj1kviaqqdzUacryoacwmscfvwtlfkVbbbqpqmzqnbile2euljywazejgyxxvqlf",0}, {0x52ff,0x649f,0x448f, "hj1kviaqqdzUacryoacwmscfvwtlfkVbbbqpqmzqnbile2euljywazejgyxxvqlf",0},
/* Mirai Nikki: 13-ninme no Nikki Shoyuusha Re-Write (PSP) */
{0x58a3,0x66f5,0x599f, "FDRW17th",0},
}; };
static const adxkey_info adxkey9_list[] = { static const adxkey_info adxkey9_list[] = {

View file

@ -128,12 +128,8 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
/* Alt decoding without libvorbis (minor number of beginning samples difference). /* Alt decoding without libvorbis (minor number of beginning samples difference).
* Otherwise same output with (inaudible) +-1 lower byte differences due to rounding. */ * Otherwise same output with (inaudible) +-1 lower byte differences due to rounding. */
case 0x05: { /* Ogg Vorbis [Final Fantasy VI (iOS), Dragon Quest II-VI (iOS)] */ case 0x05: { /* Ogg Vorbis [Final Fantasy VI (iOS), Dragon Quest II-VI (iOS)] */
ffmpeg_codec_data *ffmpeg_data; vgmstream->codec_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
if (!vgmstream->codec_data) goto fail;
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
/* These oggs have loop info in the comments, too */ /* These oggs have loop info in the comments, too */
@ -149,12 +145,8 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
case 0x06: { /* M4A with AAC [The World Ends with You (iPad)] */ case 0x06: { /* M4A with AAC [The World Ends with You (iPad)] */
/* init_vgmstream_akb_mp4 above has priority, but this works fine too */ /* init_vgmstream_akb_mp4 above has priority, but this works fine too */
ffmpeg_codec_data *ffmpeg_data; vgmstream->codec_data = init_ffmpeg_offset(streamFile, start_offset,stream_size-start_offset);
if (!vgmstream->codec_data) goto fail;
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size-start_offset);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;

View file

@ -7,37 +7,51 @@ VGMSTREAM * init_vgmstream_ast(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM * vgmstream = NULL;
off_t start_offset; off_t start_offset;
int loop_flag, channel_count, codec; int loop_flag, channel_count, codec;
int big_endian;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
/* checks */ /* checks */
if (!check_extensions(streamFile, "ast")) if (!check_extensions(streamFile, "ast"))
goto fail; goto fail;
if (read_32bitBE(0x00,streamFile) != 0x5354524D) /* "STRM" */
if (((uint32_t)read_32bitBE(0x00, streamFile) == 0x5354524D) && /* "STRM" */
((uint32_t)read_32bitBE(0x40, streamFile) == 0x424C434B)) { /* "BLCK" */
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
big_endian = 1;
} else if (((uint32_t)read_32bitBE(0x00, streamFile) == 0x4D525453) && /* "MRTS" */ // Super Mario Galaxy (Super Mario 3D All-Stars (Switch))
((uint32_t)read_32bitBE(0x40, streamFile) == 0x4B434C42)) { /* "KCLB" */
read_32bit = read_32bitLE;
read_16bit = read_16bitLE;
big_endian = 0;
} else {
goto fail; goto fail;
if (read_16bitBE(0x0a,streamFile) != 0x10) /* ? */ }
if (read_16bit(0x0a,streamFile) != 0x10) /* ? */
goto fail; goto fail;
if (read_32bitBE(0x04,streamFile)+0x40 != get_streamfile_size(streamFile)) if (read_32bit(0x04,streamFile)+0x40 != get_streamfile_size(streamFile))
goto fail; goto fail;
codec = read_16bitBE(0x08,streamFile);
channel_count = read_16bitBE(0x0c,streamFile);
loop_flag = read_16bitBE(0x0e,streamFile);
//max_block = read_32bitBE(0x20,streamFile);
codec = read_16bitBE(0x08,streamFile); // always big-endian?
channel_count = read_16bit(0x0c,streamFile);
loop_flag = read_16bit(0x0e,streamFile);
//max_block = read_32bit(0x20,streamFile);
start_offset = 0x40; start_offset = 0x40;
if (read_32bitBE(start_offset,streamFile) != 0x424C434B) /* "BLCK" */
goto fail;
/* build the VGMSTREAM */ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag); vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->meta_type = meta_AST; vgmstream->meta_type = meta_AST;
vgmstream->sample_rate = read_32bitBE(0x10,streamFile); vgmstream->sample_rate = read_32bit(0x10,streamFile);
vgmstream->num_samples = read_32bitBE(0x14,streamFile); vgmstream->num_samples = read_32bit(0x14,streamFile);
vgmstream->loop_start_sample = read_32bitBE(0x18,streamFile); vgmstream->loop_start_sample = read_32bit(0x18,streamFile);
vgmstream->loop_end_sample = read_32bitBE(0x1c,streamFile); vgmstream->loop_end_sample = read_32bit(0x1c,streamFile);
vgmstream->codec_endian = big_endian;
vgmstream->layout_type = layout_blocked_ast; vgmstream->layout_type = layout_blocked_ast;
switch (codec) { switch (codec) {

View file

@ -3,42 +3,42 @@
typedef enum { ADX, HCA, VAG, RIFF, CWAV, DSP } awb_type; typedef enum { ADX, HCA, VAG, RIFF, CWAV, DSP } awb_type;
static void load_awb_name(STREAMFILE *streamFile, STREAMFILE *acbFile, VGMSTREAM *vgmstream, int waveid); static void load_awb_name(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstream, int waveid);
/* AFS2/AWB (Atom Wave Bank) - CRI container of streaming audio, often together with a .acb cue sheet */ /* AFS2/AWB (Atom Wave Bank) - CRI container of streaming audio, often together with a .acb cue sheet */
VGMSTREAM * init_vgmstream_awb(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_awb(STREAMFILE* sf) {
return init_vgmstream_awb_memory(streamFile, NULL); return init_vgmstream_awb_memory(sf, NULL);
} }
VGMSTREAM * init_vgmstream_awb_memory(STREAMFILE *streamFile, STREAMFILE *acbFile) { VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
VGMSTREAM *vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL; STREAMFILE* temp_sf = NULL;
off_t offset, subfile_offset, subfile_next; off_t offset, subfile_offset, subfile_next;
size_t subfile_size; size_t subfile_size;
int total_subsongs, target_subsong = streamFile->stream_index; int total_subsongs, target_subsong = sf->stream_index;
//uint32_t flags; //uint32_t flags;
uint8_t offset_size; uint8_t offset_size;
uint16_t alignment, subkey; uint16_t alignment, subkey;
awb_type type; awb_type type;
char *extension = NULL; const char* extension = NULL;
int waveid; int waveid;
/* checks /* checks
* .awb: standard * .awb: standard
* .afs2: sometimes [Okami HD (PS4)] */ * .afs2: sometimes [Okami HD (PS4)] */
if (!check_extensions(streamFile, "awb,afs2")) if (!check_extensions(sf, "awb,afs2"))
goto fail; goto fail;
if (read_u32be(0x00,streamFile) != 0x41465332) /* "AFS2" */ if (read_u32be(0x00,sf) != 0x41465332) /* "AFS2" */
goto fail; goto fail;
//flags = read_32bitLE(0x08,streamFile); //flags = read_32bitLE(0x08,sf);
/* 0x04(1): version? 0x01=common, 0x02=2018+ (no apparent differences) */ /* 0x04(1): version? 0x01=common, 0x02=2018+ (no apparent differences) */
offset_size = read_u8(0x05,streamFile); offset_size = read_u8(0x05,sf);
/* 0x06(2): always 0x0002? */ /* 0x06(2): always 0x0002? */
total_subsongs = read_s32le(0x08,streamFile); total_subsongs = read_s32le(0x08,sf);
alignment = read_u16le(0x0c,streamFile); alignment = read_u16le(0x0c,sf);
subkey = read_u16le(0x0e,streamFile); subkey = read_u16le(0x0e,sf);
if (target_subsong == 0) target_subsong = 1; if (target_subsong == 0) target_subsong = 1;
if (target_subsong > total_subsongs || total_subsongs <= 0) goto fail; if (target_subsong > total_subsongs || total_subsongs <= 0) goto fail;
@ -49,26 +49,26 @@ VGMSTREAM * init_vgmstream_awb_memory(STREAMFILE *streamFile, STREAMFILE *acbFil
{ {
off_t waveid_offset = offset + (target_subsong-1) * 0x02; off_t waveid_offset = offset + (target_subsong-1) * 0x02;
waveid = read_u16le(waveid_offset,streamFile); waveid = read_u16le(waveid_offset,sf);
offset += total_subsongs * 0x02; offset += total_subsongs * 0x02;
} }
/* offset table: find target */ /* offset table: find target */
{ {
off_t file_size = get_streamfile_size(streamFile); off_t file_size = get_streamfile_size(sf);
/* last sub-offset is always file end, so table entries = total_subsongs+1 */ /* last sub-offset is always file end, so table entries = total_subsongs+1 */
offset += (target_subsong-1) * offset_size; offset += (target_subsong-1) * offset_size;
switch(offset_size) { switch(offset_size) {
case 0x04: /* common */ case 0x04: /* common */
subfile_offset = read_u32le(offset+0x00,streamFile); subfile_offset = read_u32le(offset+0x00,sf);
subfile_next = read_u32le(offset+0x04,streamFile); subfile_next = read_u32le(offset+0x04,sf);
break; break;
case 0x02: /* mostly sfx in .acb */ case 0x02: /* mostly sfx in .acb */
subfile_offset = read_u16le(offset+0x00,streamFile); subfile_offset = read_u16le(offset+0x00,sf);
subfile_next = read_u16le(offset+0x02,streamFile); subfile_next = read_u16le(offset+0x02,sf);
break; break;
default: default:
VGM_LOG("AWB: unknown offset size\n"); VGM_LOG("AWB: unknown offset size\n");
@ -87,31 +87,32 @@ VGMSTREAM * init_vgmstream_awb_memory(STREAMFILE *streamFile, STREAMFILE *acbFil
/* autodetect as there isn't anything, plus can mix types /* autodetect as there isn't anything, plus can mix types
* (waveid<>codec info is usually in the companion .acb) */ * (waveid<>codec info is usually in the companion .acb) */
if (read_u16be(subfile_offset, streamFile) == 0x8000) { /* ADX id (type 0) */ if (read_u16be(subfile_offset, sf) == 0x8000) { /* ADX id (type 0) */
type = ADX; type = ADX;
extension = "adx"; extension = "adx";
} }
else if ((read_u32be(subfile_offset,streamFile) & 0x7f7f7f7f) == 0x48434100) { /* "HCA\0" (type 2=HCA, 6=HCA-MX) */ else if ((read_u32be(subfile_offset,sf) & 0x7f7f7f7f) == 0x48434100) { /* "HCA\0" (type 2=HCA, 6=HCA-MX) */
type = HCA; type = HCA;
extension = "hca"; extension = "hca";
} }
else if (read_u32be(subfile_offset,streamFile) == 0x56414770) { /* "VAGp" (type 7=VAG, 10=HEVAG) */ else if (read_u32be(subfile_offset,sf) == 0x56414770) { /* "VAGp" (type 7=VAG, 10=HEVAG) */
type = VAG; type = VAG;
extension = "vag"; extension = "vag";
} }
else if (read_u32be(subfile_offset,streamFile) == 0x52494646) { /* "RIFF" (type 8=ATRAC3, 11=ATRAC9) */ else if (read_u32be(subfile_offset,sf) == 0x52494646) { /* "RIFF" (type 8=ATRAC3, 11=ATRAC9) */
type = RIFF; type = RIFF;
extension = "wav"; extension = "wav";
subfile_size = read_u32le(subfile_offset + 0x04,sf) + 0x08; /* rough size, use RIFF's */
} }
else if (read_u32be(subfile_offset,streamFile) == 0x43574156) { /* "CWAV" (type 9) */ else if (read_u32be(subfile_offset,sf) == 0x43574156) { /* "CWAV" (type 9) */
type = CWAV; type = CWAV;
extension = "bcwav"; extension = "bcwav";
} }
else if (read_u32be(subfile_offset + 0x08,streamFile) >= 8000 && else if (read_u32be(subfile_offset + 0x08,sf) >= 8000 &&
read_u32be(subfile_offset + 0x08,streamFile) <= 48000 && read_u32be(subfile_offset + 0x08,sf) <= 48000 &&
read_u16be(subfile_offset + 0x0e,streamFile) == 0 && read_u16be(subfile_offset + 0x0e,sf) == 0 &&
read_u32be(subfile_offset + 0x18,streamFile) == 2 && read_u32be(subfile_offset + 0x18,sf) == 2 &&
read_u32be(subfile_offset + 0x50,streamFile) == 0) { /* probably should call some check function (type 13) */ read_u32be(subfile_offset + 0x50,sf) == 0) { /* probably should call some check function (type 13) */
type = DSP; type = DSP;
extension = "dsp"; extension = "dsp";
} }
@ -121,32 +122,32 @@ VGMSTREAM * init_vgmstream_awb_memory(STREAMFILE *streamFile, STREAMFILE *acbFil
} }
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, extension); temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, extension);
if (!temp_streamFile) goto fail; if (!temp_sf) goto fail;
switch(type) { switch(type) {
case HCA: /* most common */ case HCA: /* most common */
vgmstream = init_vgmstream_hca_subkey(temp_streamFile, subkey); vgmstream = init_vgmstream_hca_subkey(temp_sf, subkey);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
break; break;
case ADX: /* Okami HD (PS4) */ case ADX: /* Okami HD (PS4) */
vgmstream = init_vgmstream_adx(temp_streamFile); vgmstream = init_vgmstream_adx(temp_sf);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
break; break;
case VAG: /* Ukiyo no Roushi (Vita) */ case VAG: /* Ukiyo no Roushi (Vita) */
vgmstream = init_vgmstream_vag(temp_streamFile); vgmstream = init_vgmstream_vag(temp_sf);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
break; break;
case RIFF: /* Ukiyo no Roushi (Vita) */ case RIFF: /* Ukiyo no Roushi (Vita) */
vgmstream = init_vgmstream_riff(temp_streamFile); vgmstream = init_vgmstream_riff(temp_sf);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
break; break;
case CWAV: /* Sonic: Lost World (3DS) */ case CWAV: /* Sonic: Lost World (3DS) */
vgmstream = init_vgmstream_rwsd(temp_streamFile); vgmstream = init_vgmstream_rwsd(temp_sf);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
break; break;
case DSP: /* Sonic: Lost World (WiiU) */ case DSP: /* Sonic: Lost World (WiiU) */
vgmstream = init_vgmstream_ngc_dsp_std(temp_streamFile); vgmstream = init_vgmstream_ngc_dsp_std(temp_sf);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
break; break;
default: default:
@ -156,20 +157,20 @@ VGMSTREAM * init_vgmstream_awb_memory(STREAMFILE *streamFile, STREAMFILE *acbFil
vgmstream->num_streams = total_subsongs; vgmstream->num_streams = total_subsongs;
/* try to load cue names */ /* try to load cue names */
load_awb_name(streamFile, acbFile, vgmstream, waveid); load_awb_name(sf, sf_acb, vgmstream, waveid);
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;
} }
static void load_awb_name(STREAMFILE *streamFile, STREAMFILE *acbFile, VGMSTREAM* vgmstream, int waveid) { static void load_awb_name(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstream, int waveid) {
int is_memory = (acbFile != NULL); int is_memory = (sf_acb != NULL);
/* .acb is passed when loading memory .awb inside .acb */ /* .acb is passed when loading memory .awb inside .acb */
if (!is_memory) { if (!is_memory) {
@ -179,40 +180,40 @@ static void load_awb_name(STREAMFILE *streamFile, STREAMFILE *acbFile, VGMSTREAM
/* try (name).awb + (name).awb */ /* try (name).awb + (name).awb */
acbFile = open_streamfile_by_ext(streamFile, "acb"); sf_acb = open_streamfile_by_ext(sf, "acb");
/* try (name)_streamfiles.awb + (name).acb */ /* try (name)_streamfiles.awb + (name).acb */
if (!acbFile) { if (!sf_acb) {
char *cmp = "_streamfiles"; char *cmp = "_streamfiles";
get_streamfile_basename(streamFile, filename, sizeof(filename)); get_streamfile_basename(sf, filename, sizeof(filename));
len_name = strlen(filename); len_name = strlen(filename);
len_cmp = strlen(cmp); len_cmp = strlen(cmp);
if (len_name > len_cmp && strcmp(filename + len_name - len_cmp, cmp) == 0) { if (len_name > len_cmp && strcmp(filename + len_name - len_cmp, cmp) == 0) {
filename[len_name - len_cmp] = '\0'; filename[len_name - len_cmp] = '\0';
strcat(filename, ".acb"); strcat(filename, ".acb");
acbFile = open_streamfile_by_filename(streamFile, filename); sf_acb = open_streamfile_by_filename(sf, filename);
} }
} }
/* try (name)_STR.awb + (name).acb */ /* try (name)_STR.awb + (name).acb */
if (!acbFile) { if (!sf_acb) {
char *cmp = "_STR"; char *cmp = "_STR";
get_streamfile_basename(streamFile, filename, sizeof(filename)); get_streamfile_basename(sf, filename, sizeof(filename));
len_name = strlen(filename); len_name = strlen(filename);
len_cmp = strlen(cmp); len_cmp = strlen(cmp);
if (len_name > len_cmp && strcmp(filename + len_name - len_cmp, cmp) == 0) { if (len_name > len_cmp && strcmp(filename + len_name - len_cmp, cmp) == 0) {
filename[len_name - len_cmp] = '\0'; filename[len_name - len_cmp] = '\0';
strcat(filename, ".acb"); strcat(filename, ".acb");
acbFile = open_streamfile_by_filename(streamFile, filename); sf_acb = open_streamfile_by_filename(sf, filename);
} }
} }
/* try (name)_(name)_R001.awb + (name).acb [Sengoku Basara Battle Party (Mobile)] */ /* try (name)_(name)_R001.awb + (name).acb [Sengoku Basara Battle Party (Mobile)] */
if (!acbFile) { if (!sf_acb) {
char *cmp = "_R001"; char *cmp = "_R001";
get_streamfile_basename(streamFile, filename, sizeof(filename)); get_streamfile_basename(sf, filename, sizeof(filename));
len_name = strlen(filename); len_name = strlen(filename);
len_cmp = strlen(cmp); len_cmp = strlen(cmp);
@ -220,16 +221,16 @@ static void load_awb_name(STREAMFILE *streamFile, STREAMFILE *acbFile, VGMSTREAM
filename[(len_name - len_cmp) / 2] = '\0'; filename[(len_name - len_cmp) / 2] = '\0';
strcat(filename, ".acb"); strcat(filename, ".acb");
VGM_LOG("%s\n", filename); VGM_LOG("%s\n", filename);
acbFile = open_streamfile_by_filename(streamFile, filename); sf_acb = open_streamfile_by_filename(sf, filename);
} }
} }
/* probably loaded */ /* probably loaded */
load_acb_wave_name(acbFile, vgmstream, waveid, is_memory); load_acb_wave_name(sf_acb, vgmstream, waveid, is_memory);
close_streamfile(acbFile); close_streamfile(sf_acb);
} }
else { else {
load_acb_wave_name(acbFile, vgmstream, waveid, is_memory); load_acb_wave_name(sf_acb, vgmstream, waveid, is_memory);
} }
} }

View file

@ -8,9 +8,10 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
STREAMFILE* temp_sf = NULL; STREAMFILE* temp_sf = NULL;
off_t subfile_offset, base_offset = 0; off_t subfile_offset, base_offset = 0;
size_t subfile_size; size_t subfile_size;
uint32_t subfile_id, header_id; uint32_t subfile_id;
int big_endian, version, is_dummy = 0; int big_endian, version, is_riff = 0, is_dummy = 0, is_wmid = 0;
uint32_t (*read_u32)(off_t,STREAMFILE*); uint32_t (*read_u32)(off_t,STREAMFILE*);
float (*read_f32)(off_t,STREAMFILE*);
int total_subsongs, target_subsong = sf->stream_index; int total_subsongs, target_subsong = sf->stream_index;
@ -24,6 +25,7 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
goto fail; goto fail;
big_endian = guess_endianness32bit(base_offset + 0x04, sf); big_endian = guess_endianness32bit(base_offset + 0x04, sf);
read_u32 = big_endian ? read_u32be : read_u32le; read_u32 = big_endian ? read_u32be : read_u32le;
read_f32 = big_endian ? read_f32be : read_f32le;
/* Wwise banks have event/track/sequence/etc info in the HIRC chunk, as well /* Wwise banks have event/track/sequence/etc info in the HIRC chunk, as well
@ -91,26 +93,37 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
subfile_size = read_u32(offset + 0x08, sf); subfile_size = read_u32(offset + 0x08, sf);
} }
/* some indexes don't have that, but for now leave a dummy song for easier HIRC mapping */ //;VGM_LOG("BKHD: %lx, %x\n", subfile_offset, subfile_size);
/* detect format */
if (subfile_offset <= 0 || subfile_size <= 0) { if (subfile_offset <= 0 || subfile_size <= 0) {
//;VGM_LOG("BKHD: dummy entry"); /* some indexes don't have data */
temp_sf = setup_subfile_streamfile(sf, 0x00, 0x10, "raw");
if (!temp_sf) goto fail;
//todo make some better silent entry
vgmstream = init_vgmstream_raw_pcm(temp_sf);
if (!vgmstream) goto fail;
is_dummy = 1; is_dummy = 1;
} }
else if (read_u32be(subfile_offset + 0x00, sf) == 0x52494646 || /* "RIFF" */
read_u32be(subfile_offset + 0x00, sf) == 0x52494658) { /* "RIFX" */
is_riff = 1;
}
else if (read_f32(subfile_offset + 0x02, sf) >= 30.0 &&
read_f32(subfile_offset + 0x02, sf) <= 250.0) {
/* ignore Wwise's custom .wmid (similar to a regular midi but with simplified
* chunks and custom fields: 0x00=MThd's division, 0x02: bpm (new), etc) */
is_wmid = 1;
}
/* default is sfx */
if (is_dummy || is_wmid) {
/* for now leave a dummy song for easier .bnk index-to-subsong mapping */
vgmstream = init_vgmstream_silence(0, 0, 0);
if (!vgmstream) goto fail;
}
else { else {
//;VGM_LOG("BKHD: %lx, %x\n", subfile_offset, subfile_size);
/* could pass .wem but few files need memory .wem detection */ /* could pass .wem but few files need memory .wem detection */
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, NULL); temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, NULL);
if (!temp_sf) goto fail; if (!temp_sf) goto fail;
header_id = read_u32be(0x00, temp_sf); if (is_riff) {
if (header_id == 0x52494646 || header_id == 0x52494658) { /* "RIFF" / "RIFX" */
vgmstream = init_vgmstream_wwise(temp_sf); vgmstream = init_vgmstream_wwise(temp_sf);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
} }
@ -124,7 +137,9 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
vgmstream->num_streams = total_subsongs; vgmstream->num_streams = total_subsongs;
if (is_dummy) if (is_dummy)
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%s", "dummy"); snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%u/dummy", subfile_id);
else if (is_wmid)
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%u/wmid", subfile_id);
else if (subfile_id != 0xFFFFFFFF) else if (subfile_id != 0xFFFFFFFF)
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%u", subfile_id); snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%u", subfile_id);

View file

@ -106,26 +106,39 @@ VGMSTREAM * init_vgmstream_brstm(STREAMFILE *streamFile) {
if (vgmstream->coding_type == coding_NGC_DSP) { if (vgmstream->coding_type == coding_NGC_DSP) {
off_t coef_offset; off_t coef_offset;
off_t coef_offset1; off_t head_part3_offset;
off_t coef_offset2; off_t adpcm_header_offset;
int i,j; int i,j;
int coef_spacing = 0x38; int coef_spacing;
if (atlus_shrunken_head) if (atlus_shrunken_head)
{ {
coef_offset = 0x50; coef_offset = 0x50;
coef_spacing = 0x30; coef_spacing = 0x30;
for (j = 0; j < vgmstream->channels; j++) {
for (i = 0; i < 16; i++) {
vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(head_offset + coef_offset + j * coef_spacing + i * 2,streamFile);
}
}
} }
else else
{ {
coef_offset1=read_32bitBE(head_offset+0x1c,streamFile); head_part3_offset = read_32bitBE(head_offset + 0x1c, streamFile);
coef_offset2=read_32bitBE(head_offset+0x10+coef_offset1,streamFile);
coef_offset=coef_offset2+0x10;
}
for (j=0;j<vgmstream->channels;j++) { for (j = 0; j < vgmstream->channels; j++) {
for (i=0;i<16;i++) { adpcm_header_offset = head_offset + 0x08
vgmstream->ch[j].adpcm_coef[i]=read_16bitBE(head_offset+coef_offset+j*coef_spacing+i*2,streamFile); + head_part3_offset + 0x04 /* skip over HEAD part 3 */
+ j * 0x08 /* skip to channel's ADPCM offset table */
+ 0x04; /* ADPCM header offset field */
coef_offset = head_offset + 0x08
+ read_32bitBE(adpcm_header_offset, streamFile)
+ 0x08; /* coeffs field */
for (i = 0; i < 16; i++) {
vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_offset + i * 2, streamFile);
}
} }
} }
} }

View file

@ -0,0 +1,97 @@
#include "meta.h"
#include "../coding/coding.h"
/* .bsf - from Kuju games [Reign of Fire ((PS2/GC/Xbox)] */
VGMSTREAM* init_vgmstream_bsf(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
uint32_t subfile_type;
off_t subfile_name;
off_t subfile_offset;
size_t subfile_size;
int total_subsongs, target_subsong = sf->stream_index;
/* checks */
if (!check_extensions(sf,"bsf"))
goto fail;
if (read_u32le(0x00,sf) != 0x42534648) /* "BSFH" (notice chunks are LE even on GC) */
goto fail;
total_subsongs = read_u32le(0x08,sf);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
/* dumb container of other formats */
{
int i;
off_t offset = 0x08 + read_u32le(0x04,sf); /* 0x04: chunk size */
subfile_type = 0;
for (i = 0; i < total_subsongs; i++) {
/* subsong header "xxxH" */
//uint32_t head_type = read_u32le(offset + 0x00,sf);
uint32_t head_size = read_u32le(offset + 0x04,sf);
/* 0x08: name
* 0x28: audio config? */
/* subsong data "xxxD" */
uint32_t data_type = read_u32le(offset + 0x08 + head_size + 0x00,sf);
uint32_t data_size = read_u32le(offset + 0x08 + head_size + 0x04,sf);
if (i + 1 == target_subsong) {
subfile_name = offset + 0x08;
subfile_type = data_type;
subfile_size = data_size;
subfile_offset = offset + 0x08 + head_size + 0x08;
break;
}
offset += 0x08 + head_size + 0x08 + data_size;
}
if (subfile_type == 0)
goto fail;
}
switch(subfile_type) {
case 0x44535044: /* "DSPD" */
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "dsp");
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_ngc_dsp_std(temp_sf);
if (!vgmstream) goto fail;
break;
case 0x56414744: /* "VAGD" */
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "vag");
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_vag(temp_sf);
if (!vgmstream) goto fail;
break;
case 0x57415644: /* "WAVD" */
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "wav");
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_riff(temp_sf);
if (!vgmstream) goto fail;
break;
default:
goto fail;
}
vgmstream->num_streams = total_subsongs;
read_string(vgmstream->stream_name, 0x20, subfile_name, sf);
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -23,6 +23,7 @@ static size_t deblock_io_read(STREAMFILE* sf, uint8_t* dest, off_t offset, size_
data->block_size = 0; data->block_size = 0;
data->data_size = 0; data->data_size = 0;
data->skip_size = 0; data->skip_size = 0;
data->chunk_size = 0;
data->step_count = data->cfg.step_start; data->step_count = data->cfg.step_start;
//data->read_count = data->cfg.read_count; //data->read_count = data->cfg.read_count;

View file

@ -49,6 +49,7 @@ struct deblock_io_data {
off_t block_size; /* current block (added to physical offset) */ off_t block_size; /* current block (added to physical offset) */
off_t skip_size; /* data to skip from block start to reach data (like a header) */ off_t skip_size; /* data to skip from block start to reach data (like a header) */
off_t data_size; /* usable data in a block (added to logical offset) */ off_t data_size; /* usable data in a block (added to logical offset) */
off_t chunk_size; /* current super-block size (for complex blocks, handled manually) */
int step_count; /* number of blocks to step over */ int step_count; /* number of blocks to step over */
//int read_count; /* number of blocks to read */ //int read_count; /* number of blocks to read */

View file

@ -0,0 +1,54 @@
#include "meta.h"
#include "../coding/coding.h"
/* .dsb - from Namco games [Taiko no Tatsujin DS: Dororon! Yokai Daikessen!! (DS)] */
VGMSTREAM* init_vgmstream_dsb(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
off_t subfile_offset;
size_t subfile_size;
/* checks */
if (!check_extensions(sf,"dsb"))
goto fail;
if (read_u32be(0x00,sf) != 0x44535342) /* "DSSB" */
goto fail;
if (read_u32be(0x40,sf) != 0x44535354) /* "DSST" */
goto fail;
/* - DDSB:
* 0x04: chunk size
* 0x08: file name
* 0x14: sample rate
* 0x18: v01?
* 0x1c: file size
* 0x20: DSST offset
*
* - DDST:
* 0x44: chunk size
* 0x48: file name
* 0x58: small signed number?
* 0x5c: data size (with padding)
* 0x60: small signed number?
* 0x64: ?
* rest: null
*/
subfile_offset = 0x80;
subfile_size = read_u32be(0x80 + 0x04, sf) + 0x08; /* files are padded so use BNSF */
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "bnsf");
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_bnsf(temp_sf);
if (!vgmstream) goto fail;
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -598,7 +598,7 @@ static STREAMFILE *open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks)
/* EA MPF/MUS combo - used in older 7th gen games for storing interactive music */ /* EA MPF/MUS combo - used in older 7th gen games for storing interactive music */
VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE* sf) { VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE* sf) {
uint32_t num_tracks, track_start, track_hash, mus_sounds, mus_stream = 0; uint32_t num_tracks, track_start, track_hash = 0, mus_sounds, mus_stream = 0;
uint8_t version, sub_version; uint8_t version, sub_version;
off_t tracks_table, samples_table, eof_offset, table_offset, entry_offset, snr_offset, sns_offset; off_t tracks_table, samples_table, eof_offset, table_offset, entry_offset, snr_offset, sns_offset;
int32_t(*read_32bit)(off_t, STREAMFILE*); int32_t(*read_32bit)(off_t, STREAMFILE*);
@ -639,6 +639,9 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE* sf) {
entry_offset = read_32bit(tracks_table + i * 0x04, sf) * 0x04; entry_offset = read_32bit(tracks_table + i * 0x04, sf) * 0x04;
track_start = read_32bit(entry_offset + 0x00, sf); track_start = read_32bit(entry_offset + 0x00, sf);
if (track_start == 0 && i != 0)
continue; /* empty track */
if (track_start <= target_stream - 1) { if (track_start <= target_stream - 1) {
track_hash = read_32bitBE(entry_offset + 0x08, sf); track_hash = read_32bitBE(entry_offset + 0x08, sf);
is_ram = (track_hash == 0xF1F1F1F1); is_ram = (track_hash == 0xF1F1F1F1);
@ -649,8 +652,6 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE* sf) {
goto fail; goto fail;
track_hash = read_32bitBE(entry_offset + 0x14, sf); track_hash = read_32bitBE(entry_offset + 0x14, sf);
if (track_hash == 0xF1F1F1F1)
continue; /* empty track */
} else { } else {
if (read_32bitBE(entry_offset + 0x0c, sf) == 0x00) if (read_32bitBE(entry_offset + 0x0c, sf) == 0x00)
goto fail; goto fail;

View file

@ -36,7 +36,7 @@ typedef struct {
static layered_layout_data* build_layered_fsb5_celt(STREAMFILE* sf, fsb5_header* fsb5); static layered_layout_data* build_layered_fsb5_celt(STREAMFILE* sf, fsb5_header* fsb5);
static layered_layout_data* build_layered_fsb5_atrac9(STREAMFILE* sf, fsb5_header* fsb5, off_t configs_offset, size_t configs_size); static layered_layout_data* build_layered_fsb5_atrac9(STREAMFILE* sf, fsb5_header* fsb5, off_t configs_offset, size_t configs_size);
/* FSB5 - FMOD Studio multiplatform format */ /* FSB5 - Firelight's FMOD Studio SoundBank format */
VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
fsb5_header fsb5 = {0}; fsb5_header fsb5 = {0};
@ -211,6 +211,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
/* found in some XMA2/Vorbis/FADPCM */ /* found in some XMA2/Vorbis/FADPCM */
VGM_LOG("FSB5: stream %i flag %x with value %08x\n", i, extraflag_type, read_32bitLE(extraflag_offset+0x04,sf)); VGM_LOG("FSB5: stream %i flag %x with value %08x\n", i, extraflag_type, read_32bitLE(extraflag_offset+0x04,sf));
break; break;
case 0x0e: /* number of layered Vorbis channels [Invisible, Inc. (Switch)] */
default: default:
VGM_LOG("FSB5: stream %i unknown flag 0x%x at %x + 0x04 (size 0x%x)\n", i, extraflag_type, (uint32_t)extraflag_offset, extraflag_size); VGM_LOG("FSB5: stream %i unknown flag 0x%x at %x + 0x04 (size 0x%x)\n", i, extraflag_type, (uint32_t)extraflag_offset, extraflag_size);
break; break;
@ -219,13 +220,19 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
extraflag_offset += 0x04 + extraflag_size; extraflag_offset += 0x04 + extraflag_size;
stream_header_size += 0x04 + extraflag_size; stream_header_size += 0x04 + extraflag_size;
} while (extraflag_end != 0x00); }
while (extraflag_end != 0x00);
} }
/* target found */ /* target found */
if (i + 1 == target_subsong) { if (i + 1 == target_subsong) {
fsb5.stream_offset = fsb5.base_header_size + fsb5.sample_header_size + fsb5.name_table_size + data_offset; fsb5.stream_offset = fsb5.base_header_size + fsb5.sample_header_size + fsb5.name_table_size + data_offset;
/* catch bad rips (like incorrectly split +1.5GB .fsb with wrong header+data) */
if (fsb5.stream_offset > get_streamfile_size(sf))
goto fail;
/* get stream size from next stream offset or full size if there is only one */ /* get stream size from next stream offset or full size if there is only one */
if (i + 1 == fsb5.total_subsongs) { if (i + 1 == fsb5.total_subsongs) {
fsb5.stream_size = fsb5.sample_data_size - data_offset; fsb5.stream_size = fsb5.sample_data_size - data_offset;

View file

@ -7,7 +7,7 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
STREAMFILE* temp_sf = NULL; STREAMFILE* temp_sf = NULL;
off_t subfile_offset, chunk_offset, bank_offset, offset; off_t subfile_offset, chunk_offset, bank_offset, offset;
size_t subfile_size, bank_size; size_t subfile_size, bank_size;
int is_old = 0; uint32_t version = 0;
/* checks */ /* checks */
@ -18,6 +18,7 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
goto fail; goto fail;
if (read_u32be(0x08,sf) != 0x46455620) /* "FEV " */ if (read_u32be(0x08,sf) != 0x46455620) /* "FEV " */
goto fail; goto fail;
version = read_u32le(0x14,sf); /* newer FEV have some kind of sub-version at 0x18 */
/* .fev is an event format referencing various external .fsb, but FMOD can bake .fev and .fsb to /* .fev is an event format referencing various external .fsb, but FMOD can bake .fev and .fsb to
* form a .bank, which is the format we support here (regular .fev is complex and not very interesting). * form a .bank, which is the format we support here (regular .fev is complex and not very interesting).
@ -42,15 +43,14 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
goto fail; goto fail;
switch(chunk_type) { switch(chunk_type) {
case 0x4C495354: /* "LIST" with "SNDH" (older) */ case 0x4C495354: /* "LIST" with "SNDH" (usually v0x28 but also in Fall Guys's BNK_Music_RoundReveal) */
if (read_u32be(offset + 0x04, sf) == 0x534E4448) { if (read_u32be(offset + 0x04, sf) == 0x534E4448) {
bank_offset = offset + 0x0c; bank_offset = offset + 0x0c;
bank_size = read_s32le(offset + 0x08,sf); bank_size = read_s32le(offset + 0x08,sf);
is_old = 1;
} }
break; break;
case 0x534E4448: /* "SNDH" (newer) */ case 0x534E4448: /* "SNDH" */
bank_offset = offset; bank_offset = offset;
bank_size = chunk_size; bank_size = chunk_size;
break; break;
@ -65,10 +65,18 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
if (bank_offset == 0) if (bank_offset == 0)
goto fail; goto fail;
/* 0x00: unknown (version? ex LE: 0x00080003, 0x00080005) */ /* 0x00: unknown (chunk version? ex LE: 0x00080003, 0x00080005) */
{ {
/* versions:
* 0x28: Transistor (iOS) [+2015]
* 0x50: Runic Rampage (PC), Forza 7 (PC), Shantae: Half Genie Hero (Switch) [+2017]
* 0x58: Mana Spark (PC), Shantae and the Seven Sirens (PC) [+2018]
* 0x63: Banner Saga 3 (PC) [+2018]
* 0x64: Guacamelee! Super Turbo Championship Edition (Switch) [+2018]
* 0x65: Carrion (Switch) [+2020]
* 0x7D: Fall Guys (PC) [+2020] */
size_t entry_size = version <= 0x28 ? 0x04 : 0x08;
int banks; int banks;
size_t entry_size = is_old ? 0x04 : 0x08;
/* multiple banks is possible but rare (only seen an extra "Silence" FSB5 in Guacamelee 2 (Switch), /* multiple banks is possible but rare (only seen an extra "Silence" FSB5 in Guacamelee 2 (Switch),
* which on PC is a regular subsong in the only FSB5) */ * which on PC is a regular subsong in the only FSB5) */
@ -88,7 +96,7 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
if (bank_subsongs != 1) goto fail; if (bank_subsongs != 1) goto fail;
} }
if (is_old) { if (version <= 0x28) {
subfile_offset = read_u32le(bank_offset+0x04,sf); subfile_offset = read_u32le(bank_offset+0x04,sf);
subfile_size = /* meh */ subfile_size = /* meh */
read_u32le(subfile_offset + 0x0C,sf) + read_u32le(subfile_offset + 0x0C,sf) +
@ -105,8 +113,14 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, "fsb"); temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, "fsb");
if (!temp_sf) goto fail; if (!temp_sf) goto fail;
if (read_u32be(0x00, temp_sf) == 0x46534235) {
vgmstream = init_vgmstream_fsb5(temp_sf); vgmstream = init_vgmstream_fsb5(temp_sf);
close_streamfile(temp_sf); close_streamfile(temp_sf);
}
else { //other flag?
vgmstream = init_vgmstream_fsb_encrypted(temp_sf);
close_streamfile(temp_sf);
}
return vgmstream; return vgmstream;

View file

@ -66,8 +66,7 @@ VGMSTREAM* init_vgmstream_fsb_encrypted(STREAMFILE* sf) {
vgmstream = init_vgmstream_fsb(temp_sf); vgmstream = init_vgmstream_fsb(temp_sf);
} }
if (vgmstream) //;if (vgmstream) dump_streamfile(temp_sf, 0);
dump_streamfile(temp_sf, 0);
close_streamfile(temp_sf); close_streamfile(temp_sf);
if (vgmstream) break; if (vgmstream) break;

View file

@ -13,22 +13,23 @@ typedef struct {
/* Encrypted FSB info from guessfsb and fsbext */ /* Encrypted FSB info from guessfsb and fsbext */
static size_t fsb_decryption_read(STREAMFILE* sf, uint8_t *dest, off_t offset, size_t length, fsb_decryption_data* data) { static size_t fsb_decryption_read(STREAMFILE* sf, uint8_t *dest, off_t offset, size_t length, fsb_decryption_data* data) {
static const unsigned char reverse_bits_table[] = { /* LUT to simplify, could use some bitswap function */ static const unsigned char reverse_bits_table[] = { /* LUT to simplify, could use some bitswap function */
0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, //00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, //00
0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, //10
0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, //20
0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, //30
0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, //40
0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, //50
0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, //60
0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, //70
0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, //80
0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, //90
0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, //A0
0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, //B0
0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, //C0
0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, //D0
0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, //E0
0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF //F0
}; };
size_t bytes_read; size_t bytes_read;
int i; int i;

View file

@ -78,6 +78,12 @@ static const uint8_t key_gh5[] = { 0xFC,0xF9,0xE4,0xB3,0xF5,0x57,0x5C,0xA5,0xAC,
/* Sekiro: Shadows Die Twice (PC) */ //"G0KTrWjS9syqF7vVD6RaVXlFD91gMgkC" /* Sekiro: Shadows Die Twice (PC) */ //"G0KTrWjS9syqF7vVD6RaVXlFD91gMgkC"
static const uint8_t key_sek[] = { 0x47,0x30,0x4B,0x54,0x72,0x57,0x6A,0x53,0x39,0x73,0x79,0x71,0x46,0x37,0x76,0x56,0x44,0x36,0x52,0x61,0x56,0x58,0x6C,0x46,0x44,0x39,0x31,0x67,0x4D,0x67,0x6B,0x43 }; static const uint8_t key_sek[] = { 0x47,0x30,0x4B,0x54,0x72,0x57,0x6A,0x53,0x39,0x73,0x79,0x71,0x46,0x37,0x76,0x56,0x44,0x36,0x52,0x61,0x56,0x58,0x6C,0x46,0x44,0x39,0x31,0x67,0x4D,0x67,0x6B,0x43 };
/* SCP: Unity (PC) */ //"BasicEncryptionKey"
static const uint8_t key_scp[] = { 0x42,0x61,0x73,0x69,0x63,0x45,0x6E,0x63,0x72,0x79,0x70,0x74,0x69,0x6F,0x6E,0x4B,0x65,0x79 };
/* Guitar Hero: Metallica (X360) */
static const uint8_t key_ghm[] = { 0x8C,0xFA,0xF3,0x14,0xB1,0x53,0xDA,0xAB,0x2B,0x82,0x6B,0xD5,0x55,0x16,0xCF,0x01,0x90,0x20,0x28,0x14,0xB1,0x53,0xD8 };
// Unknown: // Unknown:
// - Battle: Los Angeles // - Battle: Los Angeles
// - Guitar Hero: Warriors of Rock, DJ hero FSB // - Guitar Hero: Warriors of Rock, DJ hero FSB
@ -86,13 +92,13 @@ static const uint8_t key_sek[] = { 0x47,0x30,0x4B,0x54,0x72,0x57,0x6A,0x53,0x39,
static const fsbkey_info fsbkey_list[] = { static const fsbkey_info fsbkey_list[] = {
{ 0,0, sizeof(key_dj2),key_dj2 }, { 0,0, sizeof(key_dj2),key_dj2 },
{ 0,0, sizeof(key_dfp),key_dfp }, { 0,0, sizeof(key_dfp),key_dfp },//FSB4
{ 1,0, sizeof(key_dfp),key_dfp },//untested { 1,0, sizeof(key_dfp),key_dfp },//untested
{ 1,1, sizeof(key_dfp),key_dfp },//untested { 1,1, sizeof(key_dfp),key_dfp },//untested
{ 1,0, sizeof(key_npp),key_npp }, { 1,0, sizeof(key_npp),key_npp },//FSB5
{ 1,0, sizeof(key_sms),key_sms }, { 1,0, sizeof(key_sms),key_sms },//FSB5
{ 1,0, sizeof(key_gfs),key_gfs }, { 1,0, sizeof(key_gfs),key_gfs },//FSB5
{ 1,0, sizeof(key_rev),key_rev }, { 1,0, sizeof(key_rev),key_rev },//FSB5
{ 1,0, sizeof(key_ds3),key_ds3 },//untested { 1,0, sizeof(key_ds3),key_ds3 },//untested
{ 1,1, sizeof(key_ds3),key_ds3 }, { 1,1, sizeof(key_ds3),key_ds3 },
{ 1,0, sizeof(key_mkx),key_mkx },//untested { 1,0, sizeof(key_mkx),key_mkx },//untested
@ -141,6 +147,8 @@ static const fsbkey_info fsbkey_list[] = {
{ 0,1, sizeof(key_mtj),key_mtj },// FSB3 { 0,1, sizeof(key_mtj),key_mtj },// FSB3
{ 0,1, sizeof(key_gh5),key_gh5 },// FSB4 { 0,1, sizeof(key_gh5),key_gh5 },// FSB4
{ 1,0, sizeof(key_sek),key_sek },// FSB5 { 1,0, sizeof(key_sek),key_sek },// FSB5
{ 1,0, sizeof(key_scp),key_scp },// FSB5
{ 0,1, sizeof(key_ghm),key_ghm },// FSB4
}; };
static const int fsbkey_list_count = sizeof(fsbkey_list) / sizeof(fsbkey_list[0]); static const int fsbkey_list_count = sizeof(fsbkey_list) / sizeof(fsbkey_list[0]);

View file

@ -112,8 +112,7 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
} }
case 0x09: { /* XMA2 [Quantum Theory (PS3)] */ case 0x09: { /* XMA2 [Quantum Theory (PS3)] */
ffmpeg_codec_data *ffmpeg_data = NULL; uint8_t buf[0x100];
uint8_t buf[200];
int32_t bytes; int32_t bytes;
if (!find_chunk_be(streamHeader, 0x584D4558,first_offset,1, &chunk_offset,NULL)) /* "XMEX" */ if (!find_chunk_be(streamHeader, 0x584D4558,first_offset,1, &chunk_offset,NULL)) /* "XMEX" */
@ -122,9 +121,8 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
/* 0x34: seek table */ /* 0x34: seek table */
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, chunk_offset,0x34, data_size, streamHeader, 1); bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, chunk_offset,0x34, data_size, streamHeader, 1);
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size); vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
if ( !ffmpeg_data ) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;

View file

@ -10,69 +10,73 @@ static void find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t
/* CRI HCA - streamed audio from CRI ADX2/Atom middleware */ /* CRI HCA - streamed audio from CRI ADX2/Atom middleware */
VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile) { VGMSTREAM * init_vgmstream_hca(STREAMFILE* sf) {
return init_vgmstream_hca_subkey(streamFile, 0x0000); return init_vgmstream_hca_subkey(sf, 0x0000);
} }
VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE *streamFile, uint16_t subkey) { VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM * vgmstream = NULL;
hca_codec_data * hca_data = NULL; hca_codec_data* hca_data = NULL;
clHCA_stInfo* hca_info;
/* checks */ /* checks */
if ( !check_extensions(streamFile, "hca")) if (!check_extensions(sf, "hca"))
return NULL; return NULL;
if (((uint32_t)read_32bitBE(0x00,streamFile) & 0x7f7f7f7f) != 0x48434100) /* "HCA\0", possibly masked */
if ((read_u32be(0x00,sf) & 0x7F7F7F7F) != 0x48434100) /* "HCA\0", possibly masked */
goto fail; goto fail;
/* init vgmstream and library's context, will validate the HCA */ /* init vgmstream and library's context, will validate the HCA */
hca_data = init_hca(streamFile); hca_data = init_hca(sf);
if (!hca_data) goto fail; if (!hca_data) goto fail;
hca_info = hca_get_info(hca_data);
/* find decryption key in external file or preloaded list */ /* find decryption key in external file or preloaded list */
if (hca_data->info.encryptionEnabled) { if (hca_info->encryptionEnabled) {
uint64_t keycode = 0; uint64_t keycode = 0;
uint8_t keybuf[0x08+0x02]; uint8_t keybuf[0x08+0x02];
size_t keysize; size_t keysize;
keysize = read_key_file(keybuf, 0x08+0x04, streamFile); keysize = read_key_file(keybuf, 0x08+0x04, sf);
if (keysize == 0x08) { /* standard */ if (keysize == 0x08) { /* standard */
keycode = (uint64_t)get_64bitBE(keybuf+0x00); keycode = get_u64be(keybuf+0x00);
if (subkey) { if (subkey) {
keycode = keycode * ( ((uint64_t)subkey << 16u) | ((uint16_t)~subkey + 2u) ); keycode = keycode * ( ((uint64_t)subkey << 16u) | ((uint16_t)~subkey + 2u) );
} }
} }
else if (keysize == 0x08+0x02) { /* seed key + AWB subkey */ else if (keysize == 0x08+0x02) { /* seed key + AWB subkey */
uint64_t file_key = (uint64_t)get_64bitBE(keybuf+0x00); uint64_t file_key = get_u64be(keybuf+0x00);
uint16_t file_sub = (uint16_t)get_16bitBE(keybuf+0x08); uint16_t file_sub = get_u16be(keybuf+0x08);
keycode = file_key * ( ((uint64_t)file_sub << 16u) | ((uint16_t)~file_sub + 2u) ); keycode = file_key * ( ((uint64_t)file_sub << 16u) | ((uint16_t)~file_sub + 2u) );
} }
#ifdef HCA_BRUTEFORCE #ifdef HCA_BRUTEFORCE
else if (1) { else if (1) {
bruteforce_hca_key(streamFile, hca_data, &keycode, subkey); bruteforce_hca_key(sf, hca_data, &keycode, subkey);
} }
#endif #endif
else { else {
find_hca_key(hca_data, &keycode, subkey); find_hca_key(hca_data, &keycode, subkey);
} }
clHCA_SetKey(hca_data->handle, (unsigned long long)keycode); //maybe should be done through hca_decoder.c? hca_set_encryption_key(hca_data, keycode);
} }
/* build the VGMSTREAM */ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(hca_data->info.channelCount, hca_data->info.loopEnabled); vgmstream = allocate_vgmstream(hca_info->channelCount, hca_info->loopEnabled);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->meta_type = meta_HCA; vgmstream->meta_type = meta_HCA;
vgmstream->sample_rate = hca_data->info.samplingRate; vgmstream->sample_rate = hca_info->samplingRate;
vgmstream->num_samples = hca_data->info.blockCount * hca_data->info.samplesPerBlock - vgmstream->num_samples = hca_info->blockCount * hca_info->samplesPerBlock -
hca_data->info.encoderDelay - hca_data->info.encoderPadding; hca_info->encoderDelay - hca_info->encoderPadding;
vgmstream->loop_start_sample = hca_data->info.loopStartBlock * hca_data->info.samplesPerBlock - vgmstream->loop_start_sample = hca_info->loopStartBlock * hca_info->samplesPerBlock -
hca_data->info.encoderDelay + hca_data->info.loopStartDelay; hca_info->encoderDelay + hca_info->loopStartDelay;
vgmstream->loop_end_sample = hca_data->info.loopEndBlock * hca_data->info.samplesPerBlock - vgmstream->loop_end_sample = hca_info->loopEndBlock * hca_info->samplesPerBlock -
hca_data->info.encoderDelay + (hca_data->info.samplesPerBlock - hca_data->info.loopEndPadding); hca_info->encoderDelay + (hca_info->samplesPerBlock - hca_info->loopEndPadding);
/* After loop end CRI's encoder removes the rest of the original samples and puts some /* After loop end CRI's encoder removes the rest of the original samples and puts some
* garbage in the last frame that should be ignored. Optionally it can encode fully preserving * garbage in the last frame that should be ignored. Optionally it can encode fully preserving
* the file too, but it isn't detectable, so we'll allow the whole thing just in case */ * the file too, but it isn't detectable, so we'll allow the whole thing just in case */
@ -80,10 +84,10 @@ VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE *streamFile, uint16_t subkey) {
// vgmstream->num_samples = vgmstream->loop_end_sample; // vgmstream->num_samples = vgmstream->loop_end_sample;
/* this can happen in preloading HCA from memory AWB */ /* this can happen in preloading HCA from memory AWB */
if (hca_data->info.blockCount * hca_data->info.blockSize > get_streamfile_size(streamFile)) { if (hca_info->blockCount * hca_info->blockSize > get_streamfile_size(sf)) {
unsigned int max_block = get_streamfile_size(streamFile) / hca_data->info.blockSize; unsigned int max_block = get_streamfile_size(sf) / hca_info->blockSize;
vgmstream->num_samples = max_block * hca_data->info.samplesPerBlock - vgmstream->num_samples = max_block * hca_info->samplesPerBlock -
hca_data->info.encoderDelay - hca_data->info.encoderPadding; hca_info->encoderDelay - hca_info->encoderPadding;
} }
vgmstream->coding_type = coding_CRI_HCA; vgmstream->coding_type = coding_CRI_HCA;
@ -115,7 +119,7 @@ fail:
} }
static inline void test_key(hca_codec_data * hca_data, uint64_t key, uint16_t subkey, int *best_score, uint64_t *best_keycode) { static inline void test_key(hca_codec_data* hca_data, uint64_t key, uint16_t subkey, int* best_score, uint64_t* best_keycode) {
int score; int score;
if (subkey) { if (subkey) {
@ -179,7 +183,7 @@ static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigne
uint8_t* buf = NULL; uint8_t* buf = NULL;
int best_score = -1; int best_score = -1;
off_t keys_size, bytes; off_t keys_size, bytes;
int i, pos; int pos;
VGM_LOG("HCA: test keys\n"); VGM_LOG("HCA: test keys\n");
@ -207,17 +211,20 @@ static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigne
//key = ((uint64_t)get_u32le(buf + pos + 0x00) << 32) | ((uint64_t)get_u32le(buf + pos + 0x04) << 0); //key = ((uint64_t)get_u32le(buf + pos + 0x00) << 32) | ((uint64_t)get_u32le(buf + pos + 0x04) << 0);
//key = ((uint64_t)get_u32be(buf + pos + 0x00) << 0 ) | ((uint64_t)get_u32be(buf + pos + 0x04) << 32); //key = ((uint64_t)get_u32be(buf + pos + 0x00) << 0 ) | ((uint64_t)get_u32be(buf + pos + 0x04) << 32);
//key = ((uint64_t)get_u32be(buf + pos + 0x00) << 32) | ((uint64_t)get_u32be(buf + pos + 0x04) << 0); //key = ((uint64_t)get_u32be(buf + pos + 0x00) << 32) | ((uint64_t)get_u32be(buf + pos + 0x04) << 0);
//key = ((uint64_t)get_u32le(buf + pos + 0x00) << 0 ) | 0; /* upper bytes not set, ex. P5 */
//key = ((uint64_t)get_u32be(buf + pos + 0x00) << 0 ) | 0; /* upper bytes not set, ex. P5 */
if (key == 0) if (key == 0)
continue; continue;
test_key(hca_data, keys[i], subkey, &best_score, out_keycode); test_key(hca_data, key, subkey, &best_score, out_keycode);
if (best_score == 1) if (best_score == 1)
goto done; goto done;
VGM_ASSERT(pos % 0x100000 == 0, "HCA: pos %x...\n", pos); VGM_ASSERT(pos % 0x100000 == 0, "HCA: pos %x...\n", pos);
/* observed files have aligned keys in the .text section, change if needed */ /* observed files have aligned keys in the .text section, change if needed */
pos += 0x04; //pos++; pos += 0x04;
//pos++;
} }
done: done:

View file

@ -26,7 +26,7 @@ static const hcakey_info hcakey_list[] = {
// Phantasy Star Online 2 (multi?) // Phantasy Star Online 2 (multi?)
// used by most console games // used by most console games
{0xCC55463930DBE1AB}, // CC55463930DBE1AB / 14723751768204501419 {14723751768204501419u}, // CC55463930DBE1AB
// Old Phantasy Star Online 2 (multi?) // Old Phantasy Star Online 2 (multi?)
{61891147883431481}, // 30DBE1ABCC554639 {61891147883431481}, // 30DBE1ABCC554639
@ -103,7 +103,7 @@ static const hcakey_info hcakey_list[] = {
{8910}, // 00000000000022CE {8910}, // 00000000000022CE
// Tokyo 7th Sisters (iOS/Android) *unconfirmed // Tokyo 7th Sisters (iOS/Android) *unconfirmed
{0xFDAE531AAB414BA1}, // FDAE531AAB414BA1 {18279639311550860193u}, // FDAE531AAB414BA1
// One Piece Dance Battle (iOS/Android) // One Piece Dance Battle (iOS/Android)
{1905818}, // 00000000001D149A {1905818}, // 00000000001D149A
@ -118,7 +118,7 @@ static const hcakey_info hcakey_list[] = {
{4867249871962584729}, // 438BF1F883653699 {4867249871962584729}, // 438BF1F883653699
// Tekken Mobile (iOS/Android) // Tekken Mobile (iOS/Android)
{0xFFFFFFFFFFFFFFFF}, // FFFFFFFFFFFFFFFF / 18446744073709551615 {18446744073709551615u}, // FFFFFFFFFFFFFFFF
// Tales of the Rays (iOS/Android) // Tales of the Rays (iOS/Android)
{9516284}, // 00000000009134FC {9516284}, // 00000000009134FC
@ -136,7 +136,7 @@ static const hcakey_info hcakey_list[] = {
{1224}, // 00000000000004C8 {1224}, // 00000000000004C8
// Schoolgirl Strikers ~Twinkle Melodies~ (iOS/Android) // Schoolgirl Strikers ~Twinkle Melodies~ (iOS/Android)
{0xDB5B61B8343D0000}, // DB5B61B8343D0000 {15806334760965177344u}, // DB5B61B8343D0000
// Bad Apple Wars (PSVita) // Bad Apple Wars (PSVita)
{241352432}, // 000000000E62BEF0 {241352432}, // 000000000E62BEF0
@ -163,7 +163,7 @@ static const hcakey_info hcakey_list[] = {
{11708691}, // 0000000000B2A913 {11708691}, // 0000000000B2A913
// Monster Gear Versus (iOS/Android) // Monster Gear Versus (iOS/Android)
{0xB1E30F346415B475}, // B1E30F346415B475 {12818105682118423669u}, // B1E30F346415B475
// Yumeiro Cast (iOS/Android) // Yumeiro Cast (iOS/Android)
{14418}, // 0000000000003852 {14418}, // 0000000000003852
@ -172,13 +172,13 @@ static const hcakey_info hcakey_list[] = {
{1000}, // 00000000000003E8 {1000}, // 00000000000003E8
// Zero kara Hajimeru Mahou no Sho (iOS/Android) // Zero kara Hajimeru Mahou no Sho (iOS/Android)
{0xD2E836E662F20000}, // D2E836E662F20000 {15197457305692143616u}, // D2E836E662F20000
// Soul Reverse Zero (iOS/Android) // Soul Reverse Zero (iOS/Android)
{2873513618}, // 00000000AB465692 {2873513618}, // 00000000AB465692
// Jojo's Bizarre Adventure: Diamond Records (iOS/Android) [additional data] // Jojo's Bizarre Adventure: Diamond Records (iOS/Android) [additional data]
{0x820212864CAB35DE}, // 820212864CAB35DE {9368070542905259486u}, // 820212864CAB35DE
// HUNTER x HUNTER: World Hunt (iOS/Android) // HUNTER x HUNTER: World Hunt (iOS/Android)
{71777214294589695}, // 00FF00FF00FF00FF {71777214294589695}, // 00FF00FF00FF00FF
@ -317,7 +317,7 @@ static const hcakey_info hcakey_list[] = {
{3957325206121219506}, // 36EB3E4EE38E05B2 {3957325206121219506}, // 36EB3E4EE38E05B2
/* Idola: Phantasy Star Saga (Android) */ /* Idola: Phantasy Star Saga (Android) */
{0xA86BF72B4C852CA7}, // A86BF72B4C852CA7 / 12136065386219383975 {12136065386219383975u}, // A86BF72B4C852CA7
/* Arca Last (Android) */ /* Arca Last (Android) */
{612310807}, // 00000000247F1F17 {612310807}, // 00000000247F1F17
@ -329,7 +329,7 @@ static const hcakey_info hcakey_list[] = {
{3315495188}, // 00000000C59E7114 {3315495188}, // 00000000C59E7114
/* Inazuma Eleven SD (Android) */ /* Inazuma Eleven SD (Android) */
{0xC436E03737D55B5F}, // C436E03737D55B5F / 14138734607940803423 {14138734607940803423u}, // C436E03737D55B5F
/* Detective Conan Runner / Case Closed Runner (Android) */ /* Detective Conan Runner / Case Closed Runner (Android) */
{1175268187653273344}, // 104f643098e3f700 {1175268187653273344}, // 104f643098e3f700
@ -340,6 +340,39 @@ static const hcakey_info hcakey_list[] = {
/* 22/7 Ongaku no Jikan (Android) */ /* 22/7 Ongaku no Jikan (Android) */
{20190906}, // 00000000013416BA {20190906}, // 00000000013416BA
/* Cardcaptor Sakura: Happiness Memories (Android) */
{625144437747651}, // 00023890C8252FC3
/* Digimon Story: Cyber Sleuth (PC) */
{2897314143465725881}, // 283553DCE3FD5FB9
/* Alice Re:Code (Android) */
{9422596198430275382u}, // 82C3C951C561F736
/* Tokyo 7th Sisters (Android) */
{18279639311550860193u}, // FDAE531AAB414BA1
/* High School Fleet: Kantai Battle de Pinch! (Mobile) */
{43472919336422565}, // 009A7263CA658CA5
/* Disney's Twisted Wonderland (Android) */
{2895000877}, // 00000000AC8E352D
/* B-PROJECT Kaikan Everyday (Android) */
{12316546176516217334u}, // AAED297DDEF1D9F6
/* HELIOS Rising Heroes (Android) */
{311981570940334162}, // 04546195F85DF052
/* World Ends's Club (iOS) */
{50979632184989243}, // 00B51DB4932A963B
/* Kandagawa Jet Girls (PC) */
{6235253715273671}, // 001626EE22C887C7
/* Re:Zero - Lost in Memories (Android) */
{1611432018519751642}, // 165CF4E2138F7BDA
/* Dragalia Lost (iOS/Android) */ /* Dragalia Lost (iOS/Android) */
{2967411924141, subkeys_dgl, sizeof(subkeys_dgl) / sizeof(subkeys_dgl[0]) }, // 000002B2E7889CAD {2967411924141, subkeys_dgl, sizeof(subkeys_dgl) / sizeof(subkeys_dgl[0]) }, // 000002B2E7889CAD

View file

@ -1,6 +1,6 @@
#include "meta.h" #include "meta.h"
#include "../layout/layout.h" #include "../layout/layout.h"
#include "../util.h" #include "../coding/coding.h"
typedef struct { typedef struct {
int is_music; int is_music;
@ -18,24 +18,25 @@ typedef struct {
off_t stream_offset; off_t stream_offset;
size_t stream_size; size_t stream_size;
int big_endian;
} ivaud_header; } ivaud_header;
static int parse_ivaud_header(STREAMFILE* streamFile, ivaud_header* ivaud); static int parse_ivaud_header(STREAMFILE* sf, ivaud_header* ivaud);
/* .ivaud - from GTA IV (PC) */ /* .ivaud - from GTA IV (PC/PS3/X360) */
VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_ivaud(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
ivaud_header ivaud = {0}; ivaud_header ivaud = {0};
int loop_flag; int loop_flag;
/* checks */ /* checks */
/* (hashed filenames are likely extensionless and .ivaud is added by tools) */ /* (hashed filenames are likely extensionless and .ivaud is added by tools) */
if (!check_extensions(streamFile, "ivaud,")) if (!check_extensions(sf, "ivaud,"))
goto fail; goto fail;
/* check header */ /* check header */
if (!parse_ivaud_header(streamFile, &ivaud)) if (!parse_ivaud_header(sf, &ivaud))
goto fail; goto fail;
@ -59,7 +60,48 @@ VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) {
vgmstream->full_block_size = ivaud.block_size; vgmstream->full_block_size = ivaud.block_size;
break; break;
case 0x0400: #ifdef VGM_USE_FFMPEG
case 0x0000: { /* XMA2 (X360) */
uint8_t buf[0x100];
size_t bytes;
if (ivaud.is_music) {
goto fail;
}
else {
/* regular XMA for sfx */
bytes = ffmpeg_make_riff_xma1(buf, 0x100, ivaud.num_samples, ivaud.stream_size, ivaud.channel_count, ivaud.sample_rate, 0);
vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, ivaud.stream_offset, ivaud.stream_size);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
xma_fix_raw_samples(vgmstream, sf, ivaud.stream_offset, ivaud.stream_size, 0, 0,0); /* samples are ok? */
}
break;
}
#endif
#ifdef VGM_USE_MPEG
case 0x0100: { /* MPEG (PS3) */
mpeg_custom_config cfg = {0};
if (ivaud.is_music) {
goto fail;
}
else {
cfg.chunk_size = ivaud.block_size;
cfg.big_endian = ivaud.big_endian;
vgmstream->codec_data = init_mpeg_custom(sf, ivaud.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_STANDARD, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
}
break;
}
#endif
case 0x0400: /* PC */
vgmstream->coding_type = coding_IMA_int; vgmstream->coding_type = coding_IMA_int;
vgmstream->layout_type = ivaud.is_music ? layout_blocked_ivaud : layout_none; vgmstream->layout_type = ivaud.is_music ? layout_blocked_ivaud : layout_none;
vgmstream->full_block_size = ivaud.block_size; vgmstream->full_block_size = ivaud.block_size;
@ -71,7 +113,7 @@ VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) {
} }
if (!vgmstream_open_stream(vgmstream,streamFile,ivaud.stream_offset)) if (!vgmstream_open_stream(vgmstream,sf,ivaud.stream_offset))
goto fail; goto fail;
return vgmstream; return vgmstream;
@ -81,28 +123,37 @@ fail:
} }
/* Parse Rockstar's .ivaud header (much info from SparkIV). */ /* Parse Rockstar's .ivaud header (much info from SparkIV). */
static int parse_ivaud_header(STREAMFILE* streamFile, ivaud_header* ivaud) { static int parse_ivaud_header(STREAMFILE* sf, ivaud_header* ivaud) {
int target_subsong = streamFile->stream_index; int target_subsong = sf->stream_index;
uint64_t (*read_u64)(off_t,STREAMFILE*);
uint32_t (*read_u32)(off_t,STREAMFILE*);
uint16_t (*read_u16)(off_t,STREAMFILE*);
ivaud->big_endian = read_u32be(0x00, sf) == 0; /* table offset at 0x04 > BE (64b) */
read_u64 = ivaud->big_endian ? read_u64be : read_u64le;
read_u32 = ivaud->big_endian ? read_u32be : read_u32le;
read_u16 = ivaud->big_endian ? read_u16be : read_u16le;
/* use bank's stream count to detect */ /* use bank's stream count to detect */
ivaud->is_music = (read_32bitLE(0x10,streamFile) == 0); ivaud->is_music = (read_u32(0x10,sf) == 0);
if (ivaud->is_music) { if (ivaud->is_music) {
off_t block_table_offset, channel_table_offset, channel_info_offset; off_t block_table_offset, channel_table_offset, channel_info_offset;
/* music header */ /* music header */
block_table_offset = read_32bitLE(0x00,streamFile); /* 64b */ block_table_offset = read_u64(0x00,sf);
ivaud->block_count = read_32bitLE(0x08,streamFile); ivaud->block_count = read_u32(0x08,sf);
ivaud->block_size = read_32bitLE(0x0c,streamFile); /* 64b, uses padded blocks */ ivaud->block_size = read_u32(0x0c,sf); /* uses padded blocks */
channel_table_offset = read_32bitLE(0x14,streamFile); /* 64b */ /* 0x10(4): stream count */
channel_table_offset = read_u64(0x14,sf);
/* 0x1c(8): block_table_offset again? */ /* 0x1c(8): block_table_offset again? */
ivaud->channel_count = read_32bitLE(0x24,streamFile); ivaud->channel_count = read_u32(0x24,sf);
/* 0x28(4): unknown entries? */ /* 0x28(4): unknown entries? */
ivaud->stream_offset = read_32bitLE(0x2c,streamFile); ivaud->stream_offset = read_u32(0x2c,sf);
channel_info_offset = channel_table_offset + ivaud->channel_count*0x10; channel_info_offset = channel_table_offset + ivaud->channel_count * 0x10;
if ((ivaud->block_count * ivaud->block_size) + ivaud->stream_offset != get_streamfile_size(streamFile)) { if ((ivaud->block_count * ivaud->block_size) + ivaud->stream_offset != get_streamfile_size(sf)) {
VGM_LOG("IVAUD: bad file size\n"); VGM_LOG("IVAUD: bad file size\n");
goto fail; goto fail;
} }
@ -116,33 +167,33 @@ static int parse_ivaud_header(STREAMFILE* streamFile, ivaud_header* ivaud) {
/* 0x00(8): offset within data (should be 0) */ /* 0x00(8): offset within data (should be 0) */
/* 0x08(4): hash */ /* 0x08(4): hash */
/* 0x0c(4): half num_samples? */ /* 0x0c(4): half num_samples? */
ivaud->num_samples = read_32bitLE(channel_info_offset+0x10,streamFile); ivaud->num_samples = read_u32(channel_info_offset+0x10,sf);
/* 0x14(4): unknown (-1) */ /* 0x14(4): unknown (-1) */
/* 0x18(2): sample rate */ /* 0x18(2): sample rate */
/* 0x1a(2): unknown */ /* 0x1a(2): unknown */
ivaud->codec = read_32bitLE(channel_info_offset+0x1c,streamFile); ivaud->codec = read_u32(channel_info_offset+0x1c,sf);
/* (when codec is IMA) */ /* (when codec is IMA) */
/* 0x20(8): adpcm states offset, 0x38: num states? (reference for seeks?) */ /* 0x20(8): adpcm states offset, 0x38: num states? (reference for seeks?) */
/* rest: unknown data */ /* rest: unknown data */
/* block table (one entry per block) */ /* block table (one entry per block) */
/* 0x00: data size processed up to this block (doesn't count block padding) */ /* 0x00: data size processed up to this block (doesn't count block padding) */
ivaud->sample_rate = read_32bitLE(block_table_offset + 0x04,streamFile); ivaud->sample_rate = read_u32(block_table_offset + 0x04,sf);
/* sample_rate should agree with each channel in the channel table */ /* sample_rate should agree with each channel in the channel table */
ivaud->total_subsongs = 1; ivaud->total_subsongs = 1;
ivaud->stream_size = get_streamfile_size(streamFile); ivaud->stream_size = get_streamfile_size(sf);
} }
else { else {
off_t stream_table_offset, stream_info_offset, stream_entry_offset; off_t stream_table_offset, stream_info_offset, stream_entry_offset, offset;
/* bank header */ /* bank header */
stream_table_offset = read_32bitLE(0x00,streamFile); /* 64b */ stream_table_offset = read_u64(0x00,sf);
/* 0x08(8): header size? start offset? */ /* 0x08(8): header size? start offset? */
ivaud->total_subsongs = read_32bitLE(0x10,streamFile); ivaud->total_subsongs = read_u32(0x10,sf);
/* 0x14(4): unknown */ /* 0x14(4): unknown */
ivaud->stream_offset = read_32bitLE(0x18,streamFile); /* base start_offset */ ivaud->stream_offset = read_u32(0x18,sf); /* base start_offset */
if (target_subsong == 0) target_subsong = 1; if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > ivaud->total_subsongs || ivaud->total_subsongs < 1) goto fail; if (target_subsong < 0 || target_subsong > ivaud->total_subsongs || ivaud->total_subsongs < 1) goto fail;
@ -152,37 +203,26 @@ static int parse_ivaud_header(STREAMFILE* streamFile, ivaud_header* ivaud) {
stream_info_offset = stream_table_offset + 0x10*ivaud->total_subsongs; stream_info_offset = stream_table_offset + 0x10*ivaud->total_subsongs;
/* stream table (one entry per stream, points to stream info) */ /* stream table (one entry per stream, points to stream info) */
stream_entry_offset = read_32bitLE(stream_table_offset + 0x10*(target_subsong-1) + 0x00,streamFile); /* within stream info */ stream_entry_offset = read_u64(stream_table_offset + 0x10*(target_subsong-1) + 0x00,sf); /* within stream info */
/* 0x00(8): offset within stream_info_offset */ /* 0x00(8): offset within stream_info_offset */
/* 0x08(4): hash */ /* 0x08(4): hash */
/* 0x0c(4): size */ /* 0x0c(4): some offset/size */
/* stream info (one entry per stream) */ /* stream info (one entry per stream) */
ivaud->stream_offset += read_32bitLE(stream_info_offset+stream_entry_offset+0x00,streamFile); /* 64b, within data */ offset = stream_info_offset + stream_entry_offset;
ivaud->stream_offset += read_u64(offset+0x00,sf); /* within data */
/* 0x08(4): hash */ /* 0x08(4): hash */
/* 0x0c(4): half num_samples? */ ivaud->stream_size = read_u32(offset+0x0c,sf);
ivaud->num_samples = read_32bitLE(stream_info_offset+stream_entry_offset+0x10,streamFile); ivaud->num_samples = read_u32(offset+0x10,sf);
/* 0x14(4): unknown (-1) */ /* 0x14(4): unknown (-1) */
ivaud->sample_rate = (uint16_t)read_16bitLE(stream_info_offset+stream_entry_offset+0x18,streamFile); ivaud->sample_rate = read_u16(offset+0x18,sf);
/* 0x1a(2): unknown */ /* 0x1a(2): unknown */
ivaud->codec = read_32bitLE(stream_info_offset+stream_entry_offset+0x1c,streamFile); ivaud->codec = read_u32(offset+0x1c,sf);
/* (when codec is IMA) */ /* (when codec is IMA) */
/* 0x20(8): adpcm states offset, 0x38: num states? (reference for seeks?) */ /* 0x20(8): adpcm states offset, 0x38: num states? (reference for seeks?) */
/* rest: unknown data */ /* rest: unknown data */
ivaud->channel_count = 1; ivaud->channel_count = 1;
/* ghetto size calculator (could substract offsets but streams are not ordered) */
switch(ivaud->codec) {
case 0x0001:
ivaud->stream_size = ivaud->num_samples * 2; /* double 16b PCM */
break;
case 0x0400:
ivaud->stream_size = ivaud->num_samples / 2; /* half nibbles */
break;
default:
break;
}
} }

View file

@ -0,0 +1,60 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
/* KTSC - Koei Tecmo KTSR container */
VGMSTREAM* init_vgmstream_ktsc(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE *temp_sf = NULL;
int target_subsong = sf->stream_index, total_subsongs;
off_t offset, subfile_offset;
size_t subfile_size;
/* checks */
/* .ktsl2asbin: common [Atelier Ryza (PC)] */
if (!check_extensions(sf, "ktsl2asbin"))
goto fail;
/* KTSC is a container of KTSRs, but can't be extracted easily as they use absolute pointers to the
* same stream companion file. KTSRs may have subsongs, but only seem to have 1, so use KTSC's subsongs. */
if (read_u32be(0x00, sf) != 0x4B545343) /* "KTSC" */
goto fail;
if (read_u32be(0x04, sf) != 0x01000001) /* version? */
goto fail;
if (target_subsong == 0) target_subsong = 1;
total_subsongs = read_u32le(0x08, sf);
if (target_subsong > total_subsongs)
goto fail;
/* 0x0c: CRC(?) table start */
offset = read_u32le(0x10, sf);
/* 0x14: file size */
/* 0x18: header end */
/* 0x1c: null */
/* 0x20+: CRC(?) table, 1 entry per file */
subfile_offset = read_u32le(offset + 0x04 * (target_subsong - 1), sf);
subfile_size = read_u32le(subfile_offset + 0x1c, sf); /* from header, meh */
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, NULL);
if (!temp_sf) goto fail;
temp_sf->stream_index = 1;
vgmstream = init_vgmstream_ktsr(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

@ -124,29 +124,6 @@ VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) {
vgmstream->layout_type = layout_layered; vgmstream->layout_type = layout_layered;
vgmstream->coding_type = coding_ATRAC9; vgmstream->coding_type = coding_ATRAC9;
break; break;
#if 0
atrac9_config cfg = {0};
if (ktsr.channels > 1) {
VGM_LOG("1\n");
goto fail;
}
/* 0x00: samples per frame */
/* 0x02: frame size */
cfg.config_data = read_u32be(ktsr.extra_offset + 0x04, sf_b);
if ((cfg.config_data & 0xFF) == 0xFE) /* later versions(?) in LE */
cfg.config_data = read_u32le(ktsr.extra_offset + 0x04, sf_b);
cfg.channels = vgmstream->channels;
cfg.encoder_delay = 256; /* observed default (ex. Attack on Titan PC vs Vita) */
vgmstream->codec_data = init_atrac9(&cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_ATRAC9;
vgmstream->layout_type = layout_none;
break;
#endif
} }
#endif #endif
@ -312,6 +289,8 @@ static int parse_ktsr_subfile(ktsr_header* ktsr, STREAMFILE* sf, off_t offset) {
switch(type) { /* hash-id? */ switch(type) { /* hash-id? */
case 0x38D0437D: /* external [Nioh (PC), Atelier Ryza (PC)] */ case 0x38D0437D: /* external [Nioh (PC), Atelier Ryza (PC)] */
case 0xDF92529F: /* external [Atelier Ryza (PC)] */
case 0x6422007C: /* external [Atelier Ryza (PC)] */
/* 08 subtype? (ex. 0x522B86B9) /* 08 subtype? (ex. 0x522B86B9)
* 0c channels * 0c channels
* 10 ? (always 0x002706B8) * 10 ? (always 0x002706B8)
@ -465,7 +444,6 @@ static void parse_longname(ktsr_header* ktsr, STREAMFILE* sf, uint32_t target_id
offset += size; offset += size;
} }
} }
static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) { static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) {
@ -503,6 +481,7 @@ static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) {
case 0x6172DBA8: /* padding (empty) */ case 0x6172DBA8: /* padding (empty) */
case 0xBD888C36: /* config (floats, stream id, etc, may have extended name) */ case 0xBD888C36: /* config (floats, stream id, etc, may have extended name) */
case 0xC9C48EC1: /* unknown (has some string inside like "boss") */ case 0xC9C48EC1: /* unknown (has some string inside like "boss") */
case 0xA9D23BF1: /* "state container", some kind of config/floats, witgh names like 'State_bgm01'..N */
break; break;
case 0xC5CCCB70: /* sound (internal data or external stream) */ case 0xC5CCCB70: /* sound (internal data or external stream) */

View file

@ -3,6 +3,9 @@
#include "../vgmstream.h" #include "../vgmstream.h"
VGMSTREAM* init_vgmstream_silence(int channels, int sample_rate, int32_t num_samples);
VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_afc(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_afc(STREAMFILE *streamFile);
@ -76,7 +79,7 @@ VGMSTREAM * init_vgmstream_raw_int(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ps2_exst(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ps2_exst(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ps2_svag(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_svag_kcet(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile);
@ -565,7 +568,7 @@ VGMSTREAM * init_vgmstream_mca(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_btsnd(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_btsnd(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_svag_snk(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_svag_snk(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_xma(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_xma(STREAMFILE* streamFile);
@ -907,4 +910,14 @@ VGMSTREAM* init_vgmstream_kat(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_pcm_success(STREAMFILE* sf); VGMSTREAM* init_vgmstream_pcm_success(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ktsc(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_adp_konami(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_zwv(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_dsb(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_bsf(STREAMFILE* sf);
#endif /*_META_H*/ #endif /*_META_H*/

View file

@ -128,17 +128,15 @@ VGMSTREAM * init_vgmstream_msf(STREAMFILE *streamFile) {
#endif #endif
#if defined(VGM_USE_MPEG) #if defined(VGM_USE_MPEG)
case 0x07: { /* MPEG (CBR LAME MP3) [Dengeki Bunko Fighting Climax (PS3)] */ case 0x07: { /* MPEG (CBR LAME MP3) [Dengeki Bunko Fighting Climax (PS3)] */
mpeg_codec_data *mpeg_data = NULL;
mpeg_data = init_mpeg(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels); vgmstream->codec_data = init_mpeg(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels);
if (!mpeg_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->codec_data = mpeg_data;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
vgmstream->num_samples = mpeg_bytes_to_samples(data_size, mpeg_data); vgmstream->num_samples = mpeg_bytes_to_samples(data_size, vgmstream->codec_data);
if (loop_flag) { if (loop_flag) {
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data); vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, vgmstream->codec_data);
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data); vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, vgmstream->codec_data);
/* loops are always aligned to CBR frame beginnings */ /* loops are always aligned to CBR frame beginnings */
} }

View file

@ -3,15 +3,15 @@
#include "../coding/coding.h" #include "../coding/coding.h"
#include "mul_streamfile.h" #include "mul_streamfile.h"
typedef enum { PSX, DSP, XBOX, XMA1 } mul_codec; typedef enum { PSX, DSP, IMA, XMA1, FSB4 } mul_codec;
static int guess_codec(STREAMFILE* sf, int big_endian, int channels, mul_codec* p_codec, off_t* p_extra_offset); static off_t get_start_offset(STREAMFILE* sf);
static int guess_codec(STREAMFILE* sf, off_t start_offset, int big_endian, int channels, mul_codec* p_codec, off_t* p_extra_offset);
static layered_layout_data* build_layered_mul(STREAMFILE *sf_data, int big_endian, VGMSTREAM* vgmstream); static layered_layout_data* build_layered_mul(STREAMFILE* sf, off_t offset, int big_endian, VGMSTREAM* vgmstream, mul_codec codec);
/* .MUL - from Crystal Dynamics games [Legacy of Kain: Defiance (PS2), Tomb Raider Underworld (multi)] */ /* .MUL - from Crystal Dynamics games [Legacy of Kain: Defiance (PS2), Tomb Raider Underworld (multi)] */
VGMSTREAM * init_vgmstream_mul(STREAMFILE *sf) { VGMSTREAM* init_vgmstream_mul(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
off_t start_offset, coefs_offset = 0; off_t start_offset, coefs_offset = 0;
int loop_flag, channel_count, sample_rate, num_samples, loop_start; int loop_flag, channel_count, sample_rate, num_samples, loop_start;
int big_endian; int big_endian;
@ -48,21 +48,24 @@ VGMSTREAM * init_vgmstream_mul(STREAMFILE *sf) {
/* 0x34: id? */ /* 0x34: id? */
/* 0x38+: channel config until ~0x100? (multiple 0x3F800000 / 1.0f depending on the number of channels) */ /* 0x38+: channel config until ~0x100? (multiple 0x3F800000 / 1.0f depending on the number of channels) */
/* test known versions (later versions start from 0x24 instead of 0x20) */ /* test known "version" (some float) later versions start from 0x24 instead of 0x20 */
if (!(read_u32(0x38,sf) == 0x3F800000 || if (!(read_u32(0x38,sf) == 0x3F800000 || /* common */
read_u32(0x38,sf) == 0x4530F000 || /* Avengers */
read_u32(0x3c,sf) == 0x3F800000)) /* Tomb Raider Underworld */ read_u32(0x3c,sf) == 0x3F800000)) /* Tomb Raider Underworld */
goto fail; goto fail;
loop_flag = (loop_start >= 0); /* 0xFFFFFFFF when not looping */ loop_flag = (loop_start >= 0); /* 0xFFFFFFFF when not looping */
start_offset = 0x800;
start_offset = get_start_offset(sf);
if (!start_offset) goto fail;
/* format is pretty limited so we need to guess codec */ /* format is pretty limited so we need to guess codec */
if (!guess_codec(sf, big_endian, channel_count, &codec, &coefs_offset)) if (!guess_codec(sf, start_offset, big_endian, channel_count, &codec, &coefs_offset))
goto fail; goto fail;
/* build the VGMSTREAM */ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag); vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->meta_type = meta_MUL; vgmstream->meta_type = meta_MUL;
@ -86,21 +89,18 @@ VGMSTREAM * init_vgmstream_mul(STREAMFILE *sf) {
dsp_read_hist_be (vgmstream,sf,coefs_offset+0x24,0x2e); dsp_read_hist_be (vgmstream,sf,coefs_offset+0x24,0x2e);
break; break;
case XBOX: case IMA:
vgmstream->coding_type = coding_XBOX_IMA_int; vgmstream->coding_type = coding_CD_IMA;
vgmstream->layout_type = layout_blocked_mul; vgmstream->layout_type = layout_blocked_mul;
break; break;
#ifdef VGM_USE_FFMPEG case XMA1:
case XMA1: { case FSB4:
vgmstream->layout_data = build_layered_mul(sf, start_offset, big_endian, vgmstream, codec);
vgmstream->layout_data = build_layered_mul(sf, big_endian, vgmstream);
if (!vgmstream->layout_data) goto fail; if (!vgmstream->layout_data) goto fail;
vgmstream->coding_type = coding_FFmpeg; //vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_layered; vgmstream->layout_type = layout_layered;
break; break;
}
#endif
default: default:
goto fail; goto fail;
@ -115,7 +115,19 @@ fail:
return NULL; return NULL;
} }
static int guess_codec(STREAMFILE* sf, int big_endian, int channels, mul_codec* p_codec, off_t* p_extra_offset) { static off_t get_start_offset(STREAMFILE* sf) {
/* find first block with header info */
if (read_u32be(0x0800,sf) != 0 || read_u32be(0x0804,sf) != 0) /* earlier games */
return 0x800;
if (read_u32be(0x2000,sf) != 0 || read_u32be(0x2004,sf) != 0) /* later games */
return 0x2000;
return 0;
}
static int guess_codec(STREAMFILE* sf, off_t start_offset, int big_endian, int channels, mul_codec* p_codec, off_t* p_extra_offset) {
uint32_t (*read_u32)(off_t,STREAMFILE*); uint32_t (*read_u32)(off_t,STREAMFILE*);
read_u32 = big_endian ? read_u32be : read_u32le; read_u32 = big_endian ? read_u32be : read_u32le;
@ -141,14 +153,11 @@ static int guess_codec(STREAMFILE* sf, int big_endian, int channels, mul_codec*
else { //if (ps_check_format(sf, 0x820, 0x100)) { else { //if (ps_check_format(sf, 0x820, 0x100)) {
/* may be PS3/X360, tested below [Tomb Raider 7 (PS3)] */ /* may be PS3/X360, tested below [Tomb Raider 7 (PS3)] */
} }
// todo test XMA1 (X360): N mono streams (layered), each block has 1 sub-blocks of 0x800 packet per channel
} }
{ {
int i; int i;
off_t offset = 0x800; off_t offset = start_offset;
size_t file_size = get_streamfile_size(sf); size_t file_size = get_streamfile_size(sf);
size_t frame_size; size_t frame_size;
@ -163,6 +172,12 @@ static int guess_codec(STREAMFILE* sf, int big_endian, int channels, mul_codec*
continue; /* not audio */ continue; /* not audio */
} }
/* test FSB4 header */
if (read_u32be(offset + 0x10, sf) == 0x46534234 || read_u32be(offset + 0x20, sf) == 0x46534234) {
*p_codec = FSB4;
return 1;
}
/* test XMA1 (X360): has sub-blocks of 0x800 per channel */ /* test XMA1 (X360): has sub-blocks of 0x800 per channel */
if (block_size == 0x810 * channels) { if (block_size == 0x810 * channels) {
for (i = 0; i < channels; i++) { for (i = 0; i < channels; i++) {
@ -195,7 +210,7 @@ static int guess_codec(STREAMFILE* sf, int big_endian, int channels, mul_codec*
break; break;
} }
if (i == data_size / frame_size) { if (i == data_size / frame_size) {
*p_codec = XBOX; *p_codec = IMA;
return 1; return 1;
} }
@ -207,8 +222,8 @@ static int guess_codec(STREAMFILE* sf, int big_endian, int channels, mul_codec*
} }
/* MUL contain one XMA1 streams per channel so we need the usual voodoo */ /* MUL contain one XMA1/FSB streams per channel so we need the usual voodoo */
static layered_layout_data* build_layered_mul(STREAMFILE *sf_data, int big_endian, VGMSTREAM* vgmstream) { static layered_layout_data* build_layered_mul(STREAMFILE* sf, off_t offset, int big_endian, VGMSTREAM* vgmstream, mul_codec codec) {
layered_layout_data* data = NULL; layered_layout_data* data = NULL;
STREAMFILE* temp_sf = NULL; STREAMFILE* temp_sf = NULL;
int i, layers = vgmstream->channels; int i, layers = vgmstream->channels;
@ -219,8 +234,19 @@ static layered_layout_data* build_layered_mul(STREAMFILE *sf_data, int big_endia
if (!data) goto fail; if (!data) goto fail;
for (i = 0; i < layers; i++) { for (i = 0; i < layers; i++) {
switch(codec) {
#ifdef VGM_USE_FFMPEG
case XMA1: {
uint8_t buf[0x100];
int bytes;
size_t stream_size;
int layer_channels = 1; int layer_channels = 1;
temp_sf = setup_mul_streamfile(sf, offset, big_endian, i, layers, NULL);
if (!temp_sf) goto fail;
stream_size = get_streamfile_size(temp_sf);
/* build the layer VGMSTREAM */ /* build the layer VGMSTREAM */
data->layers[i] = allocate_vgmstream(layer_channels, 0); data->layers[i] = allocate_vgmstream(layer_channels, 0);
@ -229,17 +255,6 @@ static layered_layout_data* build_layered_mul(STREAMFILE *sf_data, int big_endia
data->layers[i]->sample_rate = vgmstream->sample_rate; data->layers[i]->sample_rate = vgmstream->sample_rate;
data->layers[i]->num_samples = vgmstream->num_samples; data->layers[i]->num_samples = vgmstream->num_samples;
#ifdef VGM_USE_FFMPEG
{
uint8_t buf[0x100];
int bytes;
size_t stream_size;
temp_sf = setup_mul_streamfile(sf_data, big_endian, i, layers);
if (!temp_sf) goto fail;
stream_size = get_streamfile_size(temp_sf);
bytes = ffmpeg_make_riff_xma1(buf, 0x100, data->layers[i]->num_samples, stream_size, data->layers[i]->channels, data->layers[i]->sample_rate, 0); bytes = ffmpeg_make_riff_xma1(buf, 0x100, data->layers[i]->num_samples, stream_size, data->layers[i]->channels, data->layers[i]->sample_rate, 0);
data->layers[i]->codec_data = init_ffmpeg_header_offset(temp_sf, buf,bytes, 0x00, stream_size); data->layers[i]->codec_data = init_ffmpeg_header_offset(temp_sf, buf,bytes, 0x00, stream_size);
if (!data->layers[i]->codec_data) goto fail; if (!data->layers[i]->codec_data) goto fail;
@ -249,17 +264,30 @@ static layered_layout_data* build_layered_mul(STREAMFILE *sf_data, int big_endia
data->layers[i]->stream_size = stream_size; data->layers[i]->stream_size = stream_size;
xma_fix_raw_samples(data->layers[i], temp_sf, 0x00,stream_size, 0, 0,0); /* ? */ xma_fix_raw_samples(data->layers[i], temp_sf, 0x00,stream_size, 0, 0,0); /* ? */
break;
}
#endif
case FSB4: { /* FSB4 w/ mono MP3 [Tomb Raider 8 (PS3), Avengers (PC)] */
temp_sf = setup_mul_streamfile(sf, offset, big_endian, i, layers, "fsb");
if (!temp_sf) goto fail;
data->layers[i] = init_vgmstream_fsb(temp_sf);
if (!data->layers[i]) goto fail;
break;
}
default:
goto fail;
}
close_streamfile(temp_sf); close_streamfile(temp_sf);
temp_sf = NULL; temp_sf = NULL;
} }
#else
goto fail;
#endif
}
if (!setup_layout_layered(data)) if (!setup_layout_layered(data))
goto fail; goto fail;
vgmstream->coding_type = data->layers[0]->coding_type;
return data; return data;
fail: fail:

View file

@ -2,56 +2,71 @@
#define _MUL_STREAMFILE_H_ #define _MUL_STREAMFILE_H_
#include "deblock_streamfile.h" #include "deblock_streamfile.h"
static void block_callback(STREAMFILE* sf, deblock_io_data* data) { static void block_callback(STREAMFILE* sf, deblock_io_data* data) {
uint32_t block_type;
size_t block_size;
uint32_t (*read_u32)(off_t,STREAMFILE*) = data->cfg.big_endian ? read_u32be : read_u32le; uint32_t (*read_u32)(off_t,STREAMFILE*) = data->cfg.big_endian ? read_u32be : read_u32le;
/* Blocks have base header + sub-blocks with track sub-header.
* Some blocks don't contain all channels (instead they begin next block). */
if (data->physical_offset == 0) { if (data->chunk_size && data->chunk_size < 0x10) {
data->block_size = 0x800; /* padding after all sub-blocks */
data->block_size = data->chunk_size;
data->data_size = 0; data->data_size = 0;
data->skip_size = 0; data->skip_size = 0;
return; data->chunk_size = 0;
} }
else if (data->chunk_size) {
/* audio block sub-headers, ignore data for other tracks */
uint32_t track_size = read_u32(data->physical_offset + 0x00, sf);
uint32_t track_number = read_u32(data->physical_offset + 0x04, sf);
/* 0x08: dummy (may contain un-init'd data) */
/* 0x0c: dummy (may contain un-init'd data) */
block_type = read_u32(data->physical_offset + 0x00, sf); data->block_size = 0x10 + track_size;
block_size = read_u32(data->physical_offset + 0x04, sf); /* not including main header */
/* some blocks only contain half of data (continues in next block) so use track numbers */
if (block_type == 0x00 && block_size != 0) {
/* header block */
data->block_size = 0x10;
data->data_size = 0; data->data_size = 0;
data->skip_size = 0; data->skip_size = 0;
}
else if (block_type == 0x00000800) {
data->block_size = 0x810;
/* actually sub-block with size + number, kinda half-assed but meh... */ if (track_number == data->cfg.track_number) {
if (block_size == data->cfg.track_number) { data->data_size = track_size;
data->data_size = 0x800;
data->skip_size = 0x10; data->skip_size = 0x10;
} }
else{
data->data_size = 0; data->chunk_size -= data->block_size;
data->skip_size = 0;
}
} }
else { else {
/* non-audio block */ /* base block header */
data->block_size = block_size + 0x10; uint32_t block_type = read_u32(data->physical_offset + 0x00, sf);
uint32_t block_size = read_u32(data->physical_offset + 0x04, sf);
/* 0x08: dummy */
/* 0x0c: dummy */
/* blocks are padded after all sub-blocks */
if (block_size % 0x10) {
block_size = block_size + 0x10 - (block_size % 0x10);
}
data->data_size = 0; data->data_size = 0;
data->skip_size = 0; data->skip_size = 0;
if (block_type == 0x00 && block_size != 0) {
/* audio block */
data->block_size = 0x10;
data->chunk_size = block_size;
}
else {
/* non-audio block (or empty audio block) */
data->block_size = block_size + 0x10;
}
} }
} }
/* Deinterleaves MUL streams */ /* Deinterleaves MUL streams */
static STREAMFILE* setup_mul_streamfile(STREAMFILE* sf, int big_endian, int track_number, int track_count) { static STREAMFILE* setup_mul_streamfile(STREAMFILE* sf, off_t offset, int big_endian, int track_number, int track_count, const char* extension) {
STREAMFILE *new_sf = NULL; STREAMFILE *new_sf = NULL;
deblock_config_t cfg = {0}; deblock_config_t cfg = {0};
cfg.stream_start = offset;
cfg.big_endian = big_endian; cfg.big_endian = big_endian;
cfg.track_number = track_number; cfg.track_number = track_number;
cfg.track_count = track_count; cfg.track_count = track_count;
@ -59,6 +74,8 @@ static STREAMFILE* setup_mul_streamfile(STREAMFILE* sf, int big_endian, int trac
new_sf = open_wrap_streamfile(sf); new_sf = open_wrap_streamfile(sf);
new_sf = open_io_deblock_streamfile_f(new_sf, &cfg); new_sf = open_io_deblock_streamfile_f(new_sf, &cfg);
if (extension)
new_sf = open_fakename_streamfile_f(new_sf, NULL, extension);
return new_sf; return new_sf;
} }

View file

@ -2,61 +2,56 @@
#include "../coding/coding.h" #include "../coding/coding.h"
/* .NAAC - from Namco 3DS games (Ace Combat - Assault Horizon Legacy, Taiko no Tatsujin Don to Katsu no Jikuu Daibouken) */ /* .NAAC - from Namco 3DS games (Ace Combat - Assault Horizon Legacy, Taiko no Tatsujin Don to Katsu no Jikuu Daibouken) */
VGMSTREAM * init_vgmstream_naac(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_naac(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
off_t start_offset; off_t start_offset;
int loop_flag, channel_count; int loop_flag, channel_count;
size_t data_size; size_t data_size;
/* check extension */ /* check extension */
if ( !check_extensions(streamFile,"naac") ) if ( !check_extensions(sf,"naac") )
goto fail; goto fail;
/* check header */ /* check header */
if (read_32bitBE(0x00,streamFile) != 0x41414320) /* "AAC " */ if (read_32bitBE(0x00,sf) != 0x41414320) /* "AAC " */
goto fail; goto fail;
if (read_32bitLE(0x04,streamFile) != 0x01) /* version? */ if (read_32bitLE(0x04,sf) != 0x01) /* version? */
goto fail; goto fail;
start_offset = 0x1000; start_offset = 0x1000;
loop_flag = (read_32bitLE(0x18,streamFile) != 0); loop_flag = (read_32bitLE(0x18,sf) != 0);
channel_count = read_32bitLE(0x08,streamFile); channel_count = read_32bitLE(0x08,sf);
/* build the VGMSTREAM */ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag); vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(0x0c,streamFile); vgmstream->sample_rate = read_32bitLE(0x0c,sf);
vgmstream->num_samples = read_32bitLE(0x10,streamFile); /* without skip_samples */ vgmstream->num_samples = read_32bitLE(0x10,sf); /* without skip_samples */
vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile); /* with skip_samples */ vgmstream->loop_start_sample = read_32bitLE(0x14,sf); /* with skip_samples */
vgmstream->loop_end_sample = read_32bitLE(0x18,streamFile); vgmstream->loop_end_sample = read_32bitLE(0x18,sf);
/* 0x1c: loop start offset, 0x20: loop end offset (within data) */ /* 0x1c: loop start offset, 0x20: loop end offset (within data) */
data_size = read_32bitLE(0x24,streamFile); data_size = read_32bitLE(0x24,sf);
/* 0x28: unknown; 0x2c: table start offset?; 0x30: seek table (always 0xFD0, padded) */ /* 0x28: unknown; 0x2c: table start offset?; 0x30: seek table (always 0xFD0, padded) */
vgmstream->meta_type = meta_NAAC; vgmstream->meta_type = meta_NAAC;
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
{ {
ffmpeg_codec_data *ffmpeg_data = NULL; vgmstream->codec_data = init_ffmpeg_offset(sf, start_offset,data_size);
if (!vgmstream->codec_data) goto fail;
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,data_size);
if (!ffmpeg_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
/* observed default, some files start without silence though seems correct when loop_start=0 */ /* observed default, some files start without silence though seems correct when loop_start=0 */
if (!ffmpeg_data->skipSamples) /* FFmpeg doesn't seem to use not report it */ ffmpeg_set_skip_samples(vgmstream->codec_data, 1024); /* raw AAC doesn't set this */
ffmpeg_set_skip_samples(ffmpeg_data, 1024);
vgmstream->num_samples -= 1024; vgmstream->num_samples -= 1024;
} }
#else #else
goto fail; goto fail;
#endif #endif
/* open the file for reading */ if (!vgmstream_open_stream(vgmstream, sf, start_offset))
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail; goto fail;
return vgmstream; return vgmstream;

View file

@ -29,8 +29,8 @@ struct dsp_header {
/* read the above struct; returns nonzero on failure */ /* read the above struct; returns nonzero on failure */
static int read_dsp_header_endian(struct dsp_header *header, off_t offset, STREAMFILE *streamFile, int big_endian) { static int read_dsp_header_endian(struct dsp_header *header, off_t offset, STREAMFILE *streamFile, int big_endian) {
int32_t (*get_32bit)(uint8_t *) = big_endian ? get_32bitBE : get_32bitLE; int32_t (*get_32bit)(const uint8_t *) = big_endian ? get_32bitBE : get_32bitLE;
int16_t (*get_16bit)(uint8_t *) = big_endian ? get_16bitBE : get_16bitLE; int16_t (*get_16bit)(const uint8_t *) = big_endian ? get_16bitBE : get_16bitLE;
int i; int i;
uint8_t buf[0x4e]; uint8_t buf[0x4e];

View file

@ -1,18 +1,15 @@
#include "meta.h" #include "meta.h"
#include "../util.h" #include "../coding/coding.h"
#include "../coding/nwa_decoder.h"
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
static int get_loops_nwainfo_ini(STREAMFILE *streamFile, int *out_loop_flag, int32_t *out_loop_start); static int get_loops_nwainfo_ini(STREAMFILE *sf, int *p_loop_flag, int32_t *p_loop_start);
static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int32_t *out_loop_start, int32_t *out_loop_end); static int get_loops_gameexe_ini(STREAMFILE *sf, int *p_loop_flag, int32_t *p_loop_start, int32_t *p_loop_end);
static nwa_codec_data *open_nwa_vgmstream(STREAMFILE *streamFile);
static void free_nwa_vgmstream(nwa_codec_data *data);
/* NWA - Visual Art's streams [Air (PC), Clannad (PC)] */ /* NWA - Visual Art's streams [Air (PC), Clannad (PC)] */
VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_nwa(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
off_t start_offset; off_t start_offset;
int channel_count, loop_flag = 0; int channel_count, loop_flag = 0;
int32_t loop_start_sample = 0, loop_end_sample = 0; int32_t loop_start_sample = 0, loop_end_sample = 0;
@ -21,26 +18,26 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) {
/* checks */ /* checks */
if (!check_extensions(streamFile, "nwa")) if (!check_extensions(sf, "nwa"))
goto fail; goto fail;
channel_count = read_16bitLE(0x00,streamFile); channel_count = read_16bitLE(0x00,sf);
if (channel_count != 1 && channel_count != 2) goto fail; if (channel_count != 1 && channel_count != 2) goto fail;
/* check if we're using raw pcm */ /* check if we're using raw pcm */
if ( read_32bitLE(0x08,streamFile)==-1 || /* compression level */ if ( read_32bitLE(0x08,sf)==-1 || /* compression level */
read_32bitLE(0x10,streamFile)==0 || /* block count */ read_32bitLE(0x10,sf)==0 || /* block count */
read_32bitLE(0x18,streamFile)==0 || /* compressed data size */ read_32bitLE(0x18,sf)==0 || /* compressed data size */
read_32bitLE(0x20,streamFile)==0 || /* block size */ read_32bitLE(0x20,sf)==0 || /* block size */
read_32bitLE(0x24,streamFile)==0 ) { /* restsize */ read_32bitLE(0x24,sf)==0 ) { /* restsize */
compression_level = -1; compression_level = -1;
} else { } else {
compression_level = read_32bitLE(0x08,streamFile); compression_level = read_32bitLE(0x08,sf);
} }
/* loop points come from external files */ /* loop points come from external files */
nwainfo_ini_found = get_loops_nwainfo_ini(streamFile, &loop_flag, &loop_start_sample); nwainfo_ini_found = get_loops_nwainfo_ini(sf, &loop_flag, &loop_start_sample);
gameexe_ini_found = !nwainfo_ini_found && get_loops_gameexe_ini(streamFile, &loop_flag, &loop_start_sample, &loop_end_sample); gameexe_ini_found = !nwainfo_ini_found && get_loops_gameexe_ini(sf, &loop_flag, &loop_start_sample, &loop_end_sample);
start_offset = 0x2c; start_offset = 0x2c;
@ -48,12 +45,12 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) {
vgmstream = allocate_vgmstream(channel_count,loop_flag); vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(0x04,streamFile); vgmstream->sample_rate = read_32bitLE(0x04,sf);
vgmstream->num_samples = read_32bitLE(0x1c,streamFile) / channel_count; vgmstream->num_samples = read_32bitLE(0x1c,sf) / channel_count;
switch(compression_level) { switch(compression_level) {
case -1: case -1:
switch (read_16bitLE(0x02,streamFile)) { switch (read_16bitLE(0x02,sf)) {
case 8: case 8:
vgmstream->coding_type = coding_PCM8; vgmstream->coding_type = coding_PCM8;
vgmstream->interleave_block_size = 0x01; vgmstream->interleave_block_size = 0x01;
@ -76,7 +73,7 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) {
case 5: case 5:
vgmstream->coding_type = coding_NWA; vgmstream->coding_type = coding_NWA;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
vgmstream->codec_data = open_nwa_vgmstream(streamFile); vgmstream->codec_data = init_nwa(sf);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
break; break;
@ -103,7 +100,7 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) {
} }
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) if (!vgmstream_open_stream(vgmstream,sf,start_offset))
goto fail; goto fail;
return vgmstream; return vgmstream;
@ -114,8 +111,8 @@ fail:
/* try to locate NWAINFO.INI in the same directory */ /* try to locate NWAINFO.INI in the same directory */
static int get_loops_nwainfo_ini(STREAMFILE *streamFile, int *out_loop_flag, int32_t *out_loop_start) { static int get_loops_nwainfo_ini(STREAMFILE *sf, int *p_loop_flag, int32_t *p_loop_start) {
STREAMFILE *streamLoops; STREAMFILE *sf_loop;
char namebase[PATH_LIMIT]; char namebase[PATH_LIMIT];
const char * ext; const char * ext;
int length; int length;
@ -127,15 +124,15 @@ static int get_loops_nwainfo_ini(STREAMFILE *streamFile, int *out_loop_flag, int
int32_t loop_start_sample = 0; int32_t loop_start_sample = 0;
streamLoops = open_streamfile_by_filename(streamFile, "NWAINFO.INI"); sf_loop = open_streamfile_by_filename(sf, "NWAINFO.INI");
if (!streamLoops) goto fail; if (!sf_loop) goto fail;
get_streamfile_filename(streamFile,namebase,PATH_LIMIT); get_streamfile_filename(sf,namebase,PATH_LIMIT);
/* ini found, try to find our name */ /* ini found, try to find our name */
ext = filename_extension(namebase); ext = filename_extension(namebase);
length = ext - 1 - namebase; length = ext - 1 - namebase;
file_size = get_streamfile_size(streamLoops); file_size = get_streamfile_size(sf_loop);
for (found = 0, offset = 0; !found && offset < file_size; offset++) { for (found = 0, offset = 0; !found && offset < file_size; offset++) {
off_t suboffset; off_t suboffset;
@ -145,12 +142,12 @@ static int get_loops_nwainfo_ini(STREAMFILE *streamFile, int *out_loop_flag, int
for (suboffset = offset; for (suboffset = offset;
suboffset < file_size && suboffset < file_size &&
suboffset-offset < length && suboffset-offset < length &&
read_8bit(suboffset,streamLoops) == namebase[suboffset-offset]; read_8bit(suboffset,sf_loop) == namebase[suboffset-offset];
suboffset++) { suboffset++) {
/* skip */ /* skip */
} }
if (suboffset-offset==length && read_8bit(suboffset,streamLoops)==0x09) { /* tab */ if (suboffset-offset==length && read_8bit(suboffset,sf_loop)==0x09) { /* tab */
found = 1; found = 1;
found_off = suboffset+1; found_off = suboffset+1;
} }
@ -160,7 +157,7 @@ static int get_loops_nwainfo_ini(STREAMFILE *streamFile, int *out_loop_flag, int
if (found) { if (found) {
char loopstring[9] = {0}; char loopstring[9] = {0};
if (read_streamfile((uint8_t*)loopstring,found_off,8,streamLoops) == 8) { if (read_streamfile((uint8_t*)loopstring,found_off,8,sf_loop) == 8) {
loop_start_sample = atol(loopstring); loop_start_sample = atol(loopstring);
if (loop_start_sample > 0) if (loop_start_sample > 0)
loop_flag = 1; loop_flag = 1;
@ -168,22 +165,22 @@ static int get_loops_nwainfo_ini(STREAMFILE *streamFile, int *out_loop_flag, int
} }
*out_loop_flag = loop_flag; *p_loop_flag = loop_flag;
*out_loop_start = loop_start_sample; *p_loop_start = loop_start_sample;
close_streamfile(streamLoops); close_streamfile(sf_loop);
return 1; return 1;
fail: fail:
close_streamfile(streamLoops); close_streamfile(sf_loop);
return 0; return 0;
} }
/* try to locate Gameexe.ini in the same directory */ /* try to locate Gameexe.ini in the same directory */
static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int32_t *out_loop_start, int32_t *out_loop_end) { static int get_loops_gameexe_ini(STREAMFILE* sf, int* p_loop_flag, int32_t* p_loop_start, int32_t* p_loop_end) {
STREAMFILE *streamLoops; STREAMFILE*sf_loop;
char namebase[PATH_LIMIT]; char namebase[PATH_LIMIT];
const char * ext; const char* ext;
int length; int length;
int found; int found;
off_t offset; off_t offset;
@ -193,15 +190,15 @@ static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int
int32_t loop_start_sample = 0, loop_end_sample = 0; int32_t loop_start_sample = 0, loop_end_sample = 0;
streamLoops = open_streamfile_by_filename(streamFile, "Gameexe.ini"); sf_loop = open_streamfile_by_filename(sf, "Gameexe.ini");
if (!streamLoops) goto fail; if (!sf_loop) goto fail;
get_streamfile_filename(streamFile,namebase,PATH_LIMIT); get_streamfile_filename(sf,namebase,PATH_LIMIT);
/* ini found, try to find our name */ /* ini found, try to find our name */
ext = filename_extension(namebase); ext = filename_extension(namebase);
length = ext-1-namebase; length = ext-1-namebase;
file_size = get_streamfile_size(streamLoops); file_size = get_streamfile_size(sf_loop);
/* format of line is: /* format of line is:
* #DSTRACK = 00000000 - eeeeeeee - ssssssss = "name" = "name2?" * #DSTRACK = 00000000 - eeeeeeee - ssssssss = "name" = "name2?"
@ -212,20 +209,20 @@ static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int
off_t suboffset; off_t suboffset;
uint8_t buf[10]; uint8_t buf[10];
if (read_8bit(offset,streamLoops)!='#') continue; if (read_8bit(offset,sf_loop)!='#') continue;
if (read_streamfile(buf,offset+1,10,streamLoops)!=10) break; if (read_streamfile(buf,offset+1,10,sf_loop)!=10) break;
if (memcmp("DSTRACK = ",buf,10)) continue; if (memcmp("DSTRACK = ",buf,10)) continue;
if (read_8bit(offset+44,streamLoops)!='\"') continue; if (read_8bit(offset+44,sf_loop)!='\"') continue;
for (suboffset = offset+45; for (suboffset = offset+45;
suboffset < file_size && suboffset < file_size &&
suboffset-offset-45 < length && suboffset-offset-45 < length &&
tolower(read_8bit(suboffset,streamLoops)) == tolower(namebase[suboffset-offset-45]); tolower(read_8bit(suboffset,sf_loop)) == tolower(namebase[suboffset-offset-45]);
suboffset++) { suboffset++) {
/* skip */ /* skip */
} }
if (suboffset-offset-45==length && read_8bit(suboffset,streamLoops)=='\"') { /* tab */ if (suboffset-offset-45==length && read_8bit(suboffset,sf_loop)=='\"') { /* tab */
found = 1; found = 1;
found_off = offset+22; /* loop end */ found_off = offset+22; /* loop end */
} }
@ -234,9 +231,9 @@ static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int
if (found) { if (found) {
char loopstring[9] = {0}; char loopstring[9] = {0};
int start_ok = 0, end_ok = 0; int start_ok = 0, end_ok = 0;
int32_t total_samples = read_32bitLE(0x1c,streamFile) / read_16bitLE(0x00,streamFile); int32_t total_samples = read_32bitLE(0x1c,sf) / read_16bitLE(0x00,sf);
if (read_streamfile((uint8_t*)loopstring,found_off,8,streamLoops)==8) if (read_streamfile((uint8_t*)loopstring,found_off,8,sf_loop)==8)
{ {
if (!memcmp("99999999",loopstring,8)) { if (!memcmp("99999999",loopstring,8)) {
loop_end_sample = total_samples; loop_end_sample = total_samples;
@ -246,7 +243,7 @@ static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int
} }
end_ok = 1; end_ok = 1;
} }
if (read_streamfile((uint8_t*)loopstring,found_off+11,8,streamLoops)==8) if (read_streamfile((uint8_t*)loopstring,found_off+11,8,sf_loop)==8)
{ {
if (!memcmp("99999999",loopstring,8)) { if (!memcmp("99999999",loopstring,8)) {
/* not ok to start at last sample, /* not ok to start at last sample,
@ -265,43 +262,14 @@ static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int
} /* if found file name in INI */ } /* if found file name in INI */
*out_loop_flag = loop_flag; *p_loop_flag = loop_flag;
*out_loop_start = loop_start_sample; *p_loop_start = loop_start_sample;
*out_loop_end = loop_end_sample; *p_loop_end = loop_end_sample;
close_streamfile(streamLoops); close_streamfile(sf_loop);
return 1; return 1;
fail: fail:
close_streamfile(streamLoops); close_streamfile(sf_loop);
return 0; return 0;
} }
static nwa_codec_data *open_nwa_vgmstream(STREAMFILE *streamFile) {
nwa_codec_data *data = NULL;
char filename[PATH_LIMIT];
streamFile->get_name(streamFile,filename,sizeof(filename));
data = malloc(sizeof(nwa_codec_data));
if (!data) goto fail;
data->nwa = open_nwa(streamFile,filename);
if (!data->nwa) goto fail;
return data;
fail:
free_nwa_vgmstream(data);
return NULL;
}
static void free_nwa_vgmstream(nwa_codec_data *data) {
if (data) {
if (data->nwa) {
close_nwa(data->nwa);
}
free(data);
}
}

View file

@ -431,6 +431,9 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb
data = init_ogg_vorbis(streamFile, start, stream_size, &io); data = init_ogg_vorbis(streamFile, start, stream_size, &io);
if (!data) goto fail; if (!data) goto fail;
ogg_vorbis_get_info(data, &channels, &sample_rate);
ogg_vorbis_get_samples(data, &num_samples); /* let libvorbisfile find total samples */
/* search for loop comments */ /* search for loop comments */
{//todo ignore if loop flag already set? {//todo ignore if loop flag already set?
const char * comment = NULL; const char * comment = NULL;
@ -439,11 +442,13 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb
if (strstr(comment,"loop_start=") == comment || /* PSO4 */ if (strstr(comment,"loop_start=") == comment || /* PSO4 */
strstr(comment,"LOOP_START=") == comment || /* PSO4 */ strstr(comment,"LOOP_START=") == comment || /* PSO4 */
strstr(comment,"LOOPPOINT=") == comment || /* Sonic Robo Blast 2 */
strstr(comment,"COMMENT=LOOPPOINT=") == comment || strstr(comment,"COMMENT=LOOPPOINT=") == comment ||
strstr(comment,"LOOPSTART=") == comment || strstr(comment,"LOOPSTART=") == comment ||
strstr(comment,"um3.stream.looppoint.start=") == comment || strstr(comment,"um3.stream.looppoint.start=") == comment ||
strstr(comment,"LOOP_BEGIN=") == comment || /* Hatsune Miku: Project Diva F (PS3) */ strstr(comment,"LOOP_BEGIN=") == comment || /* Hatsune Miku: Project Diva F (PS3) */
strstr(comment,"LoopStart=") == comment || /* Devil May Cry 4 (PC) */ strstr(comment,"LoopStart=") == comment || /* Devil May Cry 4 (PC) */
strstr(comment,"LOOP=") == comment || /* Duke Nukem 3D: 20th Anniversary World Tour */
strstr(comment,"XIPH_CUE_LOOPSTART=") == comment) { /* Super Mario Run (Android) */ strstr(comment,"XIPH_CUE_LOOPSTART=") == comment) { /* Super Mario Run (Android) */
loop_start = atol(strrchr(comment,'=')+1); loop_start = atol(strrchr(comment,'=')+1);
loop_flag = (loop_start >= 0); loop_flag = (loop_start >= 0);
@ -512,6 +517,12 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb
loop_end_found = 1; loop_end_found = 1;
} }
} }
else if (strstr(comment,"LOOPMS=") == comment) { /* Sonic Robo Blast 2 */
/* Convert from milliseconds to samples. */
/* (x ms) * (y samples/s) / (1000 ms/s) */
loop_start = atol(strrchr(comment,'=')+1) * sample_rate / 1000;
loop_flag = (loop_start >= 0);
}
/* Hatsune Miku Project DIVA games, though only 'Arcade Future Tone' has >4ch files /* Hatsune Miku Project DIVA games, though only 'Arcade Future Tone' has >4ch files
* ENCODER tag is common but ogg_vorbis_encode looks unique enough * ENCODER tag is common but ogg_vorbis_encode looks unique enough
@ -529,8 +540,6 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb
} }
ogg_vorbis_set_disable_reordering(data, disable_reordering); ogg_vorbis_set_disable_reordering(data, disable_reordering);
ogg_vorbis_get_info(data, &channels, &sample_rate);
ogg_vorbis_get_samples(data, &num_samples); /* let libvorbisfile find total samples */
/* build the VGMSTREAM */ /* build the VGMSTREAM */

View file

@ -1,11 +1,11 @@
#include "meta.h" #include "meta.h"
#include "../coding/coding.h" #include "../coding/coding.h"
static size_t joe_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave); static size_t joe_find_padding(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, size_t interleave);
/* .JOE - from Asobo Studio games [Up (PS2), Wall-E (PS2)] */ /* .JOE - from Asobo Studio games [Up (PS2), Wall-E (PS2)] */
VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_ps2_joe(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
off_t start_offset; off_t start_offset;
int channel_count, loop_flag, sample_rate; int channel_count, loop_flag, sample_rate;
int32_t num_samples; int32_t num_samples;
@ -13,54 +13,59 @@ VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE *streamFile) {
/* checks */ /* checks */
if (!check_extensions(streamFile, "joe")) if (!check_extensions(sf, "joe"))
goto fail; goto fail;
file_size = get_streamfile_size(streamFile); file_size = get_streamfile_size(sf);
data_size = read_32bitLE(0x04,streamFile); data_size = read_u32le(0x04,sf);
unknown1 = read_32bitLE(0x08,streamFile); unknown1 = read_u32le(0x08,sf);
unknown2 = read_32bitLE(0x0c,streamFile); unknown2 = read_u32le(0x0c,sf);
/* detect version */ /* detect version */
if (data_size / 2 == file_size - 0x10 if (data_size == file_size - 0x800
&& unknown1 == 0x00002000 && unknown2 == 0xFFFFFFFF) { /* NYR (PS2) */
interleave = 0x2000;
start_offset = 0x800;
}
else if (data_size / 2 == file_size - 0x10
&& unknown1 == 0x0045039A && unknown2 == 0x00108920) { /* Super Farm (PS2) */ && unknown1 == 0x0045039A && unknown2 == 0x00108920) { /* Super Farm (PS2) */
data_size = data_size / 2; data_size = data_size / 2;
interleave = 0x4000; interleave = 0x4000;
start_offset = 0x10; start_offset = 0x10;
} else if (data_size / 2 == file_size - 0x10 }
else if (data_size / 2 == file_size - 0x10
&& unknown1 == 0xCCCCCCCC && unknown2 == 0xCCCCCCCC) { /* Sitting Ducks (PS2) */ && unknown1 == 0xCCCCCCCC && unknown2 == 0xCCCCCCCC) { /* Sitting Ducks (PS2) */
data_size = data_size / 2; data_size = data_size / 2;
interleave = 0x8000; interleave = 0x8000;
start_offset = 0x10; start_offset = 0x10;
} else if (data_size == file_size - 0x10 }
else if (data_size == file_size - 0x10
&& unknown1 == 0xCCCCCCCC && unknown2 == 0xCCCCCCCC) { /* The Mummy: The Animated Series (PS2) */ && unknown1 == 0xCCCCCCCC && unknown2 == 0xCCCCCCCC) { /* The Mummy: The Animated Series (PS2) */
interleave = 0x8000; interleave = 0x8000;
start_offset = 0x10; start_offset = 0x10;
} else if (data_size == file_size - 0x4020) { /* CT Special Forces (PS2), and all games beyond */ }
interleave = unknown1; /* always 0? */ else if (data_size == file_size - 0x4020) { /* Counter Terrorism Special Forces (PS2), all games beyond */
if (!interleave) /* header can be section(?) table (0x08=entry count) then 0xCCCCCCCC, all 0s, or all 0xCCCCCCCC (no table) */
interleave = 0x10; interleave = 0x10;
start_offset = 0x4020; /* header padding contains garbage */ start_offset = 0x4020;
} else { }
else {
goto fail; goto fail;
} }
//start_offset = file_size - data_size; /* also ok */ //start_offset = file_size - data_size; /* also ok */
channel_count = 2; channel_count = 2;
loop_flag = 0; loop_flag = 0;
sample_rate = read_32bitLE(0x00,streamFile); sample_rate = read_s32le(0x00,sf);
/* the file's end is padded with either 0xcdcdcdcd or zeroes */
padding_size = joe_find_padding(streamFile, start_offset, data_size, channel_count, interleave);
if (padding_size == SIZE_MAX)
goto fail;
/* the file's end is padded with either 0xcdcdcdcd or zeroes (but not always, ex. NYR) */
padding_size = joe_find_padding(sf, start_offset, data_size, channel_count, interleave);
data_size -= padding_size; data_size -= padding_size;
num_samples = ps_bytes_to_samples(data_size, channel_count); num_samples = ps_bytes_to_samples(data_size, channel_count);
/* build the VGMSTREAM */ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag); vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate; vgmstream->sample_rate = sample_rate;
@ -72,7 +77,7 @@ VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE *streamFile) {
vgmstream->interleave_block_size = interleave; vgmstream->interleave_block_size = interleave;
vgmstream->meta_type = meta_PS2_JOE; vgmstream->meta_type = meta_PS2_JOE;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail; goto fail;
return vgmstream; return vgmstream;
@ -81,23 +86,23 @@ fail:
return NULL; return NULL;
} }
static size_t joe_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave) { static size_t joe_find_padding(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, size_t interleave) {
uint8_t flag; uint32_t pad;
off_t min_offset, offset; off_t min_offset, offset;
size_t frame_size = 0x10; size_t frame_size = 0x10;
size_t padding_size = 0; size_t padding_size = 0;
size_t interleave_consumed = 0; size_t interleave_consumed = 0;
if (data_size == 0 || channels == 0 || (channels > 0 && interleave == 0)) if (data_size == 0 || channels == 0 || (channels > 0 && interleave == 0))
return SIZE_MAX; return 0;
offset = start_offset + data_size - interleave * (channels - 1); offset = start_offset + data_size - interleave * (channels - 1);
min_offset = start_offset; min_offset = start_offset;
while (offset > min_offset) { while (offset > min_offset) {
offset -= frame_size; offset -= frame_size;
flag = read_8bit(offset + 0x01, streamFile); pad = read_u32be(offset, sf);
if (flag == 0x03) if (pad != 0xCDCDCDCD && pad != 0x00000000)
break; break;
padding_size += frame_size * channels; padding_size += frame_size * channels;
@ -111,7 +116,7 @@ static size_t joe_find_padding(STREAMFILE *streamFile, off_t start_offset, size_
} }
if (padding_size >= data_size) if (padding_size >= data_size)
return SIZE_MAX; return 0;
return padding_size; return padding_size;
} }

View file

@ -1,80 +0,0 @@
#include "meta.h"
#include "../util.h"
/* PS2 SVAG (SNK)
*
* Found in SNK's World Heroes Anthology and Fatal Fury Battle Archives 2, maybe others
* No relation with Konami's SVAG.
*/
VGMSTREAM * init_vgmstream_ps2_svag_snk(STREAMFILE* streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset = 0x20;
int loop_flag;
int channel_count;
int loop_start_block;
int loop_end_block;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("svag",filename_extension(filename))) goto fail;
/* check SNK SVAG Header ("VAGm") */
if (read_32bitBE(0x00,streamFile) != 0x5641476D)
goto fail;
channel_count = read_32bitLE(0x0c,streamFile);
loop_start_block = read_32bitLE(0x18,streamFile);
loop_end_block = read_32bitLE(0x1c,streamFile);
loop_flag = loop_end_block > 0; /* loop_start_block can be 0 */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* header data */
vgmstream->coding_type = coding_PSX;
vgmstream->meta_type = meta_PS2_SVAG_SNK;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
vgmstream->num_samples = read_32bitLE(0x10,streamFile) * 28; /* size in blocks */
if( vgmstream->loop_flag ) {
vgmstream->loop_start_sample = loop_start_block * 28;
vgmstream->loop_end_sample = loop_end_block * 28;
}
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
/* 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

@ -23,8 +23,8 @@ VGMSTREAM * init_vgmstream_redspark(STREAMFILE *streamFile) {
uint32_t key; uint32_t key;
enum {encsize = 0x1000}; enum {encsize = 0x1000};
uint8_t buf[encsize]; uint8_t buf[encsize];
int32_t(*get_32bit)(uint8_t *p) = NULL; int32_t(*get_32bit)(const uint8_t *p) = NULL;
int16_t(*get_16bit)(uint8_t *p) = NULL; int16_t(*get_16bit)(const uint8_t *p) = NULL;
get_16bit = get_16bitBE; get_16bit = get_16bitBE;
get_32bit = get_32bitBE; get_32bit = get_32bitBE;

View file

@ -9,7 +9,7 @@
/* return milliseconds */ /* return milliseconds */
static long parse_adtl_marker(unsigned char * marker) { static long parse_adtl_marker(unsigned char* marker) {
long hh,mm,ss,ms; long hh,mm,ss,ms;
if (memcmp("Marker ",marker,7)) return -1; if (memcmp("Marker ",marker,7)) return -1;
@ -21,14 +21,14 @@ static long parse_adtl_marker(unsigned char * marker) {
} }
/* loop points have been found hiding here */ /* loop points have been found hiding here */
static void parse_adtl(off_t adtl_offset, off_t adtl_length, STREAMFILE *streamFile, long *loop_start, long *loop_end, int *loop_flag) { static void parse_adtl(off_t adtl_offset, off_t adtl_length, STREAMFILE* sf, long* loop_start, long* loop_end, int* loop_flag) {
int loop_start_found = 0; int loop_start_found = 0;
int loop_end_found = 0; int loop_end_found = 0;
off_t current_chunk = adtl_offset+0x04; off_t current_chunk = adtl_offset+0x04;
while (current_chunk < adtl_offset + adtl_length) { while (current_chunk < adtl_offset + adtl_length) {
uint32_t chunk_type = read_32bitBE(current_chunk+0x00,streamFile); uint32_t chunk_type = read_32bitBE(current_chunk+0x00,sf);
off_t chunk_size = read_32bitLE(current_chunk+0x04,streamFile); off_t chunk_size = read_32bitLE(current_chunk+0x04,sf);
if (current_chunk+0x08+chunk_size > adtl_offset+adtl_length) if (current_chunk+0x08+chunk_size > adtl_offset+adtl_length)
return; return;
@ -37,12 +37,12 @@ static void parse_adtl(off_t adtl_offset, off_t adtl_length, STREAMFILE *stream
case 0x6c61626c: { /* "labl" */ case 0x6c61626c: { /* "labl" */
unsigned char *labelcontent = malloc(chunk_size-0x04); unsigned char *labelcontent = malloc(chunk_size-0x04);
if (!labelcontent) return; if (!labelcontent) return;
if (read_streamfile(labelcontent,current_chunk+0x0c, chunk_size-0x04,streamFile) != chunk_size-0x04) { if (read_streamfile(labelcontent,current_chunk+0x0c, chunk_size-0x04,sf) != chunk_size-0x04) {
free(labelcontent); free(labelcontent);
return; return;
} }
switch (read_32bitLE(current_chunk+8,streamFile)) { switch (read_32bitLE(current_chunk+8,sf)) {
case 1: case 1:
if (!loop_start_found && (*loop_start = parse_adtl_marker(labelcontent)) >= 0) if (!loop_start_found && (*loop_start = parse_adtl_marker(labelcontent)) >= 0)
loop_start_found = 1; loop_start_found = 1;
@ -95,29 +95,29 @@ typedef struct {
int is_at9; int is_at9;
} riff_fmt_chunk; } riff_fmt_chunk;
static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk, riff_fmt_chunk * fmt, int mwv) { static int read_fmt(int big_endian, STREAMFILE* sf, off_t current_chunk, riff_fmt_chunk* fmt, int mwv) {
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE; int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE; int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE;
fmt->offset = current_chunk; fmt->offset = current_chunk;
fmt->size = read_32bit(current_chunk+0x04,streamFile); fmt->size = read_32bit(current_chunk+0x04,sf);
/* WAVEFORMAT */ /* WAVEFORMAT */
fmt->codec = (uint16_t)read_16bit(current_chunk+0x08,streamFile); fmt->codec = (uint16_t)read_16bit(current_chunk+0x08,sf);
fmt->channel_count = read_16bit(current_chunk+0x0a,streamFile); fmt->channel_count = read_16bit(current_chunk+0x0a,sf);
fmt->sample_rate = read_32bit(current_chunk+0x0c,streamFile); fmt->sample_rate = read_32bit(current_chunk+0x0c,sf);
//fmt->avg_bps = read_32bit(current_chunk+0x10,streamFile); //fmt->avg_bps = read_32bit(current_chunk+0x10,sf);
fmt->block_size = read_16bit(current_chunk+0x14,streamFile); fmt->block_size = read_16bit(current_chunk+0x14,sf);
fmt->bps = read_16bit(current_chunk+0x16,streamFile); fmt->bps = read_16bit(current_chunk+0x16,sf);
/* WAVEFORMATEX */ /* WAVEFORMATEX */
if (fmt->size >= 0x10) { if (fmt->size >= 0x10) {
fmt->extra_size = read_16bit(current_chunk+0x18,streamFile); fmt->extra_size = read_16bit(current_chunk+0x18,sf);
/* 0x1a+ depends on codec (ex. coef table for MSADPCM, samples_per_frame in MS-IMA, etc) */ /* 0x1a+ depends on codec (ex. coef table for MSADPCM, samples_per_frame in MS-IMA, etc) */
} }
/* WAVEFORMATEXTENSIBLE */ /* WAVEFORMATEXTENSIBLE */
if (fmt->codec == 0xFFFE && fmt->extra_size >= 0x16) { if (fmt->codec == 0xFFFE && fmt->extra_size >= 0x16) {
//fmt->extra_samples = read_16bit(current_chunk+0x1a,streamFile); /* valid_bits_per_sample or samples_per_block */ //fmt->extra_samples = read_16bit(current_chunk+0x1a,sf); /* valid_bits_per_sample or samples_per_block */
fmt->channel_layout = read_32bit(current_chunk+0x1c,streamFile); fmt->channel_layout = read_32bit(current_chunk+0x1c,sf);
/* 0x10 guid at 0x20 */ /* 0x10 guid at 0x20 */
/* happens in various .at3/at9, may be a bug in their encoder b/c MS's defs set mono as FC */ /* happens in various .at3/at9, may be a bug in their encoder b/c MS's defs set mono as FC */
@ -158,7 +158,7 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
case 0x02: /* MSADPCM */ case 0x02: /* MSADPCM */
if (fmt->bps == 4) { if (fmt->bps == 4) {
fmt->coding_type = coding_MSADPCM; fmt->coding_type = coding_MSADPCM;
if (!msadpcm_check_coefs(streamFile, fmt->offset + 0x08 + 0x14)) if (!msadpcm_check_coefs(sf, fmt->offset + 0x08 + 0x14))
goto fail; goto fail;
} }
else if (fmt->bps == 16 && fmt->block_size == 0x02 * fmt->channel_count && fmt->size == 0x14) { else if (fmt->bps == 16 && fmt->block_size == 0x02 * fmt->channel_count && fmt->size == 0x14) {
@ -188,7 +188,7 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
case 0x007A: /* MS IMA ADPCM [LA Rush (PC), Psi Ops (PC)] (unofficial) */ case 0x007A: /* MS IMA ADPCM [LA Rush (PC), Psi Ops (PC)] (unofficial) */
/* 0x007A is apparently "Voxware SC3" but in .MED it's just MS-IMA (0x11) */ /* 0x007A is apparently "Voxware SC3" but in .MED it's just MS-IMA (0x11) */
if (!check_extensions(streamFile,"med")) if (!check_extensions(sf,"med"))
goto fail; goto fail;
if (fmt->bps == 4) /* normal MS IMA */ if (fmt->bps == 4) /* normal MS IMA */
@ -232,11 +232,11 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
#endif #endif
case 0xFFFE: { /* WAVEFORMATEXTENSIBLE (see ksmedia.h for known GUIDs) */ case 0xFFFE: { /* WAVEFORMATEXTENSIBLE (see ksmedia.h for known GUIDs) */
uint32_t guid1 = (uint32_t)read_32bit (current_chunk+0x20,streamFile); uint32_t guid1 = (uint32_t)read_32bit (current_chunk+0x20,sf);
uint32_t guid2 = ((uint16_t)read_16bit (current_chunk+0x24,streamFile) << 16u) | uint32_t guid2 = ((uint16_t)read_16bit (current_chunk+0x24,sf) << 16u) |
((uint16_t)read_16bit (current_chunk+0x26,streamFile)); ((uint16_t)read_16bit (current_chunk+0x26,sf));
uint32_t guid3 = (uint32_t)read_32bitBE(current_chunk+0x28,streamFile); uint32_t guid3 = (uint32_t)read_32bitBE(current_chunk+0x28,sf);
uint32_t guid4 = (uint32_t)read_32bitBE(current_chunk+0x2c,streamFile); uint32_t guid4 = (uint32_t)read_32bitBE(current_chunk+0x2c,sf);
//;VGM_LOG("RIFF: guid %08x %08x %08x %08x\n", guid1, guid2, guid3, guid4); //;VGM_LOG("RIFF: guid %08x %08x %08x %08x\n", guid1, guid2, guid3, guid4);
/* PCM GUID (0x00000001,0000,0010,80,00,00,AA,00,38,9B,71) */ /* PCM GUID (0x00000001,0000,0010,80,00,00,AA,00,38,9B,71) */
@ -255,7 +255,7 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
/* ATRAC3plus GUID (0xE923AABF,CB58,4471,A1,19,FF,FA,01,E4,CE,62) */ /* ATRAC3plus GUID (0xE923AABF,CB58,4471,A1,19,FF,FA,01,E4,CE,62) */
if (guid1 == 0xE923AABF && guid2 == 0xCB584471 && guid3 == 0xA119FFFA && guid4 == 0x01E4CE62) { if (guid1 == 0xE923AABF && guid2 == 0xCB584471 && guid3 == 0xA119FFFA && guid4 == 0x01E4CE62) {
#ifdef VGM_USE_MAIATRAC3PLUS #ifdef VGM_USE_MAIATRAC3PLUS
uint16_t bztmp = read_16bit(current_chunk+0x32,streamFile); uint16_t bztmp = read_16bit(current_chunk+0x32,sf);
bztmp = (bztmp >> 8) | (bztmp << 8); bztmp = (bztmp >> 8) | (bztmp << 8);
fmt->coding_type = coding_AT3plus; fmt->coding_type = coding_AT3plus;
fmt->block_size = (bztmp & 0x3FF) * 8 + 8; /* should match fmt->block_size */ fmt->block_size = (bztmp & 0x3FF) * 8 + 8; /* should match fmt->block_size */
@ -294,12 +294,12 @@ fail:
return 0; return 0;
} }
static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* streamFile, riff_fmt_chunk* fmt, int fact_sample_count, off_t start_offset); static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* sf, riff_fmt_chunk* fmt, int fact_sample_count, off_t start_offset);
static size_t get_ue4_msadpcm_interleave(STREAMFILE *sf, riff_fmt_chunk *fmt, off_t start, size_t size); static size_t get_ue4_msadpcm_interleave(STREAMFILE* sf, riff_fmt_chunk* fmt, off_t start, size_t size);
VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
riff_fmt_chunk fmt = {0}; riff_fmt_chunk fmt = {0};
size_t file_size, riff_size, data_size = 0; size_t file_size, riff_size, data_size = 0;
@ -317,7 +317,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
int FormatChunkFound = 0, DataChunkFound = 0, JunkFound = 0; int FormatChunkFound = 0, DataChunkFound = 0, JunkFound = 0;
int mwv = 0; /* Level-5 .mwv (Dragon Quest VIII, Rogue Galaxy) */ int mwv = 0;
off_t mwv_pflt_offset = -1; off_t mwv_pflt_offset = -1;
off_t mwv_ctrl_offset = -1; off_t mwv_ctrl_offset = -1;
@ -346,11 +346,12 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
* .aud: EA Replay ATRAC3 * .aud: EA Replay ATRAC3
* .at9: standard ATRAC9 * .at9: standard ATRAC9
* .saf: Whacked! (Xbox) * .saf: Whacked! (Xbox)
* .mwv: Level-5 games [Dragon Quest VIII (PS2), Rogue Galaxy (PS2)]
*/ */
if ( check_extensions(streamFile, "wav,lwav,xwav,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv,wvx,str,at3,rws,aud,at9,saf") ) { if ( check_extensions(sf, "wav,lwav,xwav,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv,wvx,str,at3,rws,aud,at9,saf") ) {
; ;
} }
else if ( check_extensions(streamFile, "mwv") ) { else if ( check_extensions(sf, "mwv") ) {
mwv = 1; mwv = 1;
} }
else { else {
@ -358,56 +359,72 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
} }
/* check header */ /* check header */
if (read_32bitBE(0x00,streamFile) != 0x52494646) /* "RIFF" */ if (read_32bitBE(0x00,sf) != 0x52494646) /* "RIFF" */
goto fail; goto fail;
if (read_32bitBE(0x08,streamFile) != 0x57415645) /* "WAVE" */ if (read_32bitBE(0x08,sf) != 0x57415645) /* "WAVE" */
goto fail; goto fail;
riff_size = read_32bitLE(0x04,streamFile); riff_size = read_32bitLE(0x04,sf);
file_size = get_streamfile_size(streamFile); file_size = get_streamfile_size(sf);
/* 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 */
{ if (file_size != riff_size + 0x08) {
uint16_t codec = read_16bitLE(0x14,streamFile); uint16_t codec = read_16bitLE(0x14,sf);
if (riff_size+0x08+0x01 == file_size)
riff_size += 0x01; /* [Shikkoku no Sharnoth (PC)] */
else if (riff_size == file_size && codec == 0x0069) if (codec == 0x6771 && riff_size + 0x08 + 0x01 == file_size)
riff_size += 0x01; /* [Shikkoku no Sharnoth (PC)] (Sony Sound Forge?) */
else if (codec == 0x0069 && riff_size == file_size)
riff_size -= 0x08; /* [Dynasty Warriors 3 (Xbox), BloodRayne (Xbox)] */ riff_size -= 0x08; /* [Dynasty Warriors 3 (Xbox), BloodRayne (Xbox)] */
else if (riff_size + 0x04 == file_size && codec == 0x0069) else if (codec == 0x0069 && riff_size + 0x04 == file_size)
riff_size -= 0x04; /* [Halo 2 (PC)] (possibly bad extractor? 'Gravemind Tool') */ riff_size -= 0x04; /* [Halo 2 (PC)] (possibly bad extractor? 'Gravemind Tool') */
else if (riff_size + 0x04 == file_size && codec == 0x0000) else if (codec == 0x0000 && riff_size + 0x04 == file_size)
riff_size -= 0x04; /* [Headhunter (DC), Bomber hehhe (DC)] */ riff_size -= 0x04; /* [Headhunter (DC), Bomber hehhe (DC)] */
else if (riff_size == file_size && codec == 0x0000) else if (codec == 0x0000 && riff_size == file_size)
riff_size -= 0x08; /* [Rayman 2 (DC)] */ riff_size -= 0x08; /* [Rayman 2 (DC)] */
else if (riff_size + 0x02 + 0x08 == file_size && codec == 0x0000) else if (codec == 0x0000 && riff_size + 0x08 + 0x02 == file_size)
riff_size -= 0x02; /* [Rayman 2 (DC)]-dcz */ riff_size -= 0x02; /* [Rayman 2 (DC)]-dcz */
else if (riff_size == file_size && codec == 0x0300) else if (codec == 0x0300 && riff_size == file_size)
riff_size -= 0x08; /* [Chrono Ma:gia (Android)] */ riff_size -= 0x08; /* [Chrono Ma:gia (Android)] */
else if (riff_size >= file_size && read_32bitBE(0x24,streamFile) == 0x4E584246) /* "NXBF" */ else if (codec == 0xFFFE && riff_size + 0x08 + 0x18 == file_size)
riff_size += 0x18; /* [F1 2011 (Vita)] (adds a "pada" chunk but RIFF size wasn't updated) */
else if (mwv) {
int channels = read_16bitLE(0x16, sf); /* [Dragon Quest VIII (PS2), Rogue Galaxy (PS2)] */
size_t file_size_fixed = riff_size + 0x08 + 0x04 * (channels - 1);
if (file_size_fixed <= file_size && file_size - file_size_fixed < 0x10)
{
/* files inside HD6/DAT are also padded to 0x10 so need to fix file_size */
file_size = file_size_fixed;
riff_size = file_size - 0x08;
}
}
else if (riff_size >= file_size && read_32bitBE(0x24,sf) == 0x4E584246) /* "NXBF" */
riff_size = file_size - 0x08; /* [R:Racing Evolution (Xbox)] */ riff_size = file_size - 0x08; /* [R:Racing Evolution (Xbox)] */
else if (riff_size / 4 + 0x4800 + 0x3c == file_size && codec == 0x0011) /* riff_size ~= data_size * 4, always has fact and 0x14 fmt */ else if (codec == 0x0011 && (riff_size / 2 / 2 == read_32bitLE(0x30,sf))) /* riff_size = pcm_size (always stereo, has fact at 0x30) */
riff_size = file_size - 0x08; /* [Asphalt 6 (iOS)] (sfx/memory wavs have ok sizes, only streaming wavs?) */ riff_size = file_size - 0x08; /* [Asphalt 6 (iOS)] (sfx/memory wavs have ok sizes?) */
} }
/* check for truncated RIFF */ /* check for truncated RIFF */
if (file_size < riff_size+0x08) if (file_size != riff_size + 0x08)
goto fail; goto fail;
/* read through chunks to verify format and find metadata */ /* read through chunks to verify format and find metadata */
{ {
off_t current_chunk = 0x0c; /* start with first chunk */ off_t current_chunk = 0x0c; /* start with first chunk */
while (current_chunk < file_size && current_chunk < riff_size+8) { while (current_chunk < file_size) {
uint32_t chunk_id = read_32bitBE(current_chunk + 0x00,streamFile); /* FOURCC */ uint32_t chunk_id = read_32bitBE(current_chunk + 0x00,sf); /* FOURCC */
size_t chunk_size = read_32bitLE(current_chunk + 0x04,streamFile); size_t chunk_size = read_32bitLE(current_chunk + 0x04,sf);
if (current_chunk + 0x08 + chunk_size > file_size) if (current_chunk + 0x08 + chunk_size > file_size)
goto fail; goto fail;
@ -417,7 +434,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
if (FormatChunkFound) goto fail; /* only one per file */ if (FormatChunkFound) goto fail; /* only one per file */
FormatChunkFound = 1; FormatChunkFound = 1;
if (!read_fmt(0, streamFile, current_chunk, &fmt, mwv)) if (!read_fmt(0, sf, current_chunk, &fmt, mwv))
goto fail; goto fail;
/* some Dreamcast/Naomi games again [Headhunter (DC), Bomber hehhe (DC), Rayman 2 (DC)] */ /* some Dreamcast/Naomi games again [Headhunter (DC), Bomber hehhe (DC), Rayman 2 (DC)] */
@ -434,11 +451,11 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
break; break;
case 0x4C495354: /* "LIST" */ case 0x4C495354: /* "LIST" */
switch (read_32bitBE(current_chunk+0x08, streamFile)) { switch (read_32bitBE(current_chunk+0x08, sf)) {
case 0x6164746C: /* "adtl" */ case 0x6164746C: /* "adtl" */
/* yay, atdl is its own little world */ /* yay, atdl is its own little world */
parse_adtl(current_chunk + 8, chunk_size, parse_adtl(current_chunk + 8, chunk_size,
streamFile, sf,
&loop_start_ms,&loop_end_ms,&loop_flag); &loop_start_ms,&loop_end_ms,&loop_flag);
break; break;
default: default:
@ -450,13 +467,13 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
/* check loop count/loop info (most common) */ /* check loop count/loop info (most common) */
/* 0x00: manufacturer id, 0x04: product id, 0x08: sample period, 0x0c: unity node, /* 0x00: manufacturer id, 0x04: product id, 0x08: sample period, 0x0c: unity node,
* 0x10: pitch fraction, 0x14: SMPTE format, 0x18: SMPTE offset, 0x1c: loop count, 0x20: sampler data */ * 0x10: pitch fraction, 0x14: SMPTE format, 0x18: SMPTE offset, 0x1c: loop count, 0x20: sampler data */
if (read_32bitLE(current_chunk+0x08+0x1c, streamFile) == 1) { /* handle only one loop (could contain N MIDILoop) */ if (read_32bitLE(current_chunk+0x08+0x1c, sf) == 1) { /* handle only one loop (could contain N MIDILoop) */
/* 0x24: cue point id, 0x28: type (0=forward, 1=alternating, 2=backward) /* 0x24: cue point id, 0x28: type (0=forward, 1=alternating, 2=backward)
* 0x2c: start, 0x30: end, 0x34: fraction, 0x38: play count */ * 0x2c: start, 0x30: end, 0x34: fraction, 0x38: play count */
if (read_32bitLE(current_chunk+0x08+0x28, streamFile) == 0) { /* loop forward */ if (read_32bitLE(current_chunk+0x08+0x28, sf) == 0) { /* loop forward */
loop_flag = 1; loop_flag = 1;
loop_start_smpl = read_32bitLE(current_chunk+0x08+0x2c, streamFile); loop_start_smpl = read_32bitLE(current_chunk+0x08+0x2c, sf);
loop_end_smpl = read_32bitLE(current_chunk+0x08+0x30, streamFile) + 1; /* must add 1 as per spec (ok for standard WAV/AT3/AT9) */ loop_end_smpl = read_32bitLE(current_chunk+0x08+0x30, sf) + 1; /* must add 1 as per spec (ok for standard WAV/AT3/AT9) */
} }
} }
break; break;
@ -465,14 +482,14 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
/* check loop count/info (found in some Xbox games: Halo (non-looping), Dynasty Warriors 3, Crimson Sea) */ /* check loop count/info (found in some Xbox games: Halo (non-looping), Dynasty Warriors 3, Crimson Sea) */
/* 0x00: size, 0x04: unity note, 0x06: fine tune, 0x08: gain, 0x10: loop count */ /* 0x00: size, 0x04: unity note, 0x06: fine tune, 0x08: gain, 0x10: loop count */
if (chunk_size >= 0x24 if (chunk_size >= 0x24
&& read_32bitLE(current_chunk+0x08+0x00, streamFile) == 0x14 && read_32bitLE(current_chunk+0x08+0x00, sf) == 0x14
&& read_32bitLE(current_chunk+0x08+0x10, streamFile) > 0 && read_32bitLE(current_chunk+0x08+0x10, sf) > 0
&& read_32bitLE(current_chunk+0x08+0x14, streamFile) == 0x10) { && read_32bitLE(current_chunk+0x08+0x14, sf) == 0x10) {
/* 0x14: size, 0x18: loop type (0=forward, 1=release), 0x1c: loop start, 0x20: loop length */ /* 0x14: size, 0x18: loop type (0=forward, 1=release), 0x1c: loop start, 0x20: loop length */
if (read_32bitLE(current_chunk+0x08+0x18, streamFile) == 0) { /* loop forward */ if (read_32bitLE(current_chunk+0x08+0x18, sf) == 0) { /* loop forward */
loop_flag = 1; loop_flag = 1;
loop_start_wsmp = read_32bitLE(current_chunk+0x08+0x1c, streamFile); loop_start_wsmp = read_32bitLE(current_chunk+0x08+0x1c, sf);
loop_end_wsmp = read_32bitLE(current_chunk+0x08+0x20, streamFile); /* must not add 1 as per spec */ loop_end_wsmp = read_32bitLE(current_chunk+0x08+0x20, sf); /* must not add 1 as per spec */
loop_end_wsmp += loop_start_wsmp; loop_end_wsmp += loop_start_wsmp;
} }
} }
@ -480,24 +497,24 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
case 0x66616374: /* "fact" */ case 0x66616374: /* "fact" */
if (chunk_size == 0x04) { /* standard (usually for ADPCM, MS recommends to set for non-PCM codecs) */ if (chunk_size == 0x04) { /* standard (usually for ADPCM, MS recommends to set for non-PCM codecs) */
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile); fact_sample_count = read_32bitLE(current_chunk+0x08, sf);
} }
else if (chunk_size == 0x10 && read_32bitBE(current_chunk+0x08+0x04, streamFile) == 0x4C794E20) { /* "LyN " */ else if (chunk_size == 0x10 && read_32bitBE(current_chunk+0x08+0x04, sf) == 0x4C794E20) { /* "LyN " */
goto fail; /* parsed elsewhere */ goto fail; /* parsed elsewhere */
} }
else if ((fmt.is_at3 || fmt.is_at3p) && chunk_size == 0x08) { /* early AT3 (mainly PSP games) */ else if ((fmt.is_at3 || fmt.is_at3p) && chunk_size == 0x08) { /* early AT3 (mainly PSP games) */
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile); fact_sample_count = read_32bitLE(current_chunk+0x08, sf);
fact_sample_skip = read_32bitLE(current_chunk+0x0c, streamFile); /* base skip samples */ fact_sample_skip = read_32bitLE(current_chunk+0x0c, sf); /* base skip samples */
} }
else if ((fmt.is_at3 || fmt.is_at3p) && chunk_size == 0x0c) { /* late AT3 (mainly PS3 games and few PSP games) */ else if ((fmt.is_at3 || fmt.is_at3p) && chunk_size == 0x0c) { /* late AT3 (mainly PS3 games and few PSP games) */
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile); fact_sample_count = read_32bitLE(current_chunk+0x08, sf);
/* 0x0c: base skip samples, ignored by decoder */ /* 0x0c: base skip samples, ignored by decoder */
fact_sample_skip = read_32bitLE(current_chunk+0x10, streamFile); /* skip samples with extra 184 */ fact_sample_skip = read_32bitLE(current_chunk+0x10, sf); /* skip samples with extra 184 */
} }
else if (fmt.is_at9 && chunk_size == 0x0c) { else if (fmt.is_at9 && chunk_size == 0x0c) {
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile); fact_sample_count = read_32bitLE(current_chunk+0x08, sf);
/* 0x0c: base skip samples (same as next field) */ /* 0x0c: base skip samples (same as next field) */
fact_sample_skip = read_32bitLE(current_chunk+0x10, streamFile); fact_sample_skip = read_32bitLE(current_chunk+0x10, sf);
} }
break; break;
@ -508,18 +525,18 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
case 0x6374726c: /* "ctrl" (.mwv extension) */ case 0x6374726c: /* "ctrl" (.mwv extension) */
if (!mwv) break; if (!mwv) break;
loop_flag = read_32bitLE(current_chunk+0x08, streamFile); loop_flag = read_32bitLE(current_chunk+0x08, sf);
mwv_ctrl_offset = current_chunk; mwv_ctrl_offset = current_chunk;
break; break;
case 0x63756520: /* "cue " (used in Source Engine for storing loop points) */ case 0x63756520: /* "cue " (used in Source Engine for storing loop points) */
if (fmt.coding_type == coding_PCM16LE || fmt.coding_type == coding_MSADPCM) { if (fmt.coding_type == coding_PCM16LE || fmt.coding_type == coding_MSADPCM) {
uint32_t num_cues = read_32bitLE(current_chunk + 0x08, streamFile); uint32_t num_cues = read_32bitLE(current_chunk + 0x08, sf);
if (num_cues > 0) { if (num_cues > 0) {
/* The second cue sets loop end point but it's not actually used by the engine. */ /* The second cue sets loop end point but it's not actually used by the engine. */
loop_flag = 1; loop_flag = 1;
loop_start_cue = read_32bitLE(current_chunk + 0x20, streamFile); loop_start_cue = read_32bitLE(current_chunk + 0x20, sf);
} }
} }
break; break;
@ -531,7 +548,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
/* 0x08: data size */ /* 0x08: data size */
/* 0x0c: channels */ /* 0x0c: channels */
/* 0x10: null */ /* 0x10: null */
loop_start_nxbf = read_32bitLE(current_chunk + 0x08 + 0x14, streamFile); loop_start_nxbf = read_32bitLE(current_chunk + 0x08 + 0x14, sf);
/* 0x18: sample rate */ /* 0x18: sample rate */
/* 0x1c: volume? (0x3e8 = 1000 = max) */ /* 0x1c: volume? (0x3e8 = 1000 = max) */
/* 0x20: type/flags? */ /* 0x20: type/flags? */
@ -569,20 +586,20 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
* As JUNK is legal (if unusual) we only reject those codecs. * As JUNK is legal (if unusual) we only reject those codecs.
* (ex. Cave PC games have PCM16LE + JUNK + smpl created by "Samplitude software") */ * (ex. Cave PC games have PCM16LE + JUNK + smpl created by "Samplitude software") */
if (JunkFound if (JunkFound
&& check_extensions(streamFile,"wav,lwav") /* for some .MED IMA */ && check_extensions(sf,"wav,lwav") /* for some .MED IMA */
&& (fmt.coding_type==coding_MSADPCM /*|| fmt.coding_type==coding_MS_IMA*/ || fmt.coding_type==coding_XBOX_IMA)) && (fmt.coding_type==coding_MSADPCM /*|| fmt.coding_type==coding_MS_IMA*/ || fmt.coding_type==coding_XBOX_IMA))
goto fail; goto fail;
/* ignore Beyond Good & Evil HD PS3 evil reuse of PCM codec */ /* ignore Beyond Good & Evil HD PS3 evil reuse of PCM codec */
if (fmt.coding_type == coding_PCM16LE && if (fmt.coding_type == coding_PCM16LE &&
read_32bitBE(start_offset+0x00, streamFile) == 0x4D534643 && /* "MSF\43" */ read_32bitBE(start_offset+0x00, sf) == 0x4D534643 && /* "MSF\43" */
read_32bitBE(start_offset+0x34, streamFile) == 0xFFFFFFFF && /* always */ read_32bitBE(start_offset+0x34, sf) == 0xFFFFFFFF && /* always */
read_32bitBE(start_offset+0x38, streamFile) == 0xFFFFFFFF && read_32bitBE(start_offset+0x38, sf) == 0xFFFFFFFF &&
read_32bitBE(start_offset+0x3c, streamFile) == 0xFFFFFFFF) read_32bitBE(start_offset+0x3c, sf) == 0xFFFFFFFF)
goto fail; goto fail;
/* ignore Gitaroo Man Live! (PSP) multi-RIFF (to allow chunked TXTH) */ /* ignore Gitaroo Man Live! (PSP) multi-RIFF (to allow chunked TXTH) */
if (fmt.is_at3 && get_streamfile_size(streamFile) > 0x2800 && read_32bitBE(0x2800, streamFile) == 0x52494646) { /* "RIFF" */ if (fmt.is_at3 && get_streamfile_size(sf) > 0x2800 && read_32bitBE(0x2800, sf) == 0x52494646) { /* "RIFF" */
goto fail; goto fail;
} }
@ -647,17 +664,17 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
{ {
int i, ch; int i, ch;
const int filter_order = 3; const int filter_order = 3;
int filter_count = read_32bitLE(mwv_pflt_offset+0x0c, streamFile); int filter_count = read_32bitLE(mwv_pflt_offset+0x0c, sf);
if (filter_count > 0x20) goto fail; if (filter_count > 0x20) goto fail;
if (mwv_pflt_offset == -1 || if (mwv_pflt_offset == -1 ||
read_32bitLE(mwv_pflt_offset+0x08, streamFile) != filter_order || read_32bitLE(mwv_pflt_offset+0x08, sf) != filter_order ||
read_32bitLE(mwv_pflt_offset+0x04, streamFile) < 8 + filter_count * 4 * filter_order) read_32bitLE(mwv_pflt_offset+0x04, sf) < 8 + filter_count * 4 * filter_order)
goto fail; goto fail;
for (ch = 0; ch < fmt.channel_count; ch++) { for (ch = 0; ch < fmt.channel_count; ch++) {
for (i = 0; i < filter_count * filter_order; i++) { for (i = 0; i < filter_count * filter_order; i++) {
int coef = read_32bitLE(mwv_pflt_offset+0x10+i*0x04, streamFile); int coef = read_32bitLE(mwv_pflt_offset+0x10+i*0x04, sf);
vgmstream->ch[ch].adpcm_coef_3by32[i] = coef; vgmstream->ch[ch].adpcm_coef_3by32[i] = coef;
} }
} }
@ -697,7 +714,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
case coding_FFmpeg: { case coding_FFmpeg: {
if (!fmt.is_at3 && !fmt.is_at3p) goto fail; if (!fmt.is_at3 && !fmt.is_at3p) goto fail;
vgmstream->codec_data = init_ffmpeg_atrac3_riff(streamFile, 0x00, NULL); vgmstream->codec_data = init_ffmpeg_atrac3_riff(sf, 0x00, NULL);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->num_samples = fact_sample_count; vgmstream->num_samples = fact_sample_count;
@ -730,7 +747,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
atrac9_config cfg = {0}; atrac9_config cfg = {0};
cfg.channels = vgmstream->channels; cfg.channels = vgmstream->channels;
cfg.config_data = read_32bitBE(fmt.offset+0x08+0x2c,streamFile); cfg.config_data = read_32bitBE(fmt.offset+0x08+0x2c,sf);
cfg.encoder_delay = fact_sample_skip; cfg.encoder_delay = fact_sample_skip;
vgmstream->codec_data = init_atrac9(&cfg); vgmstream->codec_data = init_atrac9(&cfg);
@ -749,7 +766,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
case coding_OGG_VORBIS: { case coding_OGG_VORBIS: {
/* special handling of Liar-soft's buggy RIFF+Ogg made with Soundforge [Shikkoku no Sharnoth (PC)] */ /* special handling of Liar-soft's buggy RIFF+Ogg made with Soundforge [Shikkoku no Sharnoth (PC)] */
STREAMFILE *temp_sf = setup_riff_ogg_streamfile(streamFile, start_offset, data_size); STREAMFILE *temp_sf = setup_riff_ogg_streamfile(sf, start_offset, data_size);
if (!temp_sf) goto fail; if (!temp_sf) goto fail;
vgmstream->codec_data = init_ogg_vorbis(temp_sf, 0x00, get_streamfile_size(temp_sf), NULL); vgmstream->codec_data = init_ogg_vorbis(temp_sf, 0x00, get_streamfile_size(temp_sf), NULL);
@ -766,13 +783,13 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
} }
/* UE4 uses interleaved mono MSADPCM, try to autodetect without breaking normal MSADPCM */ /* UE4 uses interleaved mono MSADPCM, try to autodetect without breaking normal MSADPCM */
if (fmt.coding_type == coding_MSADPCM && is_ue4_msadpcm(vgmstream, streamFile, &fmt, fact_sample_count, start_offset)) { if (fmt.coding_type == coding_MSADPCM && is_ue4_msadpcm(vgmstream, sf, &fmt, fact_sample_count, start_offset)) {
vgmstream->coding_type = coding_MSADPCM_int; vgmstream->coding_type = coding_MSADPCM_int;
vgmstream->frame_size = fmt.block_size; vgmstream->frame_size = fmt.block_size;
vgmstream->layout_type = layout_interleave; vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = get_ue4_msadpcm_interleave(streamFile, &fmt, start_offset, data_size); vgmstream->interleave_block_size = get_ue4_msadpcm_interleave(sf, &fmt, start_offset, data_size);
if (fmt.size == 0x36) if (fmt.size == 0x36)
vgmstream->num_samples = read_s32le(fmt.offset+0x08+0x32, streamFile); vgmstream->num_samples = read_s32le(fmt.offset+0x08+0x32, sf);
} }
/* Dynasty Warriors 5 (Xbox) 6ch interleaves stereo frames, probably not official */ /* Dynasty Warriors 5 (Xbox) 6ch interleaves stereo frames, probably not official */
@ -807,7 +824,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_RIFF_WAVE_wsmp; vgmstream->meta_type = meta_RIFF_WAVE_wsmp;
} }
else if (mwv && mwv_ctrl_offset != -1) { else if (mwv && mwv_ctrl_offset != -1) {
vgmstream->loop_start_sample = read_32bitLE(mwv_ctrl_offset+12, streamFile); vgmstream->loop_start_sample = read_32bitLE(mwv_ctrl_offset+12, sf);
vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->loop_end_sample = vgmstream->num_samples;
} }
else if (loop_start_cue != -1) { else if (loop_start_cue != -1) {
@ -827,7 +844,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_RIFF_WAVE_MWV; vgmstream->meta_type = meta_RIFF_WAVE_MWV;
} }
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail; goto fail;
return vgmstream; return vgmstream;
@ -838,14 +855,14 @@ fail:
} }
/* UE4 MSADPCM is quite normal but has a few minor quirks we can use to detect it */ /* UE4 MSADPCM is quite normal but has a few minor quirks we can use to detect it */
static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* streamFile, riff_fmt_chunk* fmt, int fact_sample_count, off_t start) { static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* sf, riff_fmt_chunk* fmt, int fact_sample_count, off_t start) {
/* multichannel ok */ /* multichannel ok */
if (fmt->channel_count < 2) if (fmt->channel_count < 2)
goto fail; goto fail;
/* UE4 class is "ADPCM", assume it's the extension too */ /* UE4 class is "ADPCM", assume it's the extension too */
if (!check_extensions(streamFile, "adpcm")) if (!check_extensions(sf, "adpcm"))
goto fail; goto fail;
/* UE4 encoder doesn't add "fact" */ /* UE4 encoder doesn't add "fact" */
@ -864,13 +881,13 @@ static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* streamFile, riff_fmt
if (fmt->size == 0x32) { if (fmt->size == 0x32) {
off_t offset = start; off_t offset = start;
off_t max_offset = 5 * fmt->block_size; /* try N blocks */ off_t max_offset = 5 * fmt->block_size; /* try N blocks */
if (max_offset > get_streamfile_size(streamFile)) if (max_offset > get_streamfile_size(sf))
max_offset = get_streamfile_size(streamFile); max_offset = get_streamfile_size(sf);
/* their encoder doesn't calculate optimal coefs and uses fixed values every frame /* their encoder doesn't calculate optimal coefs and uses fixed values every frame
* (could do it for fmt size 0x36 too but maybe they'll fix it in the future) */ * (could do it for fmt size 0x36 too but maybe they'll fix it in the future) */
while (offset <= max_offset) { while (offset <= max_offset) {
if (read_8bit(offset+0x00, streamFile) != 0 || read_16bitLE(offset+0x01, streamFile) != 0x00E6) if (read_8bit(offset+0x00, sf) != 0 || read_16bitLE(offset+0x01, sf) != 0x00E6)
goto fail; goto fail;
offset += fmt->block_size; offset += fmt->block_size;
} }
@ -883,7 +900,7 @@ fail:
/* for maximum annoyance later UE4 versions (~v4.2x?) interleave single frames instead of /* for maximum annoyance later UE4 versions (~v4.2x?) interleave single frames instead of
* half interleave, but don't have flags to detect so we need some heuristics */ * half interleave, but don't have flags to detect so we need some heuristics */
static size_t get_ue4_msadpcm_interleave(STREAMFILE *sf, riff_fmt_chunk *fmt, off_t start, size_t size) { static size_t get_ue4_msadpcm_interleave(STREAMFILE* sf, riff_fmt_chunk* fmt, off_t start, size_t size) {
size_t v1_interleave = size / fmt->channel_count; size_t v1_interleave = size / fmt->channel_count;
size_t v2_interleave = fmt->block_size; size_t v2_interleave = fmt->block_size;
uint8_t nibbles1[0x08] = {0}; uint8_t nibbles1[0x08] = {0};
@ -940,8 +957,8 @@ static size_t get_ue4_msadpcm_interleave(STREAMFILE *sf, riff_fmt_chunk *fmt, of
} }
/* same but big endian, seen in the spec and in Kitchenette (PC) (possibly from Adobe Director) */ /* same but big endian, seen in the spec and in Kitchenette (PC) (possibly from Adobe Director) */
VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_rifx(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
riff_fmt_chunk fmt = {0}; riff_fmt_chunk fmt = {0};
size_t file_size, riff_size, data_size = 0; size_t file_size, riff_size, data_size = 0;
@ -955,17 +972,17 @@ VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
/* check extension, case insensitive */ /* check extension, case insensitive */
if ( !check_extensions(streamFile, "wav,lwav") ) if ( !check_extensions(sf, "wav,lwav") )
goto fail; goto fail;
/* check header */ /* check header */
if (read_32bitBE(0x00,streamFile) != 0x52494658) /* "RIFX" */ if (read_32bitBE(0x00,sf) != 0x52494658) /* "RIFX" */
goto fail; goto fail;
if (read_32bitBE(0x08,streamFile) != 0x57415645) /* "WAVE" */ if (read_32bitBE(0x08,sf) != 0x57415645) /* "WAVE" */
goto fail; goto fail;
riff_size = read_32bitBE(0x04,streamFile); riff_size = read_32bitBE(0x04,sf);
file_size = get_streamfile_size(streamFile); file_size = get_streamfile_size(sf);
/* check for truncated RIFF */ /* check for truncated RIFF */
if (file_size < riff_size+8) goto fail; if (file_size < riff_size+8) goto fail;
@ -975,8 +992,8 @@ VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
off_t current_chunk = 0xc; /* start with first chunk */ off_t current_chunk = 0xc; /* start with first chunk */
while (current_chunk < file_size && current_chunk < riff_size+8) { while (current_chunk < file_size && current_chunk < riff_size+8) {
uint32_t chunk_type = read_32bitBE(current_chunk,streamFile); uint32_t chunk_type = read_32bitBE(current_chunk,sf);
off_t chunk_size = read_32bitBE(current_chunk+4,streamFile); off_t chunk_size = read_32bitBE(current_chunk+4,sf);
if (current_chunk+8+chunk_size > file_size) goto fail; if (current_chunk+8+chunk_size > file_size) goto fail;
@ -986,7 +1003,7 @@ VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
if (FormatChunkFound) goto fail; if (FormatChunkFound) goto fail;
FormatChunkFound = 1; FormatChunkFound = 1;
if (!read_fmt(1, streamFile, current_chunk, &fmt, 0)) if (!read_fmt(1, sf, current_chunk, &fmt, 0))
goto fail; goto fail;
break; break;
@ -1000,11 +1017,11 @@ VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
break; break;
case 0x736D706C: /* smpl */ case 0x736D706C: /* smpl */
/* check loop count and loop info */ /* check loop count and loop info */
if (read_32bitBE(current_chunk+0x24, streamFile)==1) { if (read_32bitBE(current_chunk+0x24, sf)==1) {
if (read_32bitBE(current_chunk+0x2c+4, streamFile)==0) { if (read_32bitBE(current_chunk+0x2c+4, sf)==0) {
loop_flag = 1; loop_flag = 1;
loop_start_offset = read_32bitBE(current_chunk+0x2c+8, streamFile); loop_start_offset = read_32bitBE(current_chunk+0x2c+8, sf);
loop_end_offset = read_32bitBE(current_chunk+0x2c+0xc,streamFile) + 1; loop_end_offset = read_32bitBE(current_chunk+0x2c+0xc,sf) + 1;
} }
} }
break; break;
@ -1062,7 +1079,7 @@ VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
} }
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) ) if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail; goto fail;
return vgmstream; return vgmstream;

View file

@ -13,7 +13,7 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *streamFile) {
/* checks */ /* checks */
if (!check_extensions(streamFile,"rsd")) if (!check_extensions(streamFile,"rsd,rsp"))
goto fail; goto fail;
if ((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) != 0x52534400) /* "RSD\00" */ if ((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) != 0x52534400) /* "RSD\00" */
goto fail; goto fail;

View file

@ -1,100 +1,61 @@
#include "meta.h" #include "meta.h"
#include "../util.h"
#include "../coding/coding.h" #include "../coding/coding.h"
#include "../layout/layout.h"
#include "sab_streamfile.h"
static void get_stream_name(char * stream_name, STREAMFILE *streamFile, int target_stream); typedef struct {
int total_subsongs;
int target_subsong;
int is_stream;
int is_extra;
/* SAB - from Worms 4: Mayhem (PC/Xbox/PS2) */ uint32_t flags;
VGMSTREAM * init_vgmstream_sab(STREAMFILE *streamFile) { uint32_t sound_count;
VGMSTREAM * vgmstream = NULL; uint32_t block_size;
off_t start_offset;
int loop_flag, channel_count = 0, is_stream, align, codec, sample_rate, stream_size, loop_start, loop_end;
int total_subsongs, target_subsong = streamFile->stream_index;
/* .sab: main, .sob: config/names */ uint32_t codec;
if (!check_extensions(streamFile,"sab")) int loop_flag;
int channel_count;
int sample_rate;
uint32_t stream_size;
int32_t loop_start;
int32_t loop_end;
off_t stream_offset;
} sab_header;
static int parse_sab(STREAMFILE* sf, sab_header* sab);
static VGMSTREAM* build_layered_vgmstream(STREAMFILE* sf, sab_header* sab);
static void get_stream_name(char* stream_name, STREAMFILE* sf, int target_stream);
/* SAB - from Sensaura GameCODA middleware games [Men of Valor (multi), Worms 4: Mayhem (multi), Just Cause (multi)] */
VGMSTREAM* init_vgmstream_sab(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
sab_header sab = {0};
/* .sab: main, .sob: cue (has config/names) */
if (!check_extensions(sf,"sab"))
goto fail; goto fail;
if (read_32bitBE(0x00,streamFile) != 0x43535732 && /* "CSW2" (Windows) */ if (read_u32be(0x00,sf) != 0x43535732 && /* "CSW2" (Windows) */
read_32bitBE(0x00,streamFile) != 0x43535032 && /* "CSP2" (PS2) */ read_u32be(0x00,sf) != 0x43535032 && /* "CSP2" (PS2) */
read_32bitBE(0x00,streamFile) != 0x43535832) /* "CSX2" (Xbox) */ read_u32be(0x00,sf) != 0x43535832) /* "CSX2" (Xbox) */
goto fail; goto fail;
is_stream = read_32bitLE(0x04,streamFile) & 0x04; /* other flags don't seem to matter */ if (!parse_sab(sf, &sab))
total_subsongs = is_stream ? 1 : read_32bitLE(0x08,streamFile); goto fail;
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
align = read_32bitLE(0x0c,streamFile); /* doubles as interleave */ /* sab can be (both cases handled here):
* - bank: multiple subsongs (each a different header)
/* stream config */ * - stream: layers used as different stereo tracks (Men of Valor) or mono tracks to create stereo (Worms 4)
codec = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x00,streamFile); */
channel_count = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x04,streamFile); vgmstream = build_layered_vgmstream(sf, &sab);
sample_rate = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x08,streamFile);
stream_size = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x0c,streamFile);
loop_start = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x10,streamFile);
loop_end = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x14,streamFile);
loop_flag = (loop_end > 0);
start_offset = 0x18 + 0x1c*total_subsongs;
if (start_offset % align)
start_offset += align - (start_offset % align);
start_offset += read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x18,streamFile);
if (is_stream) {
channel_count = read_32bitLE(0x08,streamFile); /* uncommon, but non-stream stereo exists */
stream_size *= channel_count;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate; vgmstream->num_streams = sab.total_subsongs;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_SAB;
switch(codec) { get_stream_name(vgmstream->stream_name, sf, sab.target_subsong);
case 0x01: /* PC */
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = is_stream ? align : 0x02;
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, vgmstream->channels, 16);
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, vgmstream->channels, 16);
vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_end, vgmstream->channels, 16);
break;
case 0x04: /* PS2 */
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = is_stream ? align : 0x10;
vgmstream->num_samples = ps_bytes_to_samples(stream_size, vgmstream->channels);
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, vgmstream->channels);
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, vgmstream->channels);
break;
case 0x08: /* Xbox */
vgmstream->coding_type = is_stream ? coding_XBOX_IMA_int : coding_XBOX_IMA;
vgmstream->layout_type = is_stream ? layout_interleave : layout_none;
vgmstream->interleave_block_size = is_stream ? align : 0x00;
vgmstream->num_samples = xbox_ima_bytes_to_samples(stream_size, vgmstream->channels);
vgmstream->loop_start_sample = xbox_ima_bytes_to_samples(loop_start, vgmstream->channels);
vgmstream->loop_end_sample = xbox_ima_bytes_to_samples(loop_end, vgmstream->channels);
break;
default:
VGM_LOG("SAB: unknown codec\n");
goto fail;
}
get_stream_name(vgmstream->stream_name, streamFile, target_subsong);
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream; return vgmstream;
fail: fail:
@ -102,32 +63,38 @@ fail:
return NULL; return NULL;
} }
/* multiple streams may share a name, also sometimes won't a the name */ //todo doesn't seem correct always (also multiple .sob may share .sab)
static void get_stream_name(char * stream_name, STREAMFILE *streamFile, int target_stream) { /* multiple streams may share a name */
STREAMFILE * streamInfo = NULL; static void get_stream_name(char* stream_name, STREAMFILE* sf, int target_stream) {
STREAMFILE* sf_info = NULL;
int i, j, total_cues, num_cue = -1; int i, j, total_cues, num_cue = -1;
size_t name_size = 0; size_t name_size = 0;
off_t name_offset = 0x10; off_t name_offset = 0x10;
streamInfo = open_streamfile_by_ext(streamFile, "sob"); sf_info = open_streamfile_by_ext(sf, "sob");
if (!streamInfo) goto end; if (!sf_info) goto end;
if (read_32bitBE(0x00,streamInfo) != 0x43544632) /* "CTF2" */ if (read_u32be(0x00,sf_info) != 0x43544632) /* "CTF2" */
goto end; goto end;
total_cues = read_32bitLE(0x08,streamInfo); total_cues = read_u32le(0x08,sf_info);
if (total_cues > 0x1000)
goto end;
for (i = 0; i < total_cues; i++) { for (i = 0; i < total_cues; i++) {
uint32_t flags, num_subsections, subsection_1_size, subsection_2_size; uint32_t flags, num_subsections, subsection_1_size, subsection_2_size;
flags = (uint32_t)read_32bitLE(name_offset + 0x00,streamInfo); flags = read_u32le(name_offset + 0x00,sf_info);
num_subsections = (uint32_t)read_32bitLE(name_offset + 0x20,streamInfo); num_subsections = read_u32le(name_offset + 0x20,sf_info);
subsection_1_size = (flags & 0x00000001) ? 0x40 : 0x00; subsection_1_size = (flags & 0x00000001) ? 0x40 : 0x00;
subsection_1_size +=(flags & 0x00000040) ? 0x20 : 0x00; subsection_1_size +=(flags & 0x00000040) ? 0x20 : 0x00;
subsection_2_size = (flags & 0x00000100) ? 0x1c : 0x10; subsection_2_size = (flags & 0x00000100) ? 0x1c : 0x10; //todo not always correct
if (num_subsections > 0x1000)
goto end; /* bad read */
for (j = 0; j < num_subsections; j++) { for (j = 0; j < num_subsections; j++) {
int num_stream = read_32bitLE(name_offset + 0x2c + subsection_1_size + j*subsection_2_size + 0x08,streamInfo); int num_stream = read_u32le(name_offset + 0x2c + subsection_1_size + j*subsection_2_size + 0x08,sf_info);
if (target_stream-1 == num_stream) if (target_stream - 1 == num_stream)
num_cue = i; num_cue = i;
} }
@ -138,7 +105,7 @@ static void get_stream_name(char * stream_name, STREAMFILE *streamFile, int targ
for (i = 0; i < total_cues; i++) { for (i = 0; i < total_cues; i++) {
/* 0x00: id */ /* 0x00: id */
name_size = read_32bitLE(name_offset + 0x04,streamInfo); /* non null-terminated */ name_size = read_u32le(name_offset + 0x04,sf_info); /* non null-terminated */
if (i == num_cue) { if (i == num_cue) {
name_offset += 0x08; name_offset += 0x08;
break; break;
@ -146,12 +113,164 @@ static void get_stream_name(char * stream_name, STREAMFILE *streamFile, int targ
name_offset += 0x08 + name_size; name_offset += 0x08 + name_size;
} }
if (name_size > STREAM_NAME_SIZE-1) if (name_size > STREAM_NAME_SIZE - 1)
name_size = STREAM_NAME_SIZE-1; name_size = STREAM_NAME_SIZE - 1;
read_string(stream_name,name_size+1, name_offset,streamInfo); read_string(stream_name,name_size+1, name_offset,sf_info);
end: end:
if (streamInfo) close_streamfile(sf_info);
close_streamfile(streamInfo); }
static int parse_sab(STREAMFILE* sf, sab_header* sab) {
off_t entry_offset;
sab->flags = read_u32le(0x04,sf); /* upper byte is always 0x02 (version?) */
sab->sound_count = read_u32le(0x08,sf);
sab->block_size = read_u32le(0x0c,sf);
/* 0x10: number of blocks */
/* 0x14: file id? */
sab->is_stream = sab->flags & 0x04; /* "not bank" */
sab->is_extra = sab->flags & 0x10; /* not used in Worms 4 */
/* flags 1/2 are also common, no flags in banks */
sab->total_subsongs = sab->is_stream ? 1 : sab->sound_count;
sab->target_subsong = sf->stream_index;
if (sab->target_subsong == 0) sab->target_subsong = 1;
if (sab->target_subsong < 0 || sab->target_subsong > sab->total_subsongs || sab->total_subsongs < 1) goto fail;
/* stream config */
entry_offset = 0x18 + 0x1c * (sab->target_subsong - 1);
sab->codec = read_u32le(entry_offset + 0x00,sf);
sab->channel_count = read_u32le(entry_offset + 0x04,sf);
sab->sample_rate = read_u32le(entry_offset + 0x08,sf);
sab->stream_size = read_u32le(entry_offset + 0x0c,sf);
sab->loop_start = read_u32le(entry_offset + 0x10,sf);
sab->loop_end = read_u32le(entry_offset + 0x14,sf);
sab->loop_flag = (sab->loop_end > 0);
if (sab->is_stream) {
sab->stream_offset = sab->block_size;
}
else {
sab->stream_offset = 0x18 + 0x1c * sab->total_subsongs;
if (sab->stream_offset % sab->block_size)
sab->stream_offset += sab->block_size - (sab->stream_offset % sab->block_size);
sab->stream_offset += read_u32le(0x18 + 0x1c * (sab->target_subsong - 1) + 0x18,sf);
}
/* some extra values (counts?) and name at start */
if (sab->is_extra)
sab->stream_offset += sab->block_size;
return 1;
fail:
return 0;
}
static VGMSTREAM* build_vgmstream(STREAMFILE* sf, sab_header* sab) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
/* in streams streamfile is de-chunked so start becomes 0 */
start_offset = sab->is_stream ?
0 :
sab->stream_offset;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(sab->channel_count, sab->loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sab->sample_rate;
vgmstream->stream_size = sab->stream_size;
vgmstream->meta_type = meta_SAB;
switch(sab->codec) {
case 0x01: /* PC */
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
vgmstream->num_samples = pcm_bytes_to_samples(sab->stream_size, vgmstream->channels, 16);
vgmstream->loop_start_sample = pcm_bytes_to_samples(sab->loop_start, vgmstream->channels, 16);
vgmstream->loop_end_sample = pcm_bytes_to_samples(sab->loop_end, vgmstream->channels, 16);
break;
case 0x04: /* PS2 */
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
vgmstream->num_samples = ps_bytes_to_samples(sab->stream_size, vgmstream->channels);
vgmstream->loop_start_sample = ps_bytes_to_samples(sab->loop_start, vgmstream->channels);
vgmstream->loop_end_sample = ps_bytes_to_samples(sab->loop_end, vgmstream->channels);
break;
case 0x08: /* Xbox */
vgmstream->coding_type = coding_XBOX_IMA;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = xbox_ima_bytes_to_samples(sab->stream_size, vgmstream->channels);
vgmstream->loop_start_sample = xbox_ima_bytes_to_samples(sab->loop_start, vgmstream->channels);
vgmstream->loop_end_sample = xbox_ima_bytes_to_samples(sab->loop_end, vgmstream->channels);
break;
default:
VGM_LOG("SAB: unknown codec\n");
goto fail;
}
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
static VGMSTREAM* build_layered_vgmstream(STREAMFILE* sf, sab_header* sab) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
layered_layout_data* data = NULL;
int i;
if (sab->sound_count == 1 || !sab->is_stream) {
return build_vgmstream(sf, sab);
}
/* init layout */
data = init_layout_layered(sab->sound_count);
if (!data) goto fail;
/* de-chunk audio layers */
for (i = 0; i < sab->sound_count; i++) {
temp_sf = setup_sab_streamfile(sf, sab->stream_offset, sab->sound_count, i, sab->block_size);
if (!temp_sf) goto fail;
data->layers[i] = build_vgmstream(temp_sf, sab);
if (!data->layers[i]) goto fail;
close_streamfile(temp_sf);
temp_sf = NULL;
}
/* setup VGMSTREAMs */
if (!setup_layout_layered(data))
goto fail;
/* build the layout VGMSTREAM */
vgmstream = allocate_layered_vgmstream(data);
if (!vgmstream) goto fail;
//sab->stream_size = sab->stream_size * sab->sound_count; /* ? */
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
if (!vgmstream)
free_layout_layered(data);
return NULL;
} }

View file

@ -0,0 +1,20 @@
#ifndef _SAB_STREAMFILE_H_
#define _SAB_STREAMFILE_H_
#include "deblock_streamfile.h"
static STREAMFILE* setup_sab_streamfile(STREAMFILE* sf, off_t stream_start, int stream_count, int stream_number, size_t interleave) {
STREAMFILE* new_sf = NULL;
deblock_config_t cfg = {0};
cfg.stream_start = stream_start;
cfg.chunk_size = interleave;
cfg.step_start = stream_number;
cfg.step_count = stream_count;
/* setup sf */
new_sf = open_wrap_streamfile(sf);
new_sf = open_io_deblock_streamfile_f(new_sf, &cfg);
return new_sf;
}
#endif /* _SAB_STREAMFILE_H_ */

View file

@ -3,36 +3,36 @@
/* SGXD - Sony/SCEI's format (SGB+SGH / SGD / SGX) */ /* SGXD - Sony/SCEI's format (SGB+SGH / SGD / SGX) */
VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_sgxd(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
STREAMFILE * streamHeader = NULL; STREAMFILE* sf_head = NULL;
off_t start_offset, data_offset, chunk_offset, name_offset = 0; off_t start_offset, data_offset, chunk_offset, name_offset = 0;
size_t stream_size; size_t stream_size;
int is_sgx, is_sgb = 0; int is_sgx, is_sgb = 0;
int loop_flag, channels, codec; int loop_flag, channels, codec;
int sample_rate, num_samples, loop_start_sample, loop_end_sample; int sample_rate, num_samples, loop_start_sample, loop_end_sample;
int total_subsongs, target_subsong = streamFile->stream_index; int total_subsongs, target_subsong = sf->stream_index;
/* check extension, case insensitive */ /* check extension, case insensitive */
/* .sgx: header+data (Genji), .sgd: header+data, .sgh/sgd: header/data */ /* .sgx: header+data (Genji), .sgd: header+data, .sgh/sgd: header/data */
if (!check_extensions(streamFile,"sgx,sgd,sgb")) if (!check_extensions(sf,"sgx,sgd,sgb"))
goto fail; goto fail;
is_sgx = check_extensions(streamFile,"sgx"); is_sgx = check_extensions(sf,"sgx");
is_sgb = check_extensions(streamFile,"sgb"); is_sgb = check_extensions(sf,"sgb");
/* SGB+SGH: use SGH as header; otherwise use the current file as header */ /* SGB+SGH: use SGH as header; otherwise use the current file as header */
if (is_sgb) { if (is_sgb) {
streamHeader = open_streamfile_by_ext(streamFile, "sgh"); sf_head = open_streamfile_by_ext(sf, "sgh");
if (!streamHeader) goto fail; if (!sf_head) goto fail;
} else { } else {
streamHeader = streamFile; sf_head = sf;
} }
/* SGXD base (size 0x10) */ /* SGXD base (size 0x10) */
if (read_32bitBE(0x00,streamHeader) != 0x53475844) /* "SGXD" */ if (read_32bitBE(0x00,sf_head) != 0x53475844) /* "SGXD" */
goto fail; goto fail;
/* 0x04 SGX: full header_size; SGD/SGH: unknown header_size (counting from 0x0/0x8/0x10, varies) */ /* 0x04 SGX: full header_size; SGD/SGH: unknown header_size (counting from 0x0/0x8/0x10, varies) */
/* 0x08 SGX: first chunk offset? (0x10); SGD/SGH: full header_size */ /* 0x08 SGX: first chunk offset? (0x10); SGD/SGH: full header_size */
@ -40,24 +40,24 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
if (is_sgb) { if (is_sgb) {
data_offset = 0x00; data_offset = 0x00;
} else if ( is_sgx ) { } else if ( is_sgx ) {
data_offset = read_32bitLE(0x04,streamHeader); data_offset = read_32bitLE(0x04,sf_head);
} else { } else {
data_offset = read_32bitLE(0x08,streamHeader); data_offset = read_32bitLE(0x08,sf_head);
} }
/* typical chunks: WAVE, RGND, NAME (strings for WAVE or RGND), SEQD (related to SFX), WSUR, WMKR, BUSS */ /* typical chunks: WAVE, RGND, NAME (strings for WAVE or RGND), SEQD (related to SFX), WSUR, WMKR, BUSS */
/* WAVE chunk (size 0x10 + files * 0x38 + optional padding) */ /* WAVE chunk (size 0x10 + files * 0x38 + optional padding) */
if (is_sgx) { /* position after chunk+size */ if (is_sgx) { /* position after chunk+size */
if (read_32bitBE(0x10,streamHeader) != 0x57415645) goto fail; /* "WAVE" */ if (read_32bitBE(0x10,sf_head) != 0x57415645) goto fail; /* "WAVE" */
chunk_offset = 0x18; chunk_offset = 0x18;
} else { } else {
if (!find_chunk_le(streamHeader, 0x57415645,0x10,0, &chunk_offset,NULL)) goto fail; /* "WAVE" */ if (!find_chunk_le(sf_head, 0x57415645,0x10,0, &chunk_offset,NULL)) goto fail; /* "WAVE" */
} }
/* 0x04 SGX: unknown; SGD/SGH: chunk length, 0x08 null */ /* 0x04 SGX: unknown; SGD/SGH: chunk length, 0x08 null */
/* check multi-streams (usually only SE containers; Puppeteer) */ /* check multi-streams (usually only SE containers; Puppeteer) */
total_subsongs = read_32bitLE(chunk_offset+0x04,streamHeader); total_subsongs = read_32bitLE(chunk_offset+0x04,sf_head);
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;
@ -68,11 +68,11 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
/* 0x00 ? (00/01/02) */ /* 0x00 ? (00/01/02) */
if (!is_sgx) /* meaning unknown in .sgx; offset 0 = not a stream (a RGND sample) */ if (!is_sgx) /* meaning unknown in .sgx; offset 0 = not a stream (a RGND sample) */
name_offset = read_32bitLE(chunk_offset+0x04,streamHeader); name_offset = read_32bitLE(chunk_offset+0x04,sf_head);
codec = read_8bit(chunk_offset+0x08,streamHeader); codec = read_8bit(chunk_offset+0x08,sf_head);
channels = read_8bit(chunk_offset+0x09,streamHeader); channels = read_8bit(chunk_offset+0x09,sf_head);
/* 0x0a null */ /* 0x0a null */
sample_rate = read_32bitLE(chunk_offset+0x0c,streamHeader); sample_rate = read_32bitLE(chunk_offset+0x0c,sf_head);
/* 0x10 info_type: meaning of the next value /* 0x10 info_type: meaning of the next value
* (00=null, 30/40=data size without padding (ADPCM, ATRAC3plus), 80/A0=block size (AC3) */ * (00=null, 30/40=data size without padding (ADPCM, ATRAC3plus), 80/A0=block size (AC3) */
@ -80,15 +80,15 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
/* 0x18 unknown (ex. 0x0008/0010/3307/CC02/etc)x2 */ /* 0x18 unknown (ex. 0x0008/0010/3307/CC02/etc)x2 */
/* 0x1c null */ /* 0x1c null */
num_samples = read_32bitLE(chunk_offset+0x20,streamHeader); num_samples = read_32bitLE(chunk_offset+0x20,sf_head);
loop_start_sample = read_32bitLE(chunk_offset+0x24,streamHeader); loop_start_sample = read_32bitLE(chunk_offset+0x24,sf_head);
loop_end_sample = read_32bitLE(chunk_offset+0x28,streamHeader); loop_end_sample = read_32bitLE(chunk_offset+0x28,sf_head);
stream_size = read_32bitLE(chunk_offset+0x2c,streamHeader); /* stream size (without padding) / interleave (for type3) */ stream_size = read_32bitLE(chunk_offset+0x2c,sf_head); /* stream size (without padding) / interleave (for type3) */
if (is_sgx) { if (is_sgx) {
stream_offset = 0x0; stream_offset = 0x0;
} else{ } else{
stream_offset = read_32bitLE(chunk_offset+0x30,streamHeader); stream_offset = read_32bitLE(chunk_offset+0x30,sf_head);
} }
/* 0x34 SGX: unknown; SGD/SGH: stream size (with padding) / interleave */ /* 0x34 SGX: unknown; SGD/SGH: stream size (with padding) / interleave */
@ -109,7 +109,7 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
vgmstream->stream_size = stream_size; vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_SGXD; vgmstream->meta_type = meta_SGXD;
if (name_offset) if (name_offset)
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamHeader); read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,sf_head);
switch (codec) { switch (codec) {
@ -121,7 +121,7 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
case 0x02: /* Ogg Vorbis [Ni no Kuni: Wrath of the White Witch Remastered (PC)] (codec hijack?) */ case 0x02: /* Ogg Vorbis [Ni no Kuni: Wrath of the White Witch Remastered (PC)] (codec hijack?) */
vgmstream->codec_data = init_ogg_vorbis(streamFile, start_offset, stream_size, NULL); vgmstream->codec_data = init_ogg_vorbis(sf, start_offset, stream_size, NULL);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_OGG_VORBIS; vgmstream->coding_type = coding_OGG_VORBIS;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
@ -143,7 +143,7 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
case 0x04: { /* ATRAC3plus [Kurohyo 1/2 (PSP), BraveStory (PSP)] */ case 0x04: { /* ATRAC3plus [Kurohyo 1/2 (PSP), BraveStory (PSP)] */
vgmstream->codec_data = init_ffmpeg_atrac3_riff(streamFile, start_offset, NULL); vgmstream->codec_data = init_ffmpeg_atrac3_riff(sf, start_offset, NULL);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
@ -163,20 +163,15 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
case 0x06: { /* AC3 [Tokyo Jungle (PS3), Afrika (PS3)] */ case 0x06: { /* AC3 [Tokyo Jungle (PS3), Afrika (PS3)] */
ffmpeg_codec_data *ffmpeg_data; vgmstream->codec_data = init_ffmpeg_offset(sf, start_offset, stream_size);
if (!vgmstream->codec_data) goto fail;
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, stream_size);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
/* manually set skip_samples if FFmpeg didn't do it */
if (ffmpeg_data->skipSamples <= 0) {
/* PS3 AC3 consistently has 256 encoder delay samples, and there are ~1000-2000 samples after num_samples. /* PS3 AC3 consistently has 256 encoder delay samples, and there are ~1000-2000 samples after num_samples.
* Skipping them marginally improves full loops in some Tokyo Jungle tracks (ex. a_1.sgd). */ * Skipping them marginally improves full loops in some Tokyo Jungle tracks (ex. a_1.sgd). */
ffmpeg_set_skip_samples(ffmpeg_data, 256); ffmpeg_set_skip_samples(vgmstream->codec_data, 256);
}
/* SGXD loop/sample values are relative (without skip samples), no need to adjust */ /* SGXD loop/sample values are relative (without skip samples), no need to adjust */
break; break;
@ -188,15 +183,14 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
goto fail; goto fail;
} }
/* open the file for reading */ if (!vgmstream_open_stream(vgmstream, sf, start_offset))
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail; goto fail;
if (is_sgb && streamHeader) close_streamfile(streamHeader); if (is_sgb && sf_head) close_streamfile(sf_head);
return vgmstream; return vgmstream;
fail: fail:
if (is_sgb && streamHeader) close_streamfile(streamHeader); if (is_sgb && sf_head) close_streamfile(sf_head);
close_vgmstream(vgmstream); close_vgmstream(vgmstream);
return NULL; return NULL;
} }

View file

@ -0,0 +1,29 @@
#include "meta.h"
/* silent stream - mainly for engines that need them or dummy subsongs */
VGMSTREAM* init_vgmstream_silence(int channels, int sample_rate, int32_t num_samples) {
VGMSTREAM* vgmstream = NULL;
if (channels <= 0)
channels = 2;
if (sample_rate <= 0)
sample_rate = 48000;
if (num_samples <= 0)
num_samples = 1.0 * sample_rate;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, 0);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_SILENCE;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->coding_type = coding_SILENCE;
vgmstream->layout_type = layout_none;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -241,22 +241,20 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
#ifdef VGM_USE_MPEG #ifdef VGM_USE_MPEG
case 0x07: { /* MPEG [Final Fantasy XIII (PS3)] */ case 0x07: { /* MPEG [Final Fantasy XIII (PS3)] */
mpeg_codec_data *mpeg_data = NULL;
mpeg_custom_config cfg = {0}; mpeg_custom_config cfg = {0};
cfg.interleave = 0x800; /* for multistream [Final Fantasy XIII-2 (PS3)], otherwise ignored */ cfg.interleave = 0x800; /* for multistream [Final Fantasy XIII-2 (PS3)], otherwise ignored */
cfg.data_size = stream_size; cfg.data_size = stream_size;
mpeg_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_SCD, &cfg); vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_SCD, &cfg);
if (!mpeg_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->codec_data = mpeg_data;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
/* some Drakengard 3, Kingdom Hearts HD have adjusted sample rate (47999, 44099), for looping? */ /* some Drakengard 3, Kingdom Hearts HD have adjusted sample rate (47999, 44099), for looping? */
vgmstream->num_samples = mpeg_bytes_to_samples(stream_size, mpeg_data); vgmstream->num_samples = mpeg_bytes_to_samples(stream_size, vgmstream->codec_data);
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data); vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, vgmstream->codec_data);
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data); vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, vgmstream->codec_data);
/* somehow loops offsets aren't always frame-aligned, and the code below supposedly helped, /* somehow loops offsets aren't always frame-aligned, and the code below supposedly helped,
* but there isn't much difference since MPEG loops are rough (1152-aligned). Seems it * but there isn't much difference since MPEG loops are rough (1152-aligned). Seems it

View file

@ -230,7 +230,6 @@ VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) {
#ifdef VGM_USE_MPEG #ifdef VGM_USE_MPEG
case 0x06: { /* MSMP3 (MSF subfile) [Dragon Quest Builders (PS3)] */ case 0x06: { /* MSMP3 (MSF subfile) [Dragon Quest Builders (PS3)] */
mpeg_codec_data *mpeg_data = NULL;
mpeg_custom_config cfg = {0}; mpeg_custom_config cfg = {0};
start_offset = sead.extradata_offset + sead.extradata_size; start_offset = sead.extradata_offset + sead.extradata_size;
@ -238,12 +237,11 @@ VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) {
/* extradata: */ /* extradata: */
/* proper MSF header, but sample rate/loops are ignored in favor of SAB's */ /* proper MSF header, but sample rate/loops are ignored in favor of SAB's */
mpeg_data = init_mpeg_custom(sf, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_STANDARD, &cfg); vgmstream->codec_data = init_mpeg_custom(sf, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_STANDARD, &cfg);
if (!mpeg_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->codec_data = mpeg_data;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
vgmstream->num_samples = mpeg_bytes_to_samples(sead.stream_size, mpeg_data); vgmstream->num_samples = mpeg_bytes_to_samples(sead.stream_size, vgmstream->codec_data);
vgmstream->loop_start_sample = sead.loop_start; vgmstream->loop_start_sample = sead.loop_start;
vgmstream->loop_end_sample = sead.loop_end; vgmstream->loop_end_sample = sead.loop_end;
break; break;

View file

@ -3,32 +3,31 @@
/* .STRM - from Abylight 3DS games [Cursed Castilla (3DS)] */ /* .STRM - from Abylight 3DS games [Cursed Castilla (3DS)] */
VGMSTREAM * init_vgmstream_strm_abylight(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_strm_abylight(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM * vgmstream = NULL;
off_t start_offset; off_t start_offset;
int loop_flag, channel_count, sample_rate; int loop_flag, channel_count, sample_rate;
size_t data_size; size_t data_size;
/* check extension */ /* checks */
if ( !check_extensions(streamFile,"strm") ) if ( !check_extensions(sf,"strm") )
goto fail; goto fail;
/* check header */ if (read_32bitBE(0x00,sf) != 0x5354524D) /* "STRM" */
if (read_32bitBE(0x00,streamFile) != 0x5354524D) /* "STRM" */
goto fail; goto fail;
if (read_32bitLE(0x04,streamFile) != 0x03E8) /* version 1000? */ if (read_32bitLE(0x04,sf) != 0x03E8) /* version 1000? */
goto fail; goto fail;
loop_flag = 0; loop_flag = 0;
channel_count = 2; /* there are various possible fields but all files are stereo */ channel_count = 2; /* there are various possible fields but all files are stereo */
sample_rate = read_32bitLE(0x08,streamFile); sample_rate = read_32bitLE(0x08,sf);
start_offset = 0x1e; start_offset = 0x1e;
data_size = read_32bitLE(0x10,streamFile); data_size = read_32bitLE(0x10,sf);
if (data_size != get_streamfile_size(streamFile) - start_offset) if (data_size != get_streamfile_size(sf) - start_offset)
goto fail; goto fail;
if (data_size != read_32bitLE(0x18,streamFile)) if (data_size != read_32bitLE(0x18,sf))
goto fail; goto fail;
@ -37,31 +36,26 @@ VGMSTREAM * init_vgmstream_strm_abylight(STREAMFILE *streamFile) {
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate; vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = aac_get_samples(streamFile, start_offset, data_size); vgmstream->num_samples = aac_get_samples(sf, start_offset, data_size);
vgmstream->meta_type = meta_STRM_ABYLIGHT; vgmstream->meta_type = meta_STRM_ABYLIGHT;
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
{ {
ffmpeg_codec_data *ffmpeg_data = NULL; vgmstream->codec_data = init_ffmpeg_offset(sf, start_offset, data_size);
if (!vgmstream->codec_data) goto fail;
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,data_size);
if (!ffmpeg_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
/* apparently none, or maybe ~600 */ /* apparently none, or maybe ~600 */
//if (!ffmpeg_data->skipSamples) //ffmpeg_set_skip_samples(ffmpeg_data, 1024);
// ffmpeg_set_skip_samples(ffmpeg_data, 1024);
//vgmstream->num_samples -= 1024; //vgmstream->num_samples -= 1024;
} }
#else #else
goto fail; goto fail;
#endif #endif
/* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, sf, start_offset) )
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail; goto fail;
return vgmstream; return vgmstream;

View file

@ -2,51 +2,54 @@
#include "../coding/coding.h" #include "../coding/coding.h"
/* SVAG - from Konami Tokyo games [OZ (PS2), Neo Contra (PS2), Silent Hill 2 (PS2)] */ /* SVAG - from Konami Tokyo games [OZ (PS2), Neo Contra (PS2), Silent Hill 2 (PS2)] */
VGMSTREAM * init_vgmstream_ps2_svag(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_svag_kcet(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
off_t start_offset; off_t start_offset;
size_t data_size; size_t data_size;
int loop_flag, channel_count; int loop_flag, channel_count;
/* checks */ /* checks */
if (!check_extensions(streamFile, "svag")) if (!check_extensions(sf, "svag"))
goto fail; goto fail;
if (read_32bitBE(0x00,streamFile) != 0x53766167) /* "Svag" */ if (read_32bitBE(0x00,sf) != 0x53766167) /* "Svag" */
goto fail; goto fail;
channel_count = read_16bitLE(0x0C,streamFile); /* always 2? ("S"tereo vag?) */ channel_count = read_16bitLE(0x0C,sf); /* always 2? ("S"tereo vag?) */
loop_flag = (read_32bitLE(0x14,streamFile)==1); loop_flag = (read_32bitLE(0x14,sf) ==1);
/* header repeated at 0x400 presumably for stereo */ /* test padding (a set "KCE-Tokyo ..." phrase) after 0x1c to catch bad rips,
if (channel_count > 1 && read_32bitBE(0x400,streamFile) != 0x53766167) /* "Svag" */ * at 0x400 may be header again (Silent Hill 2) or more padding (Silent Scope 2) */
if (channel_count > 1 &&
read_32bitBE(0x400,sf) != 0x53766167 && /* "Svag" */
read_32bitBE(0x400,sf) != 0x44657369) /* "Desi" */
goto fail; goto fail;
start_offset = 0x800; start_offset = 0x800;
data_size = read_32bitLE(0x04,streamFile); data_size = read_32bitLE(0x04,sf);
/* build the VGMSTREAM */ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag); vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(0x08,streamFile); vgmstream->sample_rate = read_32bitLE(0x08,sf);
vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x04,streamFile), vgmstream->channels); vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x04,sf), vgmstream->channels);
if(vgmstream->loop_flag) { if(vgmstream->loop_flag) {
vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(0x18,streamFile)*vgmstream->channels, vgmstream->channels); vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(0x18,sf)*vgmstream->channels, vgmstream->channels);
vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->loop_end_sample = vgmstream->num_samples;
} }
vgmstream->meta_type = meta_PS2_SVAG; vgmstream->meta_type = meta_SVAG_KCET;
vgmstream->coding_type = coding_PSX; vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave; vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile); vgmstream->interleave_block_size = read_32bitLE(0x10,sf);
if (vgmstream->interleave_block_size) if (vgmstream->interleave_block_size)
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels; vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail; goto fail;
return vgmstream; return vgmstream;

View file

@ -0,0 +1,46 @@
#include "meta.h"
#include "../util.h"
/* .SVAG - from SNK games [World Heroes Anthology (PS2), Fatal Fury Battle Archives 2 (PS2)] */
VGMSTREAM* init_vgmstream_svag_snk(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, loop_start_block, loop_end_block;
/* checks */
if (!check_extensions(sf, "svag"))
goto fail;
if (read_32bitBE(0x00,sf) != 0x5641476D) /* "VAGm" */
goto fail;
channel_count = read_32bitLE(0x0c,sf);
loop_start_block = read_32bitLE(0x18,sf);
loop_end_block = read_32bitLE(0x1c,sf);
loop_flag = loop_end_block > 0; /* loop_start_block can be 0 */
start_offset = 0x20;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_SVAG_SNK;
vgmstream->sample_rate = read_32bitLE(0x08,sf);
vgmstream->num_samples = read_32bitLE(0x10,sf) * 28; /* size in blocks */
vgmstream->loop_start_sample = loop_start_block * 28;
vgmstream->loop_end_sample = loop_end_block * 28;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -414,8 +414,8 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
/* get coefs */ /* get coefs */
{ {
int16_t (*read_16bit)(off_t , STREAMFILE*) = txth.coef_big_endian ? read_16bitBE : read_16bitLE; int16_t (*read_16bit)(off_t, STREAMFILE*) = txth.coef_big_endian ? read_16bitBE : read_16bitLE;
int16_t (*get_16bit)(uint8_t * p) = txth.coef_big_endian ? get_16bitBE : get_16bitLE; int16_t (*get_16bit)(const uint8_t* p) = txth.coef_big_endian ? get_16bitBE : get_16bitLE;
for (i = 0; i < vgmstream->channels; i++) { for (i = 0; i < vgmstream->channels; i++) {
if (txth.coef_mode == 0) { /* normal coefs */ if (txth.coef_mode == 0) { /* normal coefs */
@ -579,7 +579,7 @@ fail:
static VGMSTREAM* init_subfile(txth_header* txth) { static VGMSTREAM* init_subfile(txth_header* txth) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
char extension[PATH_LIMIT]; char extension[PATH_LIMIT];
STREAMFILE* streamSubfile = NULL; STREAMFILE* sf_sub = NULL;
if (txth->subfile_size == 0) { if (txth->subfile_size == 0) {
@ -604,10 +604,12 @@ static VGMSTREAM* init_subfile(txth_header* txth) {
strcpy(extension, "subfile_txth."); strcpy(extension, "subfile_txth.");
strcat(extension, txth->subfile_extension); strcat(extension, txth->subfile_extension);
streamSubfile = setup_subfile_streamfile(txth->sf_body, txth->subfile_offset, txth->subfile_size, extension); sf_sub = setup_subfile_streamfile(txth->sf_body, txth->subfile_offset, txth->subfile_size, extension);
if (!streamSubfile) goto fail; if (!sf_sub) goto fail;
vgmstream = init_vgmstream_from_STREAMFILE(streamSubfile); sf_sub->stream_index = txth->sf->stream_index; /* in case of subfiles with subsongs */
vgmstream = init_vgmstream_from_STREAMFILE(sf_sub);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
/* apply some fields */ /* apply some fields */
@ -643,11 +645,11 @@ static VGMSTREAM* init_subfile(txth_header* txth) {
// txth->loop_flag = vgmstream->loop_flag; // txth->loop_flag = vgmstream->loop_flag;
close_streamfile(streamSubfile); close_streamfile(sf_sub);
return vgmstream; return vgmstream;
fail: fail:
close_streamfile(streamSubfile); close_streamfile(sf_sub);
close_vgmstream(vgmstream); close_vgmstream(vgmstream);
return NULL; return NULL;
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -154,7 +154,6 @@ VGMSTREAM * init_vgmstream_ubi_lyn(STREAMFILE *streamFile) {
#ifdef VGM_USE_MPEG #ifdef VGM_USE_MPEG
case 0x5051: { /* MPEG (PS3/PC), interleaved 1ch */ case 0x5051: { /* MPEG (PS3/PC), interleaved 1ch */
mpeg_codec_data *mpeg_data = NULL;
mpeg_custom_config cfg = {0}; mpeg_custom_config cfg = {0};
int i; int i;
@ -175,9 +174,8 @@ VGMSTREAM * init_vgmstream_ubi_lyn(STREAMFILE *streamFile) {
cfg.data_size = data_size; cfg.data_size = data_size;
//todo data parsing looks correct but some files decode a bit wrong at the end (ex. Tintin: Music~Boss~Allan~Victory~02) //todo data parsing looks correct but some files decode a bit wrong at the end (ex. Tintin: Music~Boss~Allan~Victory~02)
mpeg_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_LYN, &cfg); vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_LYN, &cfg);
if (!mpeg_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->codec_data = mpeg_data;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
break; break;

View file

@ -1116,7 +1116,6 @@ static VGMSTREAM* init_vgmstream_ubi_sb_base(ubi_sb_header* sb, STREAMFILE* sf_h
// Probably a beta/custom encoder that creates some buggy frames, that a real X360 handles ok, but trips FFmpeg // Probably a beta/custom encoder that creates some buggy frames, that a real X360 handles ok, but trips FFmpeg
// xmaencode decodes correctly if counters are fixed (otherwise has clicks on every frame). // xmaencode decodes correctly if counters are fixed (otherwise has clicks on every frame).
case FMT_XMA1: { case FMT_XMA1: {
ffmpeg_codec_data *ffmpeg_data;
uint8_t buf[0x100]; uint8_t buf[0x100];
uint32_t sec1_num, sec2_num, sec3_num, bits_per_frame; uint32_t sec1_num, sec2_num, sec3_num, bits_per_frame;
uint8_t flag; uint8_t flag;
@ -1147,9 +1146,8 @@ static VGMSTREAM* init_vgmstream_ubi_sb_base(ubi_sb_header* sb, STREAMFILE* sf_h
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf, 0x100, header_offset, chunk_size, data_size, sf_data, 1); bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf, 0x100, header_offset, chunk_size, data_size, sf_data, 1);
ffmpeg_data = init_ffmpeg_header_offset(sf_data, buf, bytes, start_offset, data_size); vgmstream->codec_data = init_ffmpeg_header_offset(sf_data, buf, bytes, start_offset, data_size);
if (!ffmpeg_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
@ -1158,7 +1156,6 @@ static VGMSTREAM* init_vgmstream_ubi_sb_base(ubi_sb_header* sb, STREAMFILE* sf_h
} }
case RAW_XMA1: { case RAW_XMA1: {
ffmpeg_codec_data *ffmpeg_data;
uint8_t buf[0x100]; uint8_t buf[0x100];
size_t bytes, chunk_size; size_t bytes, chunk_size;
off_t header_offset; off_t header_offset;
@ -1173,9 +1170,8 @@ static VGMSTREAM* init_vgmstream_ubi_sb_base(ubi_sb_header* sb, STREAMFILE* sf_h
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf, 0x100, header_offset, chunk_size, sb->stream_size, sf_head, 1); bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf, 0x100, header_offset, chunk_size, sb->stream_size, sf_head, 1);
ffmpeg_data = init_ffmpeg_header_offset(sf_data, buf, bytes, start_offset, sb->stream_size); vgmstream->codec_data = init_ffmpeg_header_offset(sf_data, buf, bytes, start_offset, sb->stream_size);
if (!ffmpeg_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
@ -3844,22 +3840,6 @@ static int config_sb_version(ubi_sb_header* sb, STREAMFILE* sf) {
return 1; return 1;
} }
/* TMNT (2007)(GC)-bank */
if (sb->version == 0x00190002 && sb->platform == UBI_GC) {
config_sb_entry(sb, 0x68, 0x6c);
config_sb_audio_fs(sb, 0x28, 0x2c, 0x30); /* assumed groud_id */
config_sb_audio_he(sb, 0x3c, 0x40, 0x48, 0x50, 0x58, 0x5c);
config_sb_sequence(sb, 0x2c, 0x14);
config_sb_layer_he(sb, 0x20, 0x34, 0x38, 0x40);
config_sb_layer_sh(sb, 0x30, 0x00, 0x04, 0x08, 0x10);
config_sb_silence_f(sb, 0x1c);
return 1;
}
/* TMNT (2007)(PS2)-bank */ /* TMNT (2007)(PS2)-bank */
if (sb->version == 0x00190002 && sb->platform == UBI_PS2) { if (sb->version == 0x00190002 && sb->platform == UBI_PS2) {
config_sb_entry(sb, 0x48, 0x5c); config_sb_entry(sb, 0x48, 0x5c);
@ -3876,6 +3856,24 @@ static int config_sb_version(ubi_sb_header* sb, STREAMFILE* sf) {
return 1; return 1;
} }
/* TMNT (2007)(GC)-bank */
/* Surf's Up (2007)(GC)-bank 0x00190005 */
if ((sb->version == 0x00190002 && sb->platform == UBI_GC) ||
(sb->version == 0x00190005 && sb->platform == UBI_GC)) {
config_sb_entry(sb, 0x68, 0x6c);
config_sb_audio_fs(sb, 0x28, 0x2c, 0x30); /* assumed groud_id */
config_sb_audio_he(sb, 0x3c, 0x40, 0x48, 0x50, 0x58, 0x5c);
config_sb_sequence(sb, 0x2c, 0x14);
config_sb_layer_he(sb, 0x20, 0x34, 0x38, 0x40);
config_sb_layer_sh(sb, 0x30, 0x00, 0x04, 0x08, 0x10);
config_sb_silence_f(sb, 0x1c);
return 1;
}
/* TMNT (2007)(X360)-bank 0x00190002 */ /* TMNT (2007)(X360)-bank 0x00190002 */
/* My Word Coach (2007)(Wii)-bank 0x00190002 */ /* My Word Coach (2007)(Wii)-bank 0x00190002 */
/* Prince of Persia: Rival Swords (2007)(Wii)-bank 0x00190003 */ /* Prince of Persia: Rival Swords (2007)(Wii)-bank 0x00190003 */
@ -3974,8 +3972,13 @@ static int config_sb_version(ubi_sb_header* sb, STREAMFILE* sf) {
return 1; return 1;
} }
/* Petz Sports: Dog Playground (2008)(Wii)-bank */
/* Cloudy with a Chance of Meatballs (2009)(Wii)-bank */
/* Grey's Anatomy: The Video Game (2009)(Wii)-bank */
/* NCIS: Based on the TV Series (2011)(Wii)-bank */
/* Splinter Cell Classic Trilogy HD (2011)(PS3)-map */ /* Splinter Cell Classic Trilogy HD (2011)(PS3)-map */
if (sb->version == 0x001D0000 && sb->platform == UBI_PS3) { if ((sb->version == 0x001D0000 && sb->platform == UBI_PS3) ||
(sb->version == 0x001D0000 && sb->platform == UBI_WII)) {
config_sb_entry(sb, 0x5c, 0x80); config_sb_entry(sb, 0x5c, 0x80);
sb->cfg.audio_interleave = 0x10; sb->cfg.audio_interleave = 0x10;
sb->cfg.audio_fix_psx_samples = 1; sb->cfg.audio_fix_psx_samples = 1;

View file

@ -20,9 +20,8 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
* .str: Ben10 Galactic Racing * .str: Ben10 Galactic Racing
* .vig: MX vs. ATV Untamed (PS2) * .vig: MX vs. ATV Untamed (PS2)
* .l/r: Crash Nitro Kart (PS2), Gradius V (PS2) * .l/r: Crash Nitro Kart (PS2), Gradius V (PS2)
* .vas: Kingdom Hearts II (PS2) * .vas: Kingdom Hearts II (PS2) */
* .khv: fake for .vas */ if ( !check_extensions(streamFile,"vag,swag,str,vig,l,r,vas") )
if ( !check_extensions(streamFile,"vag,swag,str,vig,l,r,vas,khv") )
goto fail; goto fail;
/* check VAG Header */ /* check VAG Header */

View file

@ -4,8 +4,8 @@
/* VAWX - found in feelplus games [No More Heroes: Heroes Paradise (PS3/X360), Moon Diver (PS3/X360)] */ /* VAWX - found in feelplus games [No More Heroes: Heroes Paradise (PS3/X360), Moon Diver (PS3/X360)] */
VGMSTREAM * init_vgmstream_vawx(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_vawx(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
off_t start_offset, data_size; off_t start_offset, data_size;
int loop_flag = 0, channel_count, codec; int loop_flag = 0, channel_count, codec;
@ -13,15 +13,15 @@ VGMSTREAM * init_vgmstream_vawx(STREAMFILE *streamFile) {
/* checks */ /* checks */
/* .xwv: actual extension [Moon Diver (PS3/X360)] /* .xwv: actual extension [Moon Diver (PS3/X360)]
* .vawx: header id */ * .vawx: header id */
if ( !check_extensions(streamFile, "xwv,vawx") ) if ( !check_extensions(sf, "xwv,vawx") )
goto fail; goto fail;
if (read_32bitBE(0x00,streamFile) != 0x56415758) /* "VAWX" */ if (read_32bitBE(0x00,sf) != 0x56415758) /* "VAWX" */
goto fail; goto fail;
loop_flag = read_8bit(0x37,streamFile); loop_flag = read_8bit(0x37,sf);
channel_count = read_8bit(0x39,streamFile); channel_count = read_8bit(0x39,sf);
start_offset = 0x800; /* ? read_32bitLE(0x0c,streamFile); */ start_offset = 0x800; /* ? read_32bitLE(0x0c,sf); */
codec = read_8bit(0x36,streamFile); /* could be at 0x38 too */ codec = read_8bit(0x36,sf); /* could be at 0x38 too */
/* build the VGMSTREAM */ /* build the VGMSTREAM */
@ -30,8 +30,8 @@ VGMSTREAM * init_vgmstream_vawx(STREAMFILE *streamFile) {
/* 0x04: filesize */ /* 0x04: filesize */
/* 0x16: file id */ /* 0x16: file id */
vgmstream->num_samples = read_32bitBE(0x3c,streamFile); vgmstream->num_samples = read_32bitBE(0x3c,sf);
vgmstream->sample_rate = read_32bitBE(0x40,streamFile); vgmstream->sample_rate = read_32bitBE(0x40,sf);
vgmstream->meta_type = meta_VAWX; vgmstream->meta_type = meta_VAWX;
@ -41,53 +41,51 @@ VGMSTREAM * init_vgmstream_vawx(STREAMFILE *streamFile) {
vgmstream->layout_type = channel_count == 6 ? layout_blocked_vawx : layout_interleave; vgmstream->layout_type = channel_count == 6 ? layout_blocked_vawx : layout_interleave;
vgmstream->interleave_block_size = 0x10; vgmstream->interleave_block_size = 0x10;
vgmstream->loop_start_sample = read_32bitBE(0x44,streamFile); vgmstream->loop_start_sample = read_32bitBE(0x44,sf);
vgmstream->loop_end_sample = read_32bitBE(0x48,streamFile); vgmstream->loop_end_sample = read_32bitBE(0x48,sf);
break; break;
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
case 1: { /* XMA2 */ case 1: { /* XMA2 */
ffmpeg_codec_data *ffmpeg_data = NULL;
uint8_t buf[0x100]; uint8_t buf[0x100];
int32_t bytes, block_size, block_count; int32_t bytes, block_size, block_count;
data_size = get_streamfile_size(streamFile)-start_offset; data_size = get_streamfile_size(sf)-start_offset;
block_size = 0x10000; /* VAWX default */ block_size = 0x10000; /* VAWX default */
block_count = (uint16_t)read_16bitBE(0x3A, streamFile); /* also at 0x56 */ block_count = (uint16_t)read_16bitBE(0x3A, sf); /* also at 0x56 */
bytes = ffmpeg_make_riff_xma2(buf,0x100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); bytes = ffmpeg_make_riff_xma2(buf,0x100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size); vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, start_offset,data_size);
if ( !ffmpeg_data ) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
vgmstream->loop_start_sample = read_32bitBE(0x44,streamFile); vgmstream->loop_start_sample = read_32bitBE(0x44,sf);
vgmstream->loop_end_sample = read_32bitBE(0x48,streamFile); vgmstream->loop_end_sample = read_32bitBE(0x48,sf);
//todo fix loops/samples vs ATRAC3 //todo fix loops/samples vs ATRAC3
/* may be only applying end_skip to num_samples? */ /* may be only applying end_skip to num_samples? */
xma_fix_raw_samples(vgmstream, streamFile, start_offset,data_size, 0, 0,0); xma_fix_raw_samples(vgmstream, sf, start_offset,data_size, 0, 0,0);
break; break;
} }
case 7: { /* ATRAC3 */ case 7: { /* ATRAC3 */
int block_align, encoder_delay; int block_align, encoder_delay;
data_size = read_32bitBE(0x54,streamFile); data_size = read_32bitBE(0x54,sf);
block_align = 0x98 * vgmstream->channels; block_align = 0x98 * vgmstream->channels;
encoder_delay = 1024 + 69*2; /* observed default, matches XMA (needed as many files start with garbage) */ encoder_delay = 1024 + 69*2; /* observed default, matches XMA (needed as many files start with garbage) */
vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_align) - encoder_delay; /* original samples break looping in some files otherwise */ vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_align) - encoder_delay; /* original samples break looping in some files otherwise */
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamFile, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay); 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; if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
/* set offset samples (offset 0 jumps to sample 0 > pre-applied delay, and offset end loops after sample end > adjusted delay) */ /* set offset samples (offset 0 jumps to sample 0 > pre-applied delay, and offset end loops after sample end > adjusted delay) */
vgmstream->loop_start_sample = atrac3_bytes_to_samples(read_32bitBE(0x44,streamFile), block_align); //- encoder_delay vgmstream->loop_start_sample = atrac3_bytes_to_samples(read_32bitBE(0x44,sf), block_align); //- encoder_delay
vgmstream->loop_end_sample = atrac3_bytes_to_samples(read_32bitBE(0x48,streamFile), block_align) - encoder_delay; vgmstream->loop_end_sample = atrac3_bytes_to_samples(read_32bitBE(0x48,sf), block_align) - encoder_delay;
break; break;
} }
#endif #endif
@ -97,7 +95,7 @@ VGMSTREAM * init_vgmstream_vawx(STREAMFILE *streamFile) {
} }
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail; goto fail;
return vgmstream; return vgmstream;

View file

@ -225,8 +225,9 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE* sf) {
goto fail; goto fail;
} }
if (ww.codec == PCM || ww.codec == IMA || ww.codec == DSP || ww.codec == VORBIS || ww.codec == XMA2 || ww.codec == OPUSNX || ww.codec == OPUS) { if (ww.codec == PCM || ww.codec == IMA || ww.codec == VORBIS || ww.codec == DSP || ww.codec == XMA2 ||
ww.truncated = 1; /* only seen those, probably all exist */ ww.codec == OPUSNX || ww.codec == OPUS || ww.codec == PTADPCM) {
ww.truncated = 1; /* only seen those, probably all exist (XWMA, AAC, HEVAG, ATRAC9?) */
} else { } else {
VGM_LOG("WWISE: wrong size, maybe truncated\n"); VGM_LOG("WWISE: wrong size, maybe truncated\n");
goto fail; goto fail;
@ -373,7 +374,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE* sf) {
else { else {
/* newer Wwise (>2012) */ /* newer Wwise (>2012) */
off_t extra_offset = ww.fmt_offset + 0x18; /* after flag + channels */ off_t extra_offset = ww.fmt_offset + 0x18; /* after flag + channels */
int is_wem = check_extensions(sf,"wem"); int is_wem = check_extensions(sf,"wem,bnk"); /* use extension as a guide for faster vorbis inits */
switch(ww.extra_size) { switch(ww.extra_size) {
case 0x30: case 0x30:
@ -382,7 +383,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE* sf) {
cfg.header_type = WWV_TYPE_2; cfg.header_type = WWV_TYPE_2;
cfg.packet_type = WWV_MODIFIED; cfg.packet_type = WWV_MODIFIED;
/* setup not detectable by header, so we'll try both; hopefully libvorbis will reject wrong codebooks /* setup not detectable by header, so we'll try both; libvorbis should reject wrong codebooks
* - standard: early (<2012), ex. The King of Fighters XIII (X360)-2011/11, .ogg (cbs are from aoTuV, too) * - standard: early (<2012), ex. The King of Fighters XIII (X360)-2011/11, .ogg (cbs are from aoTuV, too)
* - aoTuV603: later (>2012), ex. Sonic & All-Stars Racing Transformed (PC)-2012/11, .wem */ * - aoTuV603: later (>2012), ex. Sonic & All-Stars Racing Transformed (PC)-2012/11, .wem */
cfg.setup_type = is_wem ? WWV_AOTUV603_CODEBOOKS : WWV_EXTERNAL_CODEBOOKS; /* aoTuV came along .wem */ cfg.setup_type = is_wem ? WWV_AOTUV603_CODEBOOKS : WWV_EXTERNAL_CODEBOOKS; /* aoTuV came along .wem */
@ -679,6 +680,10 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE* sf) {
vgmstream->interleave_block_size = ww.block_align / ww.channels; vgmstream->interleave_block_size = ww.block_align / ww.channels;
//vgmstream->codec_endian = ww.big_endian; //? //vgmstream->codec_endian = ww.big_endian; //?
if (ww.truncated) {
ww.data_size = ww.file_size - ww.data_offset;
}
vgmstream->num_samples = ptadpcm_bytes_to_samples(ww.data_size, ww.channels, vgmstream->interleave_block_size); vgmstream->num_samples = ptadpcm_bytes_to_samples(ww.data_size, ww.channels, vgmstream->interleave_block_size);
break; break;

View file

@ -2,61 +2,58 @@
#include "../coding/coding.h" #include "../coding/coding.h"
/* CXS - found in Eternal Sonata (X360) */ /* CXS - found in Eternal Sonata (X360) */
VGMSTREAM * init_vgmstream_x360_cxs(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_x360_cxs(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
off_t start_offset; off_t start_offset;
int loop_flag, channel_count; int loop_flag, channel_count;
/* checks */ /* checks */
if ( !check_extensions(streamFile,"cxs")) if ( !check_extensions(sf,"cxs"))
goto fail; goto fail;
if (read_32bitBE(0x00,streamFile) != 0x43585320) /* "CXS " */ if (read_32bitBE(0x00,sf) != 0x43585320) /* "CXS " */
goto fail; goto fail;
loop_flag = read_32bitBE(0x18,streamFile) > 0; loop_flag = read_32bitBE(0x18,sf) > 0;
channel_count = read_32bitBE(0x0c,streamFile); channel_count = read_32bitBE(0x0c,sf);
start_offset = read_32bitBE(0x04,streamFile) + read_32bitBE(0x28,streamFile); /* assumed, seek table always at 0x800 */ start_offset = read_32bitBE(0x04,sf) + read_32bitBE(0x28,sf); /* assumed, seek table always at 0x800 */
/* build the VGMSTREAM */ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag); vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
/* 0x04: data start? */ /* 0x04: data start? */
vgmstream->sample_rate = read_32bitBE(0x08,streamFile); vgmstream->sample_rate = read_32bitBE(0x08,sf);
vgmstream->num_samples = read_32bitBE(0x10,streamFile); vgmstream->num_samples = read_32bitBE(0x10,sf);
vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile); vgmstream->loop_start_sample = read_32bitBE(0x14,sf);
vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile); vgmstream->loop_end_sample = read_32bitBE(0x18,sf);
/* 0x1c: below */ /* 0x1c: below */
vgmstream->meta_type = meta_X360_CXS; vgmstream->meta_type = meta_X360_CXS;
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
{ {
ffmpeg_codec_data *ffmpeg_data = NULL; uint8_t buf[0x100];
uint8_t buf[100];
size_t bytes, datasize, block_size, block_count; size_t bytes, datasize, block_size, block_count;
block_count = read_32bitBE(0x1c,streamFile); block_count = read_32bitBE(0x1c,sf);
block_size = read_32bitBE(0x20,streamFile); block_size = read_32bitBE(0x20,sf);
datasize = read_32bitBE(0x24,streamFile); datasize = read_32bitBE(0x24,sf);
bytes = ffmpeg_make_riff_xma2(buf,100, vgmstream->num_samples, datasize, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); bytes = ffmpeg_make_riff_xma2(buf,100, vgmstream->num_samples, datasize, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
if (bytes <= 0) goto fail; if (bytes <= 0) goto fail;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,datasize); vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, start_offset,datasize);
if ( !ffmpeg_data ) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
xma_fix_raw_samples(vgmstream, streamFile, start_offset,datasize, 0, 0,1); /* num samples are ok */ xma_fix_raw_samples(vgmstream, sf, start_offset,datasize, 0, 0,1); /* num samples are ok */
} }
#else #else
goto fail; goto fail;
#endif #endif
/* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, sf, start_offset) )
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail; goto fail;
return vgmstream; return vgmstream;

View file

@ -142,7 +142,6 @@ VGMSTREAM *init_vgmstream_xmv_valve(STREAMFILE *streamFile) {
break; break;
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
case 0x01: { /* XMA */ case 0x01: { /* XMA */
ffmpeg_codec_data *ffmpeg_data;
uint8_t buf[0x100]; uint8_t buf[0x100];
int block_count, block_size; int block_count, block_size;
size_t bytes; size_t bytes;
@ -152,10 +151,8 @@ VGMSTREAM *init_vgmstream_xmv_valve(STREAMFILE *streamFile) {
bytes = ffmpeg_make_riff_xma2(buf, 0x100, num_samples, data_size, channels, sample_rate, block_count, block_size); bytes = ffmpeg_make_riff_xma2(buf, 0x100, num_samples, data_size, channels, sample_rate, block_count, block_size);
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf, bytes, start_offset, data_size); vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf, bytes, start_offset, data_size);
if (!ffmpeg_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
vgmstream->loop_end_sample -= loop_end_skip; vgmstream->loop_end_sample -= loop_end_skip;
@ -166,16 +163,13 @@ VGMSTREAM *init_vgmstream_xmv_valve(STREAMFILE *streamFile) {
#endif #endif
#ifdef VGM_USE_MPEG #ifdef VGM_USE_MPEG
case 0x03: { /* MP3 */ case 0x03: { /* MP3 */
mpeg_codec_data *mpeg_data;
coding_t mpeg_coding; coding_t mpeg_coding;
if (loop_flag) /* should never happen, Source cannot loop MP3 */ if (loop_flag) /* should never happen, Source cannot loop MP3 */
goto fail; goto fail;
mpeg_data = init_mpeg(streamFile, start_offset, &mpeg_coding, channels); vgmstream->codec_data = init_mpeg(streamFile, start_offset, &mpeg_coding, channels);
if (!mpeg_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->codec_data = mpeg_data;
vgmstream->coding_type = mpeg_coding; vgmstream->coding_type = mpeg_coding;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;

View file

@ -75,40 +75,43 @@ typedef struct {
int fix_xma_loop_samples; int fix_xma_loop_samples;
} xwb_header; } xwb_header;
static void get_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamFile); static void get_name(char* buf, size_t maxsize, int target_subsong, xwb_header* xwb, STREAMFILE* sf);
/* XWB - XACT Wave Bank (Microsoft SDK format for XBOX/XBOX360/Windows) */ /* XWB - XACT Wave Bank (Microsoft SDK format for XBOX/XBOX360/Windows) */
VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_xwb(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
off_t start_offset, offset, suboffset; off_t start_offset, offset, suboffset;
xwb_header xwb = {0}; xwb_header xwb = {0};
int target_subsong = streamFile->stream_index; int target_subsong = sf->stream_index;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL;
int32_t (*read_s32)(off_t,STREAMFILE*) = NULL;
/* checks */ /* checks */
/* .xwb: standard /* .xwb: standard
* .xna: Touhou Makukasai ~ Fantasy Danmaku Festival (PC) * .xna: Touhou Makukasai ~ Fantasy Danmaku Festival (PC)
* (extensionless): Ikaruga (X360/PC), Grabbed by the Ghoulies (Xbox) */ * (extensionless): Ikaruga (X360/PC), Grabbed by the Ghoulies (Xbox) */
if (!check_extensions(streamFile,"xwb,xna,")) if (!check_extensions(sf,"xwb,xna,"))
goto fail; goto fail;
if ((read_32bitBE(0x00,streamFile) != 0x57424E44) && /* "WBND" (LE) */ if ((read_u32be(0x00,sf) != 0x57424E44) && /* "WBND" (LE) */
(read_32bitBE(0x00,streamFile) != 0x444E4257)) /* "DNBW" (BE) */ (read_u32be(0x00,sf) != 0x444E4257)) /* "DNBW" (BE) */
goto fail; goto fail;
xwb.little_endian = read_32bitBE(0x00,streamFile) == 0x57424E44; /* WBND */ xwb.little_endian = read_u32be(0x00,sf) == 0x57424E44; /* WBND */
if (xwb.little_endian) { if (xwb.little_endian) {
read_32bit = read_32bitLE; read_u32 = read_u32le;
read_s32 = read_s32le;
} else { } else {
read_32bit = read_32bitBE; read_u32 = read_u32be;
read_s32 = read_s32be;
} }
/* read main header (WAVEBANKHEADER) */ /* read main header (WAVEBANKHEADER) */
xwb.version = read_32bit(0x04, streamFile); /* XACT3: 0x04=tool version, 0x08=header version */ xwb.version = read_u32(0x04, sf); /* XACT3: 0x04=tool version, 0x08=header version */
/* Crackdown 1 (X360), essentially XACT2 but may have split header in some cases */ /* Crackdown 1 (X360), essentially XACT2 but may have split header in some cases, compact entries change */
if (xwb.version == XACT_CRACKDOWN) { if (xwb.version == XACT_CRACKDOWN) {
xwb.version = XACT2_2_MAX; xwb.version = XACT2_2_MAX;
xwb.is_crackdown = 1; xwb.is_crackdown = 1;
@ -116,15 +119,15 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* read segment offsets (SEGIDX) */ /* read segment offsets (SEGIDX) */
if (xwb.version <= XACT1_0_MAX) { if (xwb.version <= XACT1_0_MAX) {
xwb.total_subsongs = read_32bit(0x0c, streamFile); xwb.total_subsongs = read_s32(0x0c, sf);
read_string(xwb.wavebank_name,0x10+1, 0x10, streamFile); /* null-terminated */ read_string(xwb.wavebank_name,0x10+1, 0x10, sf); /* null-terminated */
xwb.base_offset = 0; xwb.base_offset = 0;
xwb.base_size = 0; xwb.base_size = 0;
xwb.entry_offset = 0x50; xwb.entry_offset = 0x50;
xwb.entry_elem_size = 0x14; xwb.entry_elem_size = 0x14;
xwb.entry_size = xwb.entry_elem_size * xwb.total_subsongs; xwb.entry_size = xwb.entry_elem_size * xwb.total_subsongs;
xwb.data_offset = xwb.entry_offset + xwb.entry_size; xwb.data_offset = xwb.entry_offset + xwb.entry_size;
xwb.data_size = get_streamfile_size(streamFile) - xwb.data_offset; xwb.data_size = get_streamfile_size(sf) - xwb.data_offset;
xwb.names_offset = 0; xwb.names_offset = 0;
xwb.names_size = 0; xwb.names_size = 0;
@ -134,52 +137,52 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
} }
else { else {
offset = xwb.version <= XACT2_2_MAX ? 0x08 : 0x0c; offset = xwb.version <= XACT2_2_MAX ? 0x08 : 0x0c;
xwb.base_offset = read_32bit(offset+0x00, streamFile);//BANKDATA xwb.base_offset = read_s32(offset+0x00, sf);//BANKDATA
xwb.base_size = read_32bit(offset+0x04, streamFile); xwb.base_size = read_s32(offset+0x04, sf);
xwb.entry_offset= read_32bit(offset+0x08, streamFile);//ENTRYMETADATA xwb.entry_offset= read_s32(offset+0x08, sf);//ENTRYMETADATA
xwb.entry_size = read_32bit(offset+0x0c, streamFile); xwb.entry_size = read_s32(offset+0x0c, sf);
/* read extra segments (values can be 0 == no segment) */ /* read extra segments (values can be 0 == no segment) */
if (xwb.version <= XACT1_1_MAX) { if (xwb.version <= XACT1_1_MAX) {
xwb.names_offset = read_32bit(offset+0x10, streamFile);//ENTRYNAMES xwb.names_offset = read_s32(offset+0x10, sf);//ENTRYNAMES
xwb.names_size = read_32bit(offset+0x14, streamFile); xwb.names_size = read_s32(offset+0x14, sf);
xwb.names_entry_size= 0x40; xwb.names_entry_size= 0x40;
xwb.extra_offset = 0; xwb.extra_offset = 0;
xwb.extra_size = 0; xwb.extra_size = 0;
suboffset = 0x04*2; suboffset = 0x04*2;
} }
else if (xwb.version <= XACT2_1_MAX) { else if (xwb.version <= XACT2_1_MAX) {
xwb.names_offset = read_32bit(offset+0x10, streamFile);//ENTRYNAMES xwb.names_offset = read_s32(offset+0x10, sf);//ENTRYNAMES
xwb.names_size = read_32bit(offset+0x14, streamFile); xwb.names_size = read_s32(offset+0x14, sf);
xwb.names_entry_size= 0x40; xwb.names_entry_size= 0x40;
xwb.extra_offset = read_32bit(offset+0x18, streamFile);//EXTRA xwb.extra_offset = read_s32(offset+0x18, sf);//EXTRA
xwb.extra_size = read_32bit(offset+0x1c, streamFile); xwb.extra_size = read_s32(offset+0x1c, sf);
suboffset = 0x04*2 + 0x04*2; suboffset = 0x04*2 + 0x04*2;
} else { } else {
xwb.extra_offset = read_32bit(offset+0x10, streamFile);//SEEKTABLES xwb.extra_offset = read_s32(offset+0x10, sf);//SEEKTABLES
xwb.extra_size = read_32bit(offset+0x14, streamFile); xwb.extra_size = read_s32(offset+0x14, sf);
xwb.names_offset = read_32bit(offset+0x18, streamFile);//ENTRYNAMES xwb.names_offset = read_s32(offset+0x18, sf);//ENTRYNAMES
xwb.names_size = read_32bit(offset+0x1c, streamFile); xwb.names_size = read_s32(offset+0x1c, sf);
xwb.names_entry_size= 0x40; xwb.names_entry_size= 0x40;
suboffset = 0x04*2 + 0x04*2; suboffset = 0x04*2 + 0x04*2;
} }
xwb.data_offset = read_32bit(offset+0x10+suboffset, streamFile);//ENTRYWAVEDATA xwb.data_offset = read_s32(offset+0x10+suboffset, sf);//ENTRYWAVEDATA
xwb.data_size = read_32bit(offset+0x14+suboffset, streamFile); xwb.data_size = read_s32(offset+0x14+suboffset, sf);
/* for Techland's XWB with no data */ /* for Techland's XWB with no data */
if (xwb.base_offset == 0) goto fail; if (xwb.base_offset == 0) goto fail;
/* read base entry (WAVEBANKDATA) */ /* read base entry (WAVEBANKDATA) */
offset = xwb.base_offset; offset = xwb.base_offset;
xwb.base_flags = (uint32_t)read_32bit(offset+0x00, streamFile); xwb.base_flags = read_u32(offset+0x00, sf);
xwb.total_subsongs = read_32bit(offset+0x04, streamFile); xwb.total_subsongs = read_s32(offset+0x04, sf);
read_string(xwb.wavebank_name,0x40+1, offset+0x08, streamFile); /* null-terminated */ read_string(xwb.wavebank_name,0x40+1, offset+0x08, sf); /* null-terminated */
suboffset = 0x08 + (xwb.version <= XACT1_1_MAX ? 0x10 : 0x40); suboffset = 0x08 + (xwb.version <= XACT1_1_MAX ? 0x10 : 0x40);
xwb.entry_elem_size = read_32bit(offset+suboffset+0x00, streamFile); xwb.entry_elem_size = read_s32(offset+suboffset+0x00, sf);
/* suboff+0x04: meta name entry size */ /* suboff+0x04: meta name entry size */
xwb.entry_alignment = read_32bit(offset+suboffset+0x08, streamFile); /* usually 1 dvd sector */ xwb.entry_alignment = read_s32(offset+suboffset+0x08, sf); /* usually 1 dvd sector */
xwb.format = read_32bit(offset+suboffset+0x0c, streamFile); /* compact mode only */ xwb.format = read_s32(offset+suboffset+0x0c, sf); /* compact mode only */
/* suboff+0x10: build time 64b (XACT2/3) */ /* suboff+0x10: build time 64b (XACT2/3) */
} }
@ -192,20 +195,34 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* read stream entry (WAVEBANKENTRY) */ /* read stream entry (WAVEBANKENTRY) */
offset = xwb.entry_offset + (target_subsong-1) * xwb.entry_elem_size; offset = xwb.entry_offset + (target_subsong-1) * xwb.entry_elem_size;
if (xwb.base_flags & WAVEBANK_FLAGS_COMPACT) { /* compact entry [NFL Fever 2004 demo from Amped 2 (Xbox)] */
if ((xwb.base_flags & WAVEBANK_FLAGS_COMPACT) && xwb.is_crackdown) {
/* mutant compact (w/ entry_elem_size=0x08) [Crackdown (X360)] */
uint32_t entry, size_sectors, sector_offset;
entry = read_u32(offset+0x00, sf);
size_sectors = ((entry >> 19) & 0x1FFF); /* 13b, exact size in sectors */
sector_offset = (entry & 0x7FFFF); /* 19b, offset within data in sectors */
xwb.stream_size = size_sectors * xwb.entry_alignment;
xwb.num_samples = read_u32(offset+0x04, sf);
xwb.stream_offset = xwb.data_offset + sector_offset * xwb.entry_alignment;
}
else if (xwb.base_flags & WAVEBANK_FLAGS_COMPACT) {
/* compact entry [NFL Fever 2004 demo from Amped 2 (Xbox)] */
uint32_t entry, size_deviation, sector_offset; uint32_t entry, size_deviation, sector_offset;
off_t next_stream_offset; off_t next_stream_offset;
entry = (uint32_t)read_32bit(offset+0x00, streamFile); entry = read_u32(offset+0x00, sf);
size_deviation = ((entry >> 21) & 0x7FF); /* 11b, padding data for sector alignment in bytes*/ size_deviation = ((entry >> 21) & 0x7FF); /* 11b, padding data for sector alignment in bytes*/
sector_offset = (entry & 0x1FFFFF); /* 21b, offset within data in sectors */ sector_offset = (entry & 0x1FFFFF); /* 21b, offset within data in sectors */
xwb.stream_offset = xwb.data_offset + sector_offset*xwb.entry_alignment; xwb.stream_offset = xwb.data_offset + sector_offset * xwb.entry_alignment;
/* find size using next offset */ /* find size using next offset */
if (target_subsong < xwb.total_subsongs) { if (target_subsong < xwb.total_subsongs) {
uint32_t next_entry = (uint32_t)read_32bit(offset+0x04, streamFile); uint32_t next_entry = read_u32(offset + xwb.entry_elem_size, sf);
next_stream_offset = xwb.data_offset + (next_entry & 0x1FFFFF)*xwb.entry_alignment; next_stream_offset = xwb.data_offset + (next_entry & 0x1FFFFF) * xwb.entry_alignment;
} }
else { /* for last entry (or first, when subsongs = 1) */ else { /* for last entry (or first, when subsongs = 1) */
next_stream_offset = xwb.data_offset + xwb.data_size; next_stream_offset = xwb.data_offset + xwb.data_size;
@ -213,31 +230,31 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
xwb.stream_size = next_stream_offset - xwb.stream_offset - size_deviation; xwb.stream_size = next_stream_offset - xwb.stream_offset - size_deviation;
} }
else if (xwb.version <= XACT1_0_MAX) { else if (xwb.version <= XACT1_0_MAX) {
xwb.format = (uint32_t)read_32bit(offset+0x00, streamFile); xwb.format = read_u32(offset+0x00, sf);
xwb.stream_offset = xwb.data_offset + (uint32_t)read_32bit(offset+0x04, streamFile); xwb.stream_offset = xwb.data_offset + read_u32(offset+0x04, sf);
xwb.stream_size = (uint32_t)read_32bit(offset+0x08, streamFile); xwb.stream_size = read_u32(offset+0x08, sf);
xwb.loop_start = (uint32_t)read_32bit(offset+0x0c, streamFile); xwb.loop_start = read_u32(offset+0x0c, sf);
xwb.loop_end = (uint32_t)read_32bit(offset+0x10, streamFile);//length xwb.loop_end = read_u32(offset+0x10, sf);//length
} }
else { else {
uint32_t entry_info = (uint32_t)read_32bit(offset+0x00, streamFile); uint32_t entry_info = read_u32(offset+0x00, sf);
if (xwb.version <= XACT1_1_MAX) { if (xwb.version <= XACT1_1_MAX) {
xwb.entry_flags = entry_info; xwb.entry_flags = entry_info;
} else { } else {
xwb.entry_flags = (entry_info) & 0xF; /*4b*/ xwb.entry_flags = (entry_info) & 0xF; /*4b*/
xwb.num_samples = (entry_info >> 4) & 0x0FFFFFFF; /*28b*/ xwb.num_samples = (entry_info >> 4) & 0x0FFFFFFF; /*28b*/
} }
xwb.format = (uint32_t)read_32bit(offset+0x04, streamFile); xwb.format = read_u32(offset+0x04, sf);
xwb.stream_offset = xwb.data_offset + (uint32_t)read_32bit(offset+0x08, streamFile); xwb.stream_offset = xwb.data_offset + read_u32(offset+0x08, sf);
xwb.stream_size = (uint32_t)read_32bit(offset+0x0c, streamFile); xwb.stream_size = read_u32(offset+0x0c, sf);
if (xwb.version <= XACT2_1_MAX) { /* LoopRegion (bytes) */ if (xwb.version <= XACT2_1_MAX) { /* LoopRegion (bytes) */
xwb.loop_start = (uint32_t)read_32bit(offset+0x10, streamFile); xwb.loop_start = read_u32(offset+0x10, sf);
xwb.loop_end = (uint32_t)read_32bit(offset+0x14, streamFile);//length (LoopRegion) or offset (XMALoopRegion in late XACT2) xwb.loop_end = read_u32(offset+0x14, sf);//length (LoopRegion) or offset (XMALoopRegion in late XACT2)
} else { /* LoopRegion (samples) */ } else { /* LoopRegion (samples) */
xwb.loop_start_sample = (uint32_t)read_32bit(offset+0x10, streamFile); xwb.loop_start_sample = read_u32(offset+0x10, sf);
xwb.loop_end_sample = (uint32_t)read_32bit(offset+0x14, streamFile) + xwb.loop_start_sample; xwb.loop_end_sample = read_u32(offset+0x14, sf) + xwb.loop_start_sample;
} }
} }
@ -326,9 +343,9 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
} }
else if (xwb.version == XACT3_0_MAX && xwb.codec == XMA2 else if (xwb.version == XACT3_0_MAX && xwb.codec == XMA2
&& xwb.bits_per_sample == 0x01 && xwb.block_align == 0x04 && xwb.bits_per_sample == 0x01 && xwb.block_align == 0x04
&& read_32bitLE(xwb.stream_offset + 0x08, streamFile) == xwb.sample_rate /* DSP header */ && read_u32le(xwb.stream_offset + 0x08, sf) == xwb.sample_rate /* DSP header */
&& read_16bitLE(xwb.stream_offset + 0x0e, streamFile) == 0 && read_u16le(xwb.stream_offset + 0x0e, sf) == 0
&& read_32bitLE(xwb.stream_offset + 0x18, streamFile) == 2 && read_u32le(xwb.stream_offset + 0x18, sf) == 2
/*&& xwb.data_size == 0x55951c1c*/) { /* some kind of id in Stardew Valley? */ /*&& xwb.data_size == 0x55951c1c*/) { /* some kind of id in Stardew Valley? */
/* Stardew Valley (Switch), Skulls of the Shogun (Switch): full interleaved DSPs (including headers) */ /* Stardew Valley (Switch), Skulls of the Shogun (Switch): full interleaved DSPs (including headers) */
xwb.codec = DSP; xwb.codec = DSP;
@ -348,9 +365,9 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* Oddworld OGG the data_size value is size of uncompressed bytes instead; DSP uses some id/config as value */ /* Oddworld OGG the data_size value is size of uncompressed bytes instead; DSP uses some id/config as value */
if (xwb.codec != OGG && xwb.codec != DSP && xwb.codec != ATRAC9_RIFF) { if (xwb.codec != OGG && xwb.codec != DSP && xwb.codec != ATRAC9_RIFF) {
/* some low-q rips don't remove padding, relax validation a bit */ /* some low-q rips don't remove padding, relax validation a bit */
if (xwb.data_offset + xwb.stream_size > get_streamfile_size(streamFile)) if (xwb.data_offset + xwb.stream_size > get_streamfile_size(sf))
goto fail; goto fail;
//if (xwb.data_offset + xwb.data_size > get_streamfile_size(streamFile)) /* badly split */ //if (xwb.data_offset + xwb.data_size > get_streamfile_size(sf)) /* badly split */
// goto fail; // goto fail;
} }
@ -394,7 +411,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
msd.loop_end_subframe = ((xwb.loop_end >> 2) & 0x3) + 1; /* 2b */ msd.loop_end_subframe = ((xwb.loop_end >> 2) & 0x3) + 1; /* 2b */
msd.loop_start_subframe = ((xwb.loop_end >> 0) & 0x3) + 1; /* 2b */ msd.loop_start_subframe = ((xwb.loop_end >> 0) & 0x3) + 1; /* 2b */
xma_get_samples(&msd, streamFile); xma_get_samples(&msd, sf);
xwb.loop_start_sample = msd.loop_start_sample; xwb.loop_start_sample = msd.loop_start_sample;
xwb.loop_end_sample = msd.loop_end_sample; xwb.loop_end_sample = msd.loop_end_sample;
@ -431,7 +448,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
vgmstream->num_streams = xwb.total_subsongs; vgmstream->num_streams = xwb.total_subsongs;
vgmstream->stream_size = xwb.stream_size; vgmstream->stream_size = xwb.stream_size;
vgmstream->meta_type = meta_XWB; vgmstream->meta_type = meta_XWB;
get_name(vgmstream->stream_name,STREAM_NAME_SIZE, target_subsong, &xwb, streamFile); get_name(vgmstream->stream_name,STREAM_NAME_SIZE, target_subsong, &xwb, sf);
switch(xwb.codec) { switch(xwb.codec) {
case PCM: /* Unreal Championship (Xbox)[PCM8], KOF2003 (Xbox)[PCM16LE], Otomedius (X360)[PCM16BE] */ case PCM: /* Unreal Championship (Xbox)[PCM8], KOF2003 (Xbox)[PCM16LE], Otomedius (X360)[PCM16BE] */
@ -458,12 +475,12 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
int bytes; int bytes;
bytes = ffmpeg_make_riff_xma1(buf,0x100, vgmstream->num_samples, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, 0); bytes = ffmpeg_make_riff_xma1(buf,0x100, vgmstream->num_samples, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, 0);
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, xwb.stream_offset,xwb.stream_size); vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, xwb.stream_offset,xwb.stream_size);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
xma_fix_raw_samples(vgmstream, streamFile, xwb.stream_offset,xwb.stream_size, 0, xwb.fix_xma_num_samples,xwb.fix_xma_loop_samples); xma_fix_raw_samples(vgmstream, sf, xwb.stream_offset,xwb.stream_size, 0, xwb.fix_xma_num_samples,xwb.fix_xma_loop_samples);
/* this fixes some XMA1, perhaps the above isn't reading end_skip correctly (doesn't happen for all files though) */ /* this fixes some XMA1, perhaps the above isn't reading end_skip correctly (doesn't happen for all files though) */
if (vgmstream->loop_flag && if (vgmstream->loop_flag &&
@ -482,19 +499,19 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
block_count = xwb.stream_size / block_size + (xwb.stream_size % block_size ? 1 : 0); block_count = xwb.stream_size / block_size + (xwb.stream_size % block_size ? 1 : 0);
bytes = ffmpeg_make_riff_xma2(buf,0x100, vgmstream->num_samples, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); bytes = ffmpeg_make_riff_xma2(buf,0x100, vgmstream->num_samples, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, xwb.stream_offset,xwb.stream_size); vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, xwb.stream_offset,xwb.stream_size);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
xma_fix_raw_samples(vgmstream, streamFile, xwb.stream_offset,xwb.stream_size, 0, xwb.fix_xma_num_samples,xwb.fix_xma_loop_samples); xma_fix_raw_samples(vgmstream, sf, xwb.stream_offset,xwb.stream_size, 0, xwb.fix_xma_num_samples,xwb.fix_xma_loop_samples);
break; break;
} }
case WMA: { /* WMAudio1 (WMA v2): Prince of Persia 2 port (Xbox) */ case WMA: { /* WMAudio1 (WMA v2): Prince of Persia 2 port (Xbox) */
ffmpeg_codec_data *ffmpeg_data = NULL; ffmpeg_codec_data *ffmpeg_data = NULL;
ffmpeg_data = init_ffmpeg_offset(streamFile, xwb.stream_offset,xwb.stream_size); ffmpeg_data = init_ffmpeg_offset(sf, xwb.stream_offset,xwb.stream_size);
if ( !ffmpeg_data ) goto fail; if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data; vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
@ -520,7 +537,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
wma_codec = xwb.bits_per_sample ? 0x162 : 0x161; /* 0=WMAudio2, 1=WMAudio3 */ wma_codec = xwb.bits_per_sample ? 0x162 : 0x161; /* 0=WMAudio2, 1=WMAudio3 */
bytes = ffmpeg_make_riff_xwma(buf,0x100, wma_codec, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, avg_bps, block_align); bytes = ffmpeg_make_riff_xwma(buf,0x100, wma_codec, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, avg_bps, block_align);
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, xwb.stream_offset,xwb.stream_size); vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, xwb.stream_offset,xwb.stream_size);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
@ -534,7 +551,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
encoder_delay = 1024; /* assumed */ encoder_delay = 1024; /* assumed */
vgmstream->num_samples -= encoder_delay; vgmstream->num_samples -= encoder_delay;
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamFile, xwb.stream_offset,xwb.stream_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay); vgmstream->codec_data = init_ffmpeg_atrac3_raw(sf, xwb.stream_offset,xwb.stream_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
@ -543,7 +560,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
#endif #endif
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
case OGG: { /* Oddworld: Strangers Wrath (iOS/Android) extension */ case OGG: { /* Oddworld: Strangers Wrath (iOS/Android) extension */
vgmstream->codec_data = init_ogg_vorbis(streamFile, xwb.stream_offset, xwb.stream_size, NULL); vgmstream->codec_data = init_ogg_vorbis(sf, xwb.stream_offset, xwb.stream_size, NULL);
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_OGG_VORBIS; vgmstream->coding_type = coding_OGG_VORBIS;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
@ -556,8 +573,8 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
vgmstream->layout_type = layout_interleave; vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = xwb.stream_size / xwb.channels; vgmstream->interleave_block_size = xwb.stream_size / xwb.channels;
dsp_read_coefs(vgmstream,streamFile,xwb.stream_offset + 0x1c,vgmstream->interleave_block_size,!xwb.little_endian); dsp_read_coefs(vgmstream,sf,xwb.stream_offset + 0x1c,vgmstream->interleave_block_size,!xwb.little_endian);
dsp_read_hist (vgmstream,streamFile,xwb.stream_offset + 0x3c,vgmstream->interleave_block_size,!xwb.little_endian); dsp_read_hist (vgmstream,sf,xwb.stream_offset + 0x3c,vgmstream->interleave_block_size,!xwb.little_endian);
xwb.stream_offset += 0x60; /* skip DSP header */ xwb.stream_offset += 0x60; /* skip DSP header */
break; break;
} }
@ -565,16 +582,16 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
#ifdef VGM_USE_ATRAC9 #ifdef VGM_USE_ATRAC9
case ATRAC9_RIFF: { /* Stardew Valley (Vita) extension */ case ATRAC9_RIFF: { /* Stardew Valley (Vita) extension */
VGMSTREAM *temp_vgmstream = NULL; VGMSTREAM *temp_vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL; STREAMFILE* temp_sf = NULL;
/* standard RIFF, use subfile (seems doesn't use xwb loops) */ /* standard RIFF, use subfile (seems doesn't use xwb loops) */
VGM_ASSERT(xwb.loop_flag, "XWB: RIFF ATRAC9 loop flag found\n"); VGM_ASSERT(xwb.loop_flag, "XWB: RIFF ATRAC9 loop flag found\n");
temp_streamFile = setup_subfile_streamfile(streamFile, xwb.stream_offset,xwb.stream_size, "at9"); temp_sf = setup_subfile_streamfile(sf, xwb.stream_offset,xwb.stream_size, "at9");
if (!temp_streamFile) goto fail; if (!temp_sf) goto fail;
temp_vgmstream = init_vgmstream_riff(temp_streamFile); temp_vgmstream = init_vgmstream_riff(temp_sf);
close_streamfile(temp_streamFile); close_streamfile(temp_sf);
if (!temp_vgmstream) goto fail; if (!temp_vgmstream) goto fail;
temp_vgmstream->num_streams = vgmstream->num_streams; temp_vgmstream->num_streams = vgmstream->num_streams;
@ -594,7 +611,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
start_offset = xwb.stream_offset; start_offset = xwb.stream_offset;
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) ) if ( !vgmstream_open_stream(vgmstream,sf,start_offset) )
goto fail; goto fail;
return vgmstream; return vgmstream;
@ -605,13 +622,13 @@ fail:
/* ****************************************************************************** */ /* ****************************************************************************** */
static int get_xwb_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamFile) { static int get_xwb_name(char* buf, size_t maxsize, int target_subsong, xwb_header* xwb, STREAMFILE* sf) {
size_t read; size_t read;
if (!xwb->names_offset || !xwb->names_size || xwb->names_entry_size > maxsize) if (!xwb->names_offset || !xwb->names_size || xwb->names_entry_size > maxsize)
goto fail; goto fail;
read = read_string(buf,xwb->names_entry_size, xwb->names_offset + xwb->names_entry_size*(target_subsong-1),streamFile); read = read_string(buf,xwb->names_entry_size, xwb->names_offset + xwb->names_entry_size*(target_subsong-1),sf);
if (read == 0) goto fail; if (read == 0) goto fail;
return 1; return 1;
@ -620,11 +637,11 @@ fail:
return 0; return 0;
} }
static int get_xsb_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamFile) { static int get_xsb_name(char* buf, size_t maxsize, int target_subsong, xwb_header* xwb, STREAMFILE* sf) {
xsb_header xsb = {0}; xsb_header xsb = {0};
xsb.selected_stream = target_subsong - 1; xsb.selected_stream = target_subsong - 1;
if (!parse_xsb(&xsb, streamFile, xwb->wavebank_name)) if (!parse_xsb(&xsb, sf, xwb->wavebank_name))
goto fail; goto fail;
if ((xwb->version <= XACT1_1_MAX && xsb.version > XSB_XACT1_2_MAX) || if ((xwb->version <= XACT1_1_MAX && xsb.version > XSB_XACT1_2_MAX) ||
@ -649,12 +666,12 @@ static int get_wbh_name(char* buf, size_t maxsize, int target_subsong, xwb_heade
int version, name_count; int version, name_count;
off_t offset, name_number; off_t offset, name_number;
if (read_32bitBE(0x00, sf) != 0x57424844) /* "WBHD" */ if (read_u32be(0x00, sf) != 0x57424844) /* "WBHD" */
goto fail; goto fail;
version = read_32bitLE(0x04, sf); version = read_u32le(0x04, sf);
if (version != 1) if (version != 1)
goto fail; goto fail;
name_count = read_32bitLE(0x08, sf); name_count = read_u32le(0x08, sf);
if (selected_stream > name_count) if (selected_stream > name_count)
goto fail; goto fail;
@ -682,19 +699,19 @@ fail:
return 0; return 0;
} }
static void get_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamXwb) { static void get_name(char* buf, size_t maxsize, int target_subsong, xwb_header* xwb, STREAMFILE* sf_xwb) {
STREAMFILE *sf_name = NULL; STREAMFILE* sf_name = NULL;
int name_found; int name_found;
/* try to get the stream name in the .xwb, though they are very rarely included */ /* try to get the stream name in the .xwb, though they are very rarely included */
name_found = get_xwb_name(buf, maxsize, target_subsong, xwb, streamXwb); name_found = get_xwb_name(buf, maxsize, target_subsong, xwb, sf_xwb);
if (name_found) return; if (name_found) return;
/* try again in a companion files */ /* try again in a companion files */
if (xwb->version == 1) { if (xwb->version == 1) {
/* .wbh, a simple name container */ /* .wbh, a simple name container */
sf_name = open_streamfile_by_ext(streamXwb, "wbh"); sf_name = open_streamfile_by_ext(sf_xwb, "wbh");
if (!sf_name) return; /* rarely found [Pac-Man World 2 (Xbox)] */ if (!sf_name) return; /* rarely found [Pac-Man World 2 (Xbox)] */
name_found = get_wbh_name(buf, maxsize, target_subsong, xwb, sf_name); name_found = get_wbh_name(buf, maxsize, target_subsong, xwb, sf_name);
@ -702,7 +719,7 @@ static void get_name(char * buf, size_t maxsize, int target_subsong, xwb_header
} }
else { else {
/* .xsb, a comically complex cue format */ /* .xsb, a comically complex cue format */
sf_name = open_xsb_filename_pair(streamXwb); sf_name = open_xsb_filename_pair(sf_xwb);
if (!sf_name) return; /* not all xwb have xsb though */ if (!sf_name) return; /* not all xwb have xsb though */
name_found = get_xsb_name(buf, maxsize, target_subsong, xwb, sf_name); name_found = get_xsb_name(buf, maxsize, target_subsong, xwb, sf_name);

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