Updated VGMStream to r1050-3272-g842171b8
This commit is contained in:
parent
6a534ad900
commit
bb38853ee9
113 changed files with 11112 additions and 8439 deletions
|
@ -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 */,
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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*/
|
||||||
|
|
|
@ -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 */
|
||||||
/* ******************************************** */
|
/* ******************************************** */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
91
Frameworks/vgmstream/vgmstream/src/coding/mpeg_bitreader.h
Normal file
91
Frameworks/vgmstream/vgmstream/src/coding/mpeg_bitreader.h
Normal 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
|
|
@ -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};
|
||||||
|
@ -148,7 +149,7 @@ int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *
|
||||||
|
|
||||||
|
|
||||||
/* read first frame/granule, or PCM-only frame (found alone at the end of SCHl streams) */
|
/* read first frame/granule, or PCM-only frame (found alone at the end of SCHl streams) */
|
||||||
{
|
{
|
||||||
//;VGM_LOG("s%i: get granule0 at %lx\n", num_stream,stream->offset);
|
//;VGM_LOG("s%i: get granule0 at %lx\n", num_stream,stream->offset);
|
||||||
if (!ealayer3_skip_data(stream, data, num_stream, 1))
|
if (!ealayer3_skip_data(stream, data, num_stream, 1))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -168,15 +169,15 @@ int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *
|
||||||
|
|
||||||
if (!ealayer3_skip_data(stream, data, num_stream, 0))
|
if (!ealayer3_skip_data(stream, data, num_stream, 0))
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In EAL3 V2P sometimes there is a new SNS/SPS block between granules. Instead of trying to fix it here
|
/* In EAL3 V2P sometimes there is a new SNS/SPS block between granules. Instead of trying to fix it here
|
||||||
* or in blocked layout (too complex/patchy), SNS/SPS uses a custom streamfile that simply removes all
|
* or in blocked layout (too complex/patchy), SNS/SPS uses a custom streamfile that simply removes all
|
||||||
* block headers, so this parser only sees raw EALayer3 data. It also discards samples, which confuses
|
* block headers, so this parser only sees raw EALayer3 data. It also discards samples, which confuses
|
||||||
* blocked layout calculations
|
* blocked layout calculations
|
||||||
*
|
*
|
||||||
* Similarly (as V2P decodes and writes 1 granule at a time) stream can end in granule0. Since mpg123
|
* Similarly (as V2P decodes and writes 1 granule at a time) stream can end in granule0. Since mpg123
|
||||||
* decodes in pairs we detect and feed it a fake end granule1, to get the last granule0's 576 samples. */
|
* decodes in pairs we detect and feed it a fake end granule1, to get the last granule0's 576 samples. */
|
||||||
|
|
||||||
granule_found = 0;
|
granule_found = 0;
|
||||||
/* get second frame/granule (MPEG1 only) if first granule was found */
|
/* get second frame/granule (MPEG1 only) if first granule was found */
|
||||||
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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,319 +62,380 @@
|
||||||
#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 */
|
||||||
|
}
|
||||||
|
|
||||||
|
// NWADecode
|
||||||
|
static void decode_block(NWAData* nwa, const uint8_t* data, int outdatasize) {
|
||||||
|
sample d[2];
|
||||||
|
int i;
|
||||||
|
int shift = 0;
|
||||||
|
|
||||||
|
int dsize = outdatasize / (nwa->bps / 8);
|
||||||
|
int flip_flag = 0; /* stereo 用 */ //for stereo
|
||||||
|
int runlength = 0;
|
||||||
|
|
||||||
|
/* 最初のデータを読み込む */ //read initial data
|
||||||
|
for (i = 0; i < nwa->channels; i++) {
|
||||||
|
if (nwa->bps == 8) {
|
||||||
|
d[i] = get_s8(data);
|
||||||
|
data += 1;
|
||||||
|
}
|
||||||
|
else { /* nwa->bps == 16 */
|
||||||
|
d[i] = get_s16le(data);
|
||||||
|
data += 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < dsize; i++) {
|
||||||
|
if (runlength == 0) { /* コピーループ中でないならデータ読み込み */ //read data if not in the copy loop
|
||||||
|
int type = getbits(&data, &shift, 3);
|
||||||
|
|
||||||
|
/* type により分岐:0, 1-6, 7 */ //fork depending on type
|
||||||
|
if (type == 7) {
|
||||||
|
/* 7 : 大きな差分 */ //big diff
|
||||||
|
/* RunLength() 有効時(CompLevel==5, 音声ファイル) では無効 */ //invalid when using RLE (comp=5, voice file)
|
||||||
|
if (getbits(&data, &shift, 1) == 1) {
|
||||||
|
d[flip_flag] = 0; /* 未使用 */ //unused
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int BITS, SHIFT;
|
||||||
|
if (nwa->complevel >= 3) {
|
||||||
|
BITS = 8;
|
||||||
|
SHIFT = 9;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BITS = 8 - nwa->complevel;
|
||||||
|
SHIFT = 2 + 7 + nwa->complevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const int MASK1 = (1 << (BITS - 1));
|
||||||
|
const int MASK2 = (1 << (BITS - 1)) - 1;
|
||||||
|
int b = getbits(&data, &shift, BITS);
|
||||||
|
if (b & MASK1)
|
||||||
|
d[flip_flag] -= (b & MASK2) << SHIFT;
|
||||||
|
else
|
||||||
|
d[flip_flag] += (b & MASK2) << SHIFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type != 0) {
|
||||||
|
/* 1-6 : 通常の差分 */ //normal diff
|
||||||
|
int BITS, SHIFT;
|
||||||
|
if (nwa->complevel >= 3) {
|
||||||
|
BITS = nwa->complevel + 3;
|
||||||
|
SHIFT = 1 + type;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BITS = 5 - nwa->complevel;
|
||||||
|
SHIFT = 2 + type + nwa->complevel;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const int MASK1 = (1 << (BITS - 1));
|
||||||
|
const int MASK2 = (1 << (BITS - 1)) - 1;
|
||||||
|
int b = getbits(&data, &shift, BITS);
|
||||||
|
if (b & MASK1)
|
||||||
|
d[flip_flag] -= (b & MASK2) << SHIFT;
|
||||||
|
else
|
||||||
|
d[flip_flag] += (b & MASK2) << SHIFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { /* type == 0 */
|
||||||
|
/* ランレングス圧縮なしの場合はなにもしない */ //does nothing in case of no RLE compression
|
||||||
|
if (nwa->use_runlength) {
|
||||||
|
/* ランレングス圧縮ありの場合 */ //in case of RLE compression
|
||||||
|
runlength = getbits(&data, &shift, 1);
|
||||||
|
if (runlength == 1) {
|
||||||
|
runlength = getbits(&data, &shift, 2);
|
||||||
|
if (runlength == 3) {
|
||||||
|
runlength = getbits(&data, &shift, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
runlength--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nwa->bps == 8) {
|
||||||
|
nwa->outdata[i] = d[flip_flag] * 256; //extra (original outputs 8-bit)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nwa->outdata[i] = d[flip_flag];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nwa->channels == 2)
|
||||||
|
flip_flag ^= 1; /* channel 切り替え */ //channel swap
|
||||||
|
}
|
||||||
|
|
||||||
|
nwa->samples_in_buffer = dsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//NWAData::Decode
|
||||||
|
int nwalib_decode(STREAMFILE* sf, NWAData* nwa) {
|
||||||
|
/* some wav/pcm handling skipped here */
|
||||||
|
|
||||||
|
/* 今回読み込む/デコードするデータの大きさを得る */ //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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
//NWAFILE::Seek (not too similar)
|
||||||
nwa_decode_block(NWAData *nwa)
|
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);
|
||||||
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];
|
|
||||||
int i;
|
|
||||||
int shift = 0;
|
|
||||||
off_t offset = nwa->offsets[nwa->curblock];
|
|
||||||
int dsize = curblocksize / (nwa->bps / 8);
|
|
||||||
int flip_flag = 0; /* stereo 用 */
|
|
||||||
int runlength = 0;
|
|
||||||
|
|
||||||
/* read initial sample value */
|
|
||||||
for (i=0;i<nwa->channels;i++)
|
|
||||||
{
|
|
||||||
if (nwa->bps == 8) { d[i] = read_8bit(offset,nwa->file); }
|
|
||||||
else /* bps == 16 */
|
|
||||||
{
|
|
||||||
d[i] = read_16bitLE(offset,nwa->file);
|
|
||||||
offset += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < dsize; i++)
|
|
||||||
{
|
|
||||||
if (runlength == 0)
|
|
||||||
{ /* コピーループ中でないならデータ読み込み */
|
|
||||||
int type = getbits(nwa->file, &offset, &shift, 3);
|
|
||||||
/* type により分岐:0, 1-6, 7 */
|
|
||||||
if (type == 7)
|
|
||||||
{
|
|
||||||
/* 7 : 大きな差分 */
|
|
||||||
/* RunLength() 有効時(CompLevel==5, 音声ファイル) では無効 */
|
|
||||||
if (getbits(nwa->file, &offset, &shift, 1) == 1)
|
|
||||||
{
|
|
||||||
d[flip_flag] = 0; /* 未使用 */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int BITS, SHIFT;
|
|
||||||
if (nwa->complevel >= 3)
|
|
||||||
{
|
|
||||||
BITS = 8;
|
|
||||||
SHIFT = 9;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BITS = 8 - nwa->complevel;
|
|
||||||
SHIFT = 2 + 7 + nwa->complevel;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const int MASK1 = (1 << (BITS - 1));
|
|
||||||
const int MASK2 = (1 << (BITS - 1)) - 1;
|
|
||||||
int b = getbits(nwa->file, &offset, &shift, BITS);
|
|
||||||
if (b & MASK1)
|
|
||||||
d[flip_flag] -= (b & MASK2) << SHIFT;
|
|
||||||
else
|
|
||||||
d[flip_flag] += (b & MASK2) << SHIFT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type != 0)
|
|
||||||
{
|
|
||||||
/* 1-6 : 通常の差分 */
|
|
||||||
int BITS, SHIFT;
|
|
||||||
if (nwa->complevel >= 3)
|
|
||||||
{
|
|
||||||
BITS = nwa->complevel + 3;
|
|
||||||
SHIFT = 1 + type;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BITS = 5 - nwa->complevel;
|
|
||||||
SHIFT = 2 + type + nwa->complevel;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const int MASK1 = (1 << (BITS - 1));
|
|
||||||
const int MASK2 = (1 << (BITS - 1)) - 1;
|
|
||||||
int b = getbits(nwa->file, &offset, &shift, BITS);
|
|
||||||
if (b & MASK1)
|
|
||||||
d[flip_flag] -= (b & MASK2) << SHIFT;
|
|
||||||
else
|
|
||||||
d[flip_flag] += (b & MASK2) << SHIFT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ /* type == 0 */
|
|
||||||
/* ランレングス圧縮なしの場合はなにもしない */
|
|
||||||
if (use_runlength(nwa))
|
|
||||||
{
|
|
||||||
/* ランレングス圧縮ありの場合 */
|
|
||||||
runlength = getbits(nwa->file, &offset, &shift, 1);
|
|
||||||
if (runlength == 1)
|
|
||||||
{
|
|
||||||
runlength = getbits(nwa->file, &offset, &shift, 2);
|
|
||||||
if (runlength == 3)
|
|
||||||
{
|
|
||||||
runlength = getbits(nwa->file, &offset, &shift, 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
runlength--;
|
|
||||||
}
|
|
||||||
if (nwa->bps == 8)
|
|
||||||
{
|
|
||||||
nwa->buffer[i] = d[flip_flag]*0x100;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nwa->buffer[i] = d[flip_flag];
|
|
||||||
}
|
|
||||||
nwa->samples_in_buffer++;
|
|
||||||
if (nwa->channels == 2)
|
|
||||||
flip_flag ^= 1; /* channel 切り替え */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nwa->curblock++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
seek_nwa(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;
|
||||||
|
}
|
||||||
|
|
|
@ -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 blocks; /* block count */
|
int complevel; /* compression level */
|
||||||
int datasize; /* all data size */
|
int dummy; /* ? : 0x00 */
|
||||||
int compdatasize; /* compressed data size */
|
|
||||||
int samplecount; /* all samples */
|
int blocks; /* block count */
|
||||||
int blocksize; /* samples per block */
|
int datasize; /* all data size */
|
||||||
int restsize; /* samples of the last block */
|
|
||||||
|
int compdatasize; /* compressed data size */
|
||||||
|
int samplecount; /* all samples */
|
||||||
|
int blocksize; /* samples per 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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
103
Frameworks/vgmstream/vgmstream/src/coding/vorbis_bitreader.h
Normal file
103
Frameworks/vgmstream/vgmstream/src/coding/vorbis_bitreader.h
Normal 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
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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) */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
1481
Frameworks/vgmstream/vgmstream/src/decode.c
Normal file
1481
Frameworks/vgmstream/vgmstream/src/decode.c
Normal file
File diff suppressed because it is too large
Load diff
32
Frameworks/vgmstream/vgmstream/src/decode.h
Normal file
32
Frameworks/vgmstream/vgmstream/src/decode.h
Normal 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
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* handle looping by finding loop segment and loop_start inside that segment */
|
/* detect segment change and restart (after loop, but before decode, to allow looping to kick in) */
|
||||||
loop_segment = 0;
|
if (vgmstream->samples_into_block >= samples_this_block) {
|
||||||
total_samples = 0;
|
data->current_segment++;
|
||||||
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) {
|
if (data->current_segment >= data->segment_count) { /* when decoding more than num_samples */
|
||||||
loop_samples_skip = vgmstream->loop_sample - total_samples;
|
VGM_LOG("SEGMENTED: reached last segment\n");
|
||||||
break; /* loop_start falls within loop_segment's samples */
|
goto decode_fail;
|
||||||
}
|
|
||||||
total_samples += segment_samples;
|
|
||||||
loop_segment++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loop_segment == data->segment_count) {
|
/* in case of looping spanning multiple segments */
|
||||||
VGM_LOG("segmented_layout: can't find loop segment\n");
|
reset_vgmstream(data->segments[data->current_segment]);
|
||||||
loop_segment = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
data->current_segment = loop_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,22 +147,27 @@ 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);
|
||||||
data->segments[i]->loop_flag = 0;
|
|
||||||
|
/* config allows internal loops */
|
||||||
|
if (!data->segments[i]->config_enabled) {
|
||||||
|
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
|
||||||
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
goto fail;
|
||||||
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;
|
|
||||||
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);
|
||||||
|
|
51
Frameworks/vgmstream/vgmstream/src/meta/adp_konami.c
Normal file
51
Frameworks/vgmstream/vgmstream/src/meta/adp_konami.c
Normal 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;
|
||||||
|
}
|
|
@ -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 */
|
||||||
|
|
|
@ -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[] = {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
codec = read_16bitBE(0x08,streamFile);
|
|
||||||
channel_count = read_16bitBE(0x0c,streamFile);
|
|
||||||
loop_flag = read_16bitBE(0x0e,streamFile);
|
|
||||||
//max_block = read_32bitBE(0x20,streamFile);
|
|
||||||
|
|
||||||
start_offset = 0x40;
|
|
||||||
if (read_32bitBE(start_offset,streamFile) != 0x424C434B) /* "BLCK" */
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
/* 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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
97
Frameworks/vgmstream/vgmstream/src/meta/bsf.c
Normal file
97
Frameworks/vgmstream/vgmstream/src/meta/bsf.c
Normal 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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
54
Frameworks/vgmstream/vgmstream/src/meta/dsb.c
Normal file
54
Frameworks/vgmstream/vgmstream/src/meta/dsb.c
Normal 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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
vgmstream = init_vgmstream_fsb5(temp_sf);
|
if (read_u32be(0x00, temp_sf) == 0x46534235) {
|
||||||
close_streamfile(temp_sf);
|
vgmstream = init_vgmstream_fsb5(temp_sf);
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
}
|
||||||
|
else { //other flag?
|
||||||
|
vgmstream = init_vgmstream_fsb_encrypted(temp_sf);
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
}
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
60
Frameworks/vgmstream/vgmstream/src/meta/ktsc.c
Normal file
60
Frameworks/vgmstream/vgmstream/src/meta/ktsc.c
Normal 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;
|
||||||
|
}
|
|
@ -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) */
|
||||||
|
|
|
@ -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*/
|
||||||
|
|
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(0x3c,sf) == 0x3F800000)) /* Tomb Raider Underworld */
|
read_u32(0x38,sf) == 0x4530F000 || /* Avengers */
|
||||||
|
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,47 +234,60 @@ 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++) {
|
||||||
int layer_channels = 1;
|
|
||||||
|
|
||||||
|
|
||||||
/* build the layer VGMSTREAM */
|
|
||||||
data->layers[i] = allocate_vgmstream(layer_channels, 0);
|
|
||||||
if (!data->layers[i]) goto fail;
|
|
||||||
|
|
||||||
data->layers[i]->sample_rate = vgmstream->sample_rate;
|
|
||||||
data->layers[i]->num_samples = vgmstream->num_samples;
|
|
||||||
|
|
||||||
|
switch(codec) {
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
{
|
case XMA1: {
|
||||||
uint8_t buf[0x100];
|
uint8_t buf[0x100];
|
||||||
int bytes;
|
int bytes;
|
||||||
size_t stream_size;
|
size_t stream_size;
|
||||||
|
int layer_channels = 1;
|
||||||
|
|
||||||
temp_sf = setup_mul_streamfile(sf_data, big_endian, i, layers);
|
temp_sf = setup_mul_streamfile(sf, offset, big_endian, i, layers, NULL);
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
stream_size = get_streamfile_size(temp_sf);
|
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);
|
/* build the layer VGMSTREAM */
|
||||||
data->layers[i]->codec_data = init_ffmpeg_header_offset(temp_sf, buf,bytes, 0x00, stream_size);
|
data->layers[i] = allocate_vgmstream(layer_channels, 0);
|
||||||
if (!data->layers[i]->codec_data) goto fail;
|
if (!data->layers[i]) goto fail;
|
||||||
|
|
||||||
data->layers[i]->coding_type = coding_FFmpeg;
|
data->layers[i]->sample_rate = vgmstream->sample_rate;
|
||||||
data->layers[i]->layout_type = layout_none;
|
data->layers[i]->num_samples = vgmstream->num_samples;
|
||||||
data->layers[i]->stream_size = stream_size;
|
|
||||||
|
|
||||||
xma_fix_raw_samples(data->layers[i], temp_sf, 0x00,stream_size, 0, 0,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);
|
||||||
|
if (!data->layers[i]->codec_data) goto fail;
|
||||||
|
|
||||||
close_streamfile(temp_sf);
|
data->layers[i]->coding_type = coding_FFmpeg;
|
||||||
temp_sf = NULL;
|
data->layers[i]->layout_type = layout_none;
|
||||||
}
|
data->layers[i]->stream_size = stream_size;
|
||||||
#else
|
|
||||||
goto fail;
|
xma_fix_raw_samples(data->layers[i], temp_sf, 0x00,stream_size, 0, 0,0); /* ? */
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#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);
|
||||||
|
temp_sf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
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:
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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];
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 == 0x0045039A && unknown2 == 0x00108920) { /* Super Farm (PS2) */
|
&& 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) */
|
||||||
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
|
}
|
||||||
&& unknown1 == 0xCCCCCCCC && unknown2 == 0xCCCCCCCC) { /* Sitting Ducks (PS2) */
|
else if (data_size / 2 == file_size - 0x10
|
||||||
|
&& 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
|
}
|
||||||
&& unknown1 == 0xCCCCCCCC && unknown2 == 0xCCCCCCCC) { /* The Mummy: The Animated Series (PS2) */
|
else if (data_size == file_size - 0x10
|
||||||
|
&& 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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
20
Frameworks/vgmstream/vgmstream/src/meta/sab_streamfile.h
Normal file
20
Frameworks/vgmstream/vgmstream/src/meta/sab_streamfile.h
Normal 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_ */
|
|
@ -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 */
|
/* PS3 AC3 consistently has 256 encoder delay samples, and there are ~1000-2000 samples after num_samples.
|
||||||
if (ffmpeg_data->skipSamples <= 0) {
|
* Skipping them marginally improves full loops in some Tokyo Jungle tracks (ex. a_1.sgd). */
|
||||||
/* PS3 AC3 consistently has 256 encoder delay samples, and there are ~1000-2000 samples after num_samples.
|
ffmpeg_set_skip_samples(vgmstream->codec_data, 256);
|
||||||
* Skipping them marginally improves full loops in some Tokyo Jungle tracks (ex. a_1.sgd). */
|
|
||||||
ffmpeg_set_skip_samples(ffmpeg_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;
|
||||||
}
|
}
|
||||||
|
|
29
Frameworks/vgmstream/vgmstream/src/meta/silence.c
Normal file
29
Frameworks/vgmstream/vgmstream/src/meta/silence.c
Normal 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;
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
46
Frameworks/vgmstream/vgmstream/src/meta/svag_snk.c
Normal file
46
Frameworks/vgmstream/vgmstream/src/meta/svag_snk.c
Normal 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;
|
||||||
|
}
|
|
@ -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
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -404,7 +421,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
/* for XWB v22 (and below?) this seems normal [Project Gotham Racing (X360)] */
|
/* for XWB v22 (and below?) this seems normal [Project Gotham Racing (X360)] */
|
||||||
if (xwb.num_samples == 0) {
|
if (xwb.num_samples == 0) {
|
||||||
xwb.num_samples = msd.num_samples;
|
xwb.num_samples = msd.num_samples;
|
||||||
xwb.fix_xma_num_samples = 1;
|
xwb.fix_xma_num_samples = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
Loading…
Reference in a new issue