Updated VGMStream to r1050-3043-g295ffac0
This commit is contained in:
parent
3cdebc8425
commit
ebfb7e1207
40 changed files with 4297 additions and 2319 deletions
|
@ -312,7 +312,6 @@
|
||||||
836F6FA318BDC2190095E648 /* naomi_spsd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6718BDC2180095E648 /* naomi_spsd.c */; };
|
836F6FA318BDC2190095E648 /* naomi_spsd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6718BDC2180095E648 /* naomi_spsd.c */; };
|
||||||
836F6FA418BDC2190095E648 /* nds_hwas.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6818BDC2180095E648 /* nds_hwas.c */; };
|
836F6FA418BDC2190095E648 /* nds_hwas.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6818BDC2180095E648 /* nds_hwas.c */; };
|
||||||
836F6FA518BDC2190095E648 /* nds_rrds.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6918BDC2180095E648 /* nds_rrds.c */; };
|
836F6FA518BDC2190095E648 /* nds_rrds.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6918BDC2180095E648 /* nds_rrds.c */; };
|
||||||
836F6FA618BDC2190095E648 /* nds_sad.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6A18BDC2180095E648 /* nds_sad.c */; };
|
|
||||||
836F6FA718BDC2190095E648 /* nds_strm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6B18BDC2180095E648 /* nds_strm.c */; };
|
836F6FA718BDC2190095E648 /* nds_strm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6B18BDC2180095E648 /* nds_strm.c */; };
|
||||||
836F6FA818BDC2190095E648 /* nds_swav.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6C18BDC2180095E648 /* nds_swav.c */; };
|
836F6FA818BDC2190095E648 /* nds_swav.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6C18BDC2180095E648 /* nds_swav.c */; };
|
||||||
836F6FA918BDC2190095E648 /* ngc_adpdtk.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6D18BDC2180095E648 /* ngc_adpdtk.c */; };
|
836F6FA918BDC2190095E648 /* ngc_adpdtk.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6D18BDC2180095E648 /* ngc_adpdtk.c */; };
|
||||||
|
@ -579,6 +578,14 @@
|
||||||
83C7282922BC8C1500678B4A /* mixing.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7282522BC8C1400678B4A /* mixing.c */; };
|
83C7282922BC8C1500678B4A /* mixing.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7282522BC8C1400678B4A /* mixing.c */; };
|
||||||
83C7282A22BC8C1500678B4A /* plugins.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7282622BC8C1400678B4A /* plugins.c */; };
|
83C7282A22BC8C1500678B4A /* plugins.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7282622BC8C1400678B4A /* plugins.c */; };
|
||||||
83CD428A1F787879000F77BE /* libswresample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83CD42851F787878000F77BE /* libswresample.a */; };
|
83CD428A1F787879000F77BE /* libswresample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83CD42851F787878000F77BE /* libswresample.a */; };
|
||||||
|
83D2007A248DDB770048BD24 /* fsb_encrypted_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83D20072248DDB760048BD24 /* fsb_encrypted_streamfile.h */; };
|
||||||
|
83D2007B248DDB770048BD24 /* mups_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83D20073248DDB760048BD24 /* mups_streamfile.h */; };
|
||||||
|
83D2007C248DDB770048BD24 /* ktsr.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20074248DDB760048BD24 /* ktsr.c */; };
|
||||||
|
83D2007D248DDB770048BD24 /* kat.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20075248DDB760048BD24 /* kat.c */; };
|
||||||
|
83D2007E248DDB770048BD24 /* pcm_success.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20076248DDB770048BD24 /* pcm_success.c */; };
|
||||||
|
83D2007F248DDB770048BD24 /* mups.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20077248DDB770048BD24 /* mups.c */; };
|
||||||
|
83D20080248DDB770048BD24 /* sadf.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20078248DDB770048BD24 /* sadf.c */; };
|
||||||
|
83D20081248DDB770048BD24 /* sadl.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20079248DDB770048BD24 /* sadl.c */; };
|
||||||
83D2F58E2356B266007646ED /* libopus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D2F58A2356B266007646ED /* libopus.a */; };
|
83D2F58E2356B266007646ED /* libopus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D2F58A2356B266007646ED /* libopus.a */; };
|
||||||
83D731891A749D1500CA1366 /* g719.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D7313E1A74968A00CA1366 /* g719.framework */; };
|
83D731891A749D1500CA1366 /* g719.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D7313E1A74968A00CA1366 /* g719.framework */; };
|
||||||
83D7318A1A749D2200CA1366 /* g719.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83D7313E1A74968A00CA1366 /* g719.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
83D7318A1A749D2200CA1366 /* g719.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83D7313E1A74968A00CA1366 /* g719.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
|
@ -1019,7 +1026,6 @@
|
||||||
836F6E6718BDC2180095E648 /* naomi_spsd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = naomi_spsd.c; sourceTree = "<group>"; };
|
836F6E6718BDC2180095E648 /* naomi_spsd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = naomi_spsd.c; sourceTree = "<group>"; };
|
||||||
836F6E6818BDC2180095E648 /* nds_hwas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_hwas.c; sourceTree = "<group>"; };
|
836F6E6818BDC2180095E648 /* nds_hwas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_hwas.c; sourceTree = "<group>"; };
|
||||||
836F6E6918BDC2180095E648 /* nds_rrds.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_rrds.c; sourceTree = "<group>"; };
|
836F6E6918BDC2180095E648 /* nds_rrds.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_rrds.c; sourceTree = "<group>"; };
|
||||||
836F6E6A18BDC2180095E648 /* nds_sad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_sad.c; sourceTree = "<group>"; };
|
|
||||||
836F6E6B18BDC2180095E648 /* nds_strm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_strm.c; sourceTree = "<group>"; };
|
836F6E6B18BDC2180095E648 /* nds_strm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_strm.c; sourceTree = "<group>"; };
|
||||||
836F6E6C18BDC2180095E648 /* nds_swav.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_swav.c; sourceTree = "<group>"; };
|
836F6E6C18BDC2180095E648 /* nds_swav.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_swav.c; sourceTree = "<group>"; };
|
||||||
836F6E6D18BDC2180095E648 /* ngc_adpdtk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_adpdtk.c; sourceTree = "<group>"; };
|
836F6E6D18BDC2180095E648 /* ngc_adpdtk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_adpdtk.c; sourceTree = "<group>"; };
|
||||||
|
@ -1285,6 +1291,14 @@
|
||||||
83C7282522BC8C1400678B4A /* mixing.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mixing.c; sourceTree = "<group>"; };
|
83C7282522BC8C1400678B4A /* mixing.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mixing.c; sourceTree = "<group>"; };
|
||||||
83C7282622BC8C1400678B4A /* plugins.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = plugins.c; sourceTree = "<group>"; };
|
83C7282622BC8C1400678B4A /* plugins.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = plugins.c; sourceTree = "<group>"; };
|
||||||
83CD42851F787878000F77BE /* libswresample.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libswresample.a; path = ../../ThirdParty/ffmpeg/lib/libswresample.a; sourceTree = "<group>"; };
|
83CD42851F787878000F77BE /* libswresample.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libswresample.a; path = ../../ThirdParty/ffmpeg/lib/libswresample.a; sourceTree = "<group>"; };
|
||||||
|
83D20072248DDB760048BD24 /* fsb_encrypted_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fsb_encrypted_streamfile.h; sourceTree = "<group>"; };
|
||||||
|
83D20073248DDB760048BD24 /* mups_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mups_streamfile.h; sourceTree = "<group>"; };
|
||||||
|
83D20074248DDB760048BD24 /* ktsr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ktsr.c; sourceTree = "<group>"; };
|
||||||
|
83D20075248DDB760048BD24 /* kat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kat.c; sourceTree = "<group>"; };
|
||||||
|
83D20076248DDB770048BD24 /* pcm_success.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pcm_success.c; sourceTree = "<group>"; };
|
||||||
|
83D20077248DDB770048BD24 /* mups.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mups.c; sourceTree = "<group>"; };
|
||||||
|
83D20078248DDB770048BD24 /* sadf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sadf.c; sourceTree = "<group>"; };
|
||||||
|
83D20079248DDB770048BD24 /* sadl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sadl.c; sourceTree = "<group>"; };
|
||||||
83D2F58A2356B266007646ED /* libopus.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libopus.a; path = ../../ThirdParty/ffmpeg/lib/libopus.a; sourceTree = "<group>"; };
|
83D2F58A2356B266007646ED /* libopus.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libopus.a; path = ../../ThirdParty/ffmpeg/lib/libopus.a; sourceTree = "<group>"; };
|
||||||
83D731381A74968900CA1366 /* g719.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = g719.xcodeproj; path = ../g719/g719.xcodeproj; sourceTree = "<group>"; };
|
83D731381A74968900CA1366 /* g719.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = g719.xcodeproj; path = ../g719/g719.xcodeproj; sourceTree = "<group>"; };
|
||||||
83D7318B1A749EEE00CA1366 /* g719_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = g719_decoder.c; sourceTree = "<group>"; };
|
83D7318B1A749EEE00CA1366 /* g719_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = g719_decoder.c; sourceTree = "<group>"; };
|
||||||
|
@ -1699,6 +1713,7 @@
|
||||||
838BDB6D1D3B043C0022CA6F /* ffmpeg.c */,
|
838BDB6D1D3B043C0022CA6F /* ffmpeg.c */,
|
||||||
836F6E4B18BDC2180095E648 /* ffw.c */,
|
836F6E4B18BDC2180095E648 /* ffw.c */,
|
||||||
8349A8FD1FE6257F00E26435 /* flx.c */,
|
8349A8FD1FE6257F00E26435 /* flx.c */,
|
||||||
|
83D20072248DDB760048BD24 /* fsb_encrypted_streamfile.h */,
|
||||||
83A21F81201D8981000F04B9 /* fsb_encrypted.c */,
|
83A21F81201D8981000F04B9 /* fsb_encrypted.c */,
|
||||||
834FE0C4215C79E6000A5D3D /* fsb_interleave_streamfile.h */,
|
834FE0C4215C79E6000A5D3D /* fsb_interleave_streamfile.h */,
|
||||||
83A21F7E201D8980000F04B9 /* fsb_keys.h */,
|
83A21F7E201D8980000F04B9 /* fsb_keys.h */,
|
||||||
|
@ -1734,9 +1749,11 @@
|
||||||
836F6E5818BDC2180095E648 /* ivb.c */,
|
836F6E5818BDC2180095E648 /* ivb.c */,
|
||||||
837CEAE923487F2B00E62A4A /* jstm_streamfile.h */,
|
837CEAE923487F2B00E62A4A /* jstm_streamfile.h */,
|
||||||
837CEAEF23487F2C00E62A4A /* jstm.c */,
|
837CEAEF23487F2C00E62A4A /* jstm.c */,
|
||||||
|
83D20075248DDB760048BD24 /* kat.c */,
|
||||||
834FE0C3215C79E6000A5D3D /* kma9_streamfile.h */,
|
834FE0C3215C79E6000A5D3D /* kma9_streamfile.h */,
|
||||||
83A21F83201D8981000F04B9 /* kma9.c */,
|
83A21F83201D8981000F04B9 /* kma9.c */,
|
||||||
836F6E5918BDC2180095E648 /* kraw.c */,
|
836F6E5918BDC2180095E648 /* kraw.c */,
|
||||||
|
83D20074248DDB760048BD24 /* ktsr.c */,
|
||||||
830EBE122004656E0023AA10 /* ktss.c */,
|
830EBE122004656E0023AA10 /* ktss.c */,
|
||||||
8373342423F60CDB00DE14DC /* kwb.c */,
|
8373342423F60CDB00DE14DC /* kwb.c */,
|
||||||
8373341F23F60CDB00DE14DC /* lrmd_streamfile.h */,
|
8373341F23F60CDB00DE14DC /* lrmd_streamfile.h */,
|
||||||
|
@ -1764,6 +1781,8 @@
|
||||||
83C7280322BC893A00678B4A /* mtaf.c */,
|
83C7280322BC893A00678B4A /* mtaf.c */,
|
||||||
83031ED5243C510400C3F3E0 /* mul_streamfile.h */,
|
83031ED5243C510400C3F3E0 /* mul_streamfile.h */,
|
||||||
832BF81221E05149006F50F1 /* mul.c */,
|
832BF81221E05149006F50F1 /* mul.c */,
|
||||||
|
83D20073248DDB760048BD24 /* mups_streamfile.h */,
|
||||||
|
83D20077248DDB770048BD24 /* mups.c */,
|
||||||
836F6E6218BDC2180095E648 /* mus_acm.c */,
|
836F6E6218BDC2180095E648 /* mus_acm.c */,
|
||||||
83C7280622BC893B00678B4A /* mus_vc.c */,
|
83C7280622BC893B00678B4A /* mus_vc.c */,
|
||||||
836F6E6318BDC2180095E648 /* musc.c */,
|
836F6E6318BDC2180095E648 /* musc.c */,
|
||||||
|
@ -1776,7 +1795,6 @@
|
||||||
836F6E6718BDC2180095E648 /* naomi_spsd.c */,
|
836F6E6718BDC2180095E648 /* naomi_spsd.c */,
|
||||||
836F6E6818BDC2180095E648 /* nds_hwas.c */,
|
836F6E6818BDC2180095E648 /* nds_hwas.c */,
|
||||||
836F6E6918BDC2180095E648 /* nds_rrds.c */,
|
836F6E6918BDC2180095E648 /* nds_rrds.c */,
|
||||||
836F6E6A18BDC2180095E648 /* nds_sad.c */,
|
|
||||||
830165991F256BD000CA0941 /* nds_strm_ffta2.c */,
|
830165991F256BD000CA0941 /* nds_strm_ffta2.c */,
|
||||||
836F6E6B18BDC2180095E648 /* nds_strm.c */,
|
836F6E6B18BDC2180095E648 /* nds_strm.c */,
|
||||||
836F6E6C18BDC2180095E648 /* nds_swav.c */,
|
836F6E6C18BDC2180095E648 /* nds_swav.c */,
|
||||||
|
@ -1822,6 +1840,7 @@
|
||||||
8349A8F01FE6257C00E26435 /* pc_ast.c */,
|
8349A8F01FE6257C00E26435 /* pc_ast.c */,
|
||||||
836F6E8618BDC2180095E648 /* pc_mxst.c */,
|
836F6E8618BDC2180095E648 /* pc_mxst.c */,
|
||||||
8306B0D12098458F000302D4 /* pcm_sre.c */,
|
8306B0D12098458F000302D4 /* pcm_sre.c */,
|
||||||
|
83D20076248DDB770048BD24 /* pcm_success.c */,
|
||||||
836F6E8B18BDC2180095E648 /* pona.c */,
|
836F6E8B18BDC2180095E648 /* pona.c */,
|
||||||
836F6E8C18BDC2180095E648 /* pos.c */,
|
836F6E8C18BDC2180095E648 /* pos.c */,
|
||||||
8306B0C52098458D000302D4 /* ppst_streamfile.h */,
|
8306B0C52098458D000302D4 /* ppst_streamfile.h */,
|
||||||
|
@ -1907,6 +1926,8 @@
|
||||||
836F6EE918BDC2190095E648 /* rwx.c */,
|
836F6EE918BDC2190095E648 /* rwx.c */,
|
||||||
836F6EEA18BDC2190095E648 /* s14_sss.c */,
|
836F6EEA18BDC2190095E648 /* s14_sss.c */,
|
||||||
8349A8F11FE6257D00E26435 /* sab.c */,
|
8349A8F11FE6257D00E26435 /* sab.c */,
|
||||||
|
83D20078248DDB770048BD24 /* sadf.c */,
|
||||||
|
83D20079248DDB770048BD24 /* sadl.c */,
|
||||||
836F6EEB18BDC2190095E648 /* sat_baka.c */,
|
836F6EEB18BDC2190095E648 /* sat_baka.c */,
|
||||||
836F6EEC18BDC2190095E648 /* sat_dvi.c */,
|
836F6EEC18BDC2190095E648 /* sat_dvi.c */,
|
||||||
836F6EED18BDC2190095E648 /* sat_sap.c */,
|
836F6EED18BDC2190095E648 /* sat_sap.c */,
|
||||||
|
@ -2072,6 +2093,7 @@
|
||||||
834FE0ED215C79ED000A5D3D /* fsb_interleave_streamfile.h in Headers */,
|
834FE0ED215C79ED000A5D3D /* fsb_interleave_streamfile.h in Headers */,
|
||||||
8351F32E2212B57000A606E4 /* ubi_bao_streamfile.h in Headers */,
|
8351F32E2212B57000A606E4 /* ubi_bao_streamfile.h in Headers */,
|
||||||
8349A9111FE6258200E26435 /* bar_streamfile.h in Headers */,
|
8349A9111FE6258200E26435 /* bar_streamfile.h in Headers */,
|
||||||
|
83D2007A248DDB770048BD24 /* fsb_encrypted_streamfile.h in Headers */,
|
||||||
836F6F2718BDC2190095E648 /* g72x_state.h in Headers */,
|
836F6F2718BDC2190095E648 /* g72x_state.h in Headers */,
|
||||||
83FC176F23AC58D100E1025F /* cri_utf.h in Headers */,
|
83FC176F23AC58D100E1025F /* cri_utf.h in Headers */,
|
||||||
83C7282822BC8C1500678B4A /* mixing.h in Headers */,
|
83C7282822BC8C1500678B4A /* mixing.h in Headers */,
|
||||||
|
@ -2115,6 +2137,7 @@
|
||||||
8373341D23F60C7B00DE14DC /* g7221_decoder_lib.h in Headers */,
|
8373341D23F60C7B00DE14DC /* g7221_decoder_lib.h in Headers */,
|
||||||
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 */,
|
||||||
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 */,
|
||||||
|
@ -2167,7 +2190,7 @@
|
||||||
836F6B3018BDB8880095E648 /* Project object */ = {
|
836F6B3018BDB8880095E648 /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 0940;
|
LastUpgradeCheck = 1150;
|
||||||
ORGANIZATIONNAME = "Christopher Snowhill";
|
ORGANIZATIONNAME = "Christopher Snowhill";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
836F6B3818BDB8880095E648 = {
|
836F6B3818BDB8880095E648 = {
|
||||||
|
@ -2384,6 +2407,7 @@
|
||||||
834FE105215C79ED000A5D3D /* xmd.c in Sources */,
|
834FE105215C79ED000A5D3D /* xmd.c in Sources */,
|
||||||
837CEADA23487E8300E62A4A /* acb.c in Sources */,
|
837CEADA23487E8300E62A4A /* acb.c in Sources */,
|
||||||
834FE0F6215C79ED000A5D3D /* derf.c in Sources */,
|
834FE0F6215C79ED000A5D3D /* derf.c in Sources */,
|
||||||
|
83D20081248DDB770048BD24 /* sadl.c in Sources */,
|
||||||
836F6F8B18BDC2190095E648 /* genh.c in Sources */,
|
836F6F8B18BDC2190095E648 /* genh.c in Sources */,
|
||||||
83C7281922BC893D00678B4A /* fsb5_fev.c in Sources */,
|
83C7281922BC893D00678B4A /* fsb5_fev.c in Sources */,
|
||||||
8349A8EA1FE6253900E26435 /* blocked_ea_schl.c in Sources */,
|
8349A8EA1FE6253900E26435 /* blocked_ea_schl.c in Sources */,
|
||||||
|
@ -2475,7 +2499,9 @@
|
||||||
836F6FD318BDC2190095E648 /* ps2_ccc.c in Sources */,
|
836F6FD318BDC2190095E648 /* ps2_ccc.c in Sources */,
|
||||||
83C7281C22BC893D00678B4A /* sfh.c in Sources */,
|
83C7281C22BC893D00678B4A /* sfh.c in Sources */,
|
||||||
834FE0FC215C79ED000A5D3D /* vai.c in Sources */,
|
834FE0FC215C79ED000A5D3D /* vai.c in Sources */,
|
||||||
|
83D2007F248DDB770048BD24 /* mups.c in Sources */,
|
||||||
83AA5D171F6E2F600020821C /* mpeg_custom_utils_ealayer3.c in Sources */,
|
83AA5D171F6E2F600020821C /* mpeg_custom_utils_ealayer3.c in Sources */,
|
||||||
|
83D20080248DDB770048BD24 /* sadf.c in Sources */,
|
||||||
83345A521F8AEB2800B2EAA4 /* xvag.c in Sources */,
|
83345A521F8AEB2800B2EAA4 /* xvag.c in Sources */,
|
||||||
836F6F3918BDC2190095E648 /* SASSC_decoder.c in Sources */,
|
836F6F3918BDC2190095E648 /* SASSC_decoder.c in Sources */,
|
||||||
8306B0A920984552000302D4 /* blocked_adm.c in Sources */,
|
8306B0A920984552000302D4 /* blocked_adm.c in Sources */,
|
||||||
|
@ -2507,7 +2533,6 @@
|
||||||
83AA5D191F6E2F600020821C /* ea_xas_decoder.c in Sources */,
|
83AA5D191F6E2F600020821C /* ea_xas_decoder.c in Sources */,
|
||||||
836F6F9318BDC2190095E648 /* ivaud.c in Sources */,
|
836F6F9318BDC2190095E648 /* ivaud.c in Sources */,
|
||||||
836F6F8518BDC2190095E648 /* exakt_sc.c in Sources */,
|
836F6F8518BDC2190095E648 /* exakt_sc.c in Sources */,
|
||||||
836F6FA618BDC2190095E648 /* nds_sad.c in Sources */,
|
|
||||||
8306B0F120984590000302D4 /* ppst.c in Sources */,
|
8306B0F120984590000302D4 /* ppst.c in Sources */,
|
||||||
832BF81C21E0514B006F50F1 /* xpcm.c in Sources */,
|
832BF81C21E0514B006F50F1 /* xpcm.c in Sources */,
|
||||||
836F702B18BDC2190095E648 /* sdt.c in Sources */,
|
836F702B18BDC2190095E648 /* sdt.c in Sources */,
|
||||||
|
@ -2726,6 +2751,7 @@
|
||||||
836F6FEA18BDC2190095E648 /* ps2_msa.c in Sources */,
|
836F6FEA18BDC2190095E648 /* ps2_msa.c in Sources */,
|
||||||
836F6F3618BDC2190095E648 /* ogg_vorbis_decoder.c in Sources */,
|
836F6F3618BDC2190095E648 /* ogg_vorbis_decoder.c in Sources */,
|
||||||
8306B0E520984590000302D4 /* ubi_lyn.c in Sources */,
|
8306B0E520984590000302D4 /* ubi_lyn.c in Sources */,
|
||||||
|
83D2007D248DDB770048BD24 /* kat.c in Sources */,
|
||||||
836F6F7618BDC2190095E648 /* brstm.c in Sources */,
|
836F6F7618BDC2190095E648 /* brstm.c in Sources */,
|
||||||
836F700718BDC2190095E648 /* ps2_vgv.c in Sources */,
|
836F700718BDC2190095E648 /* ps2_vgv.c in Sources */,
|
||||||
836F704F18BDC2190095E648 /* xwb.c in Sources */,
|
836F704F18BDC2190095E648 /* xwb.c in Sources */,
|
||||||
|
@ -2753,6 +2779,7 @@
|
||||||
83A21F8C201D8982000F04B9 /* kma9.c in Sources */,
|
83A21F8C201D8982000F04B9 /* kma9.c in Sources */,
|
||||||
8342469420C4D23000926E48 /* h4m.c in Sources */,
|
8342469420C4D23000926E48 /* h4m.c in Sources */,
|
||||||
834FE111215C79ED000A5D3D /* ck.c in Sources */,
|
834FE111215C79ED000A5D3D /* ck.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 */,
|
||||||
836F6F4118BDC2190095E648 /* blocked.c in Sources */,
|
836F6F4118BDC2190095E648 /* blocked.c in Sources */,
|
||||||
|
@ -2772,6 +2799,7 @@
|
||||||
836F6FBA18BDC2190095E648 /* ngc_ymf.c in Sources */,
|
836F6FBA18BDC2190095E648 /* ngc_ymf.c in Sources */,
|
||||||
83F1EE2E245D4FB20076E182 /* vadpcm_decoder.c in Sources */,
|
83F1EE2E245D4FB20076E182 /* vadpcm_decoder.c in Sources */,
|
||||||
836F705018BDC2190095E648 /* ydsp.c in Sources */,
|
836F705018BDC2190095E648 /* ydsp.c in Sources */,
|
||||||
|
83D2007E248DDB770048BD24 /* pcm_success.c in Sources */,
|
||||||
8306B0B720984552000302D4 /* blocked_str_snds.c in Sources */,
|
8306B0B720984552000302D4 /* blocked_str_snds.c in Sources */,
|
||||||
836F702718BDC2190095E648 /* sat_baka.c in Sources */,
|
836F702718BDC2190095E648 /* sat_baka.c in Sources */,
|
||||||
832389501D2246C300482226 /* hca.c in Sources */,
|
832389501D2246C300482226 /* hca.c in Sources */,
|
||||||
|
@ -2956,7 +2984,7 @@
|
||||||
836F6B6218BDB8880095E648 /* Debug */ = {
|
836F6B6218BDB8880095E648 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
|
@ -2986,7 +3014,7 @@
|
||||||
836F6B6318BDB8880095E648 /* Release */ = {
|
836F6B6318BDB8880095E648 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
|
|
|
@ -348,6 +348,7 @@ 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);
|
||||||
|
|
||||||
|
|
||||||
/* ffmpeg_decoder_utils.c (helper-things) */
|
/* ffmpeg_decoder_utils.c (helper-things) */
|
||||||
|
|
|
@ -155,6 +155,8 @@ int ffmpeg_make_riff_xma1(uint8_t * buf, size_t buf_size, size_t sample_count, s
|
||||||
put_16bitLE(buf+off+0x12, speakers);
|
put_16bitLE(buf+off+0x12, speakers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* xmaencode decoding rejects XMA1 without "seek" chunk, though it doesn't seem to use it */
|
||||||
|
|
||||||
memcpy(buf+riff_size-4-4, "data", 4);
|
memcpy(buf+riff_size-4-4, "data", 4);
|
||||||
put_32bitLE(buf+riff_size-4, data_size); /* data size */
|
put_32bitLE(buf+riff_size-4, data_size); /* data size */
|
||||||
|
|
||||||
|
|
|
@ -941,4 +941,22 @@ void ffmpeg_set_force_seek(ffmpeg_codec_data * data) {
|
||||||
//stream = data->formatCtx->streams[data->streamIndex];
|
//stream = data->formatCtx->streams[data->streamIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* ffmpeg_get_metadata_value(ffmpeg_codec_data* data, const char* key) {
|
||||||
|
AVDictionary* avd;
|
||||||
|
AVDictionaryEntry* avde;
|
||||||
|
|
||||||
|
if (!data || !data->codec)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
avd = data->formatCtx->streams[data->streamIndex]->metadata;
|
||||||
|
if (!avd)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
avde = av_dict_get(avd, key, NULL, AV_DICT_IGNORE_SUFFIX);
|
||||||
|
if (!avde)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return avde->value;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
* - expand type: IMA style or variations; low or high nibble first
|
* - expand type: IMA style or variations; low or high nibble first
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const int ADPCMTable[89] = {
|
static const int ADPCMTable[90] = {
|
||||||
7, 8, 9, 10, 11, 12, 13, 14,
|
7, 8, 9, 10, 11, 12, 13, 14,
|
||||||
16, 17, 19, 21, 23, 25, 28, 31,
|
16, 17, 19, 21, 23, 25, 28, 31,
|
||||||
34, 37, 41, 45, 50, 55, 60, 66,
|
34, 37, 41, 45, 50, 55, 60, 66,
|
||||||
|
@ -23,7 +23,9 @@ static const int ADPCMTable[89] = {
|
||||||
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
|
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
|
||||||
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
|
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
|
||||||
32767
|
32767,
|
||||||
|
|
||||||
|
0 /* garbage value for Ubisoft IMA (see blocked_ubi_sce.c) */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int IMA_IndexTable[16] = {
|
static const int IMA_IndexTable[16] = {
|
||||||
|
@ -1054,10 +1056,14 @@ void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspa
|
||||||
|
|
||||||
if (has_header) {
|
if (has_header) {
|
||||||
first_sample -= 10; //todo fix hack (needed to adjust nibble offset below)
|
first_sample -= 10; //todo fix hack (needed to adjust nibble offset below)
|
||||||
|
|
||||||
|
if (step_index < 0) step_index = 0;
|
||||||
|
if (step_index > 88) step_index = 88;
|
||||||
|
} else {
|
||||||
|
if (step_index < 0) step_index = 0;
|
||||||
|
if (step_index > 89) step_index = 89;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (step_index < 0) step_index=0;
|
|
||||||
if (step_index > 88) step_index=88;
|
|
||||||
|
|
||||||
for (i = first_sample; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
|
for (i = first_sample; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
|
||||||
off_t byte_offset = channelspacing == 1 ?
|
off_t byte_offset = channelspacing == 1 ?
|
||||||
|
|
|
@ -106,6 +106,7 @@ static const char* extension_list[] = {
|
||||||
"bik2",
|
"bik2",
|
||||||
//"bin", //common
|
//"bin", //common
|
||||||
"bk2",
|
"bk2",
|
||||||
|
"blk",
|
||||||
"bmdx",
|
"bmdx",
|
||||||
"bms",
|
"bms",
|
||||||
"bnk",
|
"bnk",
|
||||||
|
@ -137,6 +138,7 @@ static const char* extension_list[] = {
|
||||||
"cxs",
|
"cxs",
|
||||||
|
|
||||||
"da",
|
"da",
|
||||||
|
"dat",
|
||||||
"data",
|
"data",
|
||||||
"dax",
|
"dax",
|
||||||
"dbm",
|
"dbm",
|
||||||
|
@ -237,6 +239,7 @@ static const char* extension_list[] = {
|
||||||
"joe",
|
"joe",
|
||||||
"jstm",
|
"jstm",
|
||||||
|
|
||||||
|
"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)
|
"khv", //fake extension/header id for .vas (renamed, to be removed)
|
||||||
|
@ -244,6 +247,7 @@ static const char* extension_list[] = {
|
||||||
"kovs", //fake extension/header id for .kvs
|
"kovs", //fake extension/header id for .kvs
|
||||||
"kns",
|
"kns",
|
||||||
"kraw",
|
"kraw",
|
||||||
|
"ktsl2asbin",
|
||||||
"ktss", //fake extension/header id for .kns
|
"ktss", //fake extension/header id for .kns
|
||||||
"kvs",
|
"kvs",
|
||||||
|
|
||||||
|
@ -322,6 +326,7 @@ static const char* extension_list[] = {
|
||||||
"mta2",
|
"mta2",
|
||||||
"mtaf",
|
"mtaf",
|
||||||
"mul",
|
"mul",
|
||||||
|
"mups",
|
||||||
"mus",
|
"mus",
|
||||||
"musc",
|
"musc",
|
||||||
"musx",
|
"musx",
|
||||||
|
@ -1141,7 +1146,7 @@ static const meta_info meta_info_list[] = {
|
||||||
{meta_CSTM, "Nintendo CSTM Header"},
|
{meta_CSTM, "Nintendo CSTM Header"},
|
||||||
{meta_FSTM, "Nintendo FSTM Header"},
|
{meta_FSTM, "Nintendo FSTM Header"},
|
||||||
{meta_KT_WIIBGM, "Koei Tecmo WiiBGM Header"},
|
{meta_KT_WIIBGM, "Koei Tecmo WiiBGM Header"},
|
||||||
{meta_KTSS, "Koei Tecmo Nintendo Stream KTSS Header"},
|
{meta_KTSS, "Koei Tecmo KTSS header"},
|
||||||
{meta_IDSP_NAMCO, "Namco IDSP header"},
|
{meta_IDSP_NAMCO, "Namco IDSP header"},
|
||||||
{meta_WIIU_BTSND, "Nintendo Wii U Menu Boot Sound"},
|
{meta_WIIU_BTSND, "Nintendo Wii U Menu Boot Sound"},
|
||||||
{meta_MCA, "Capcom MCA header"},
|
{meta_MCA, "Capcom MCA header"},
|
||||||
|
@ -1218,7 +1223,7 @@ static const meta_info meta_info_list[] = {
|
||||||
{meta_UBI_BAO, "Ubisoft BAO header"},
|
{meta_UBI_BAO, "Ubisoft BAO header"},
|
||||||
{meta_DSP_SWITCH_AUDIO, "UE4 Switch Audio header"},
|
{meta_DSP_SWITCH_AUDIO, "UE4 Switch Audio header"},
|
||||||
{meta_TA_AAC_VITA, "tri-Ace AAC (Vita) header"},
|
{meta_TA_AAC_VITA, "tri-Ace AAC (Vita) header"},
|
||||||
{meta_DSP_SADF, "Procyon Studio SADF header"},
|
{meta_SADF, "Procyon Studio SADF header"},
|
||||||
{meta_H4M, "Hudson HVQM4 header"},
|
{meta_H4M, "Hudson HVQM4 header"},
|
||||||
{meta_ASF, "Argonaut ASF header"},
|
{meta_ASF, "Argonaut ASF header"},
|
||||||
{meta_XMD, "Konami XMD header"},
|
{meta_XMD, "Konami XMD header"},
|
||||||
|
@ -1292,7 +1297,9 @@ static const meta_info meta_info_list[] = {
|
||||||
{meta_WWISE_FX, "Audiokinetic Wwise FX header"},
|
{meta_WWISE_FX, "Audiokinetic Wwise FX header"},
|
||||||
{meta_DIVA, "DIVA header"},
|
{meta_DIVA, "DIVA header"},
|
||||||
{meta_IMUSE, "LucasArts iMUSE header"},
|
{meta_IMUSE, "LucasArts iMUSE header"},
|
||||||
|
{meta_KTSR, "Koei Tecmo KTSR header"},
|
||||||
|
{meta_KAT, "Sega KAT header"},
|
||||||
|
{meta_PCM_SUCCESS, "Success PCM 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) {
|
||||||
|
|
|
@ -44,13 +44,13 @@ void block_update_ubi_sce(off_t block_offset, VGMSTREAM* vgmstream) {
|
||||||
vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset + header_size * i + 0x04, sf);
|
vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset + header_size * i + 0x04, sf);
|
||||||
vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset + header_size * i + 0x08, sf);
|
vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset + header_size * i + 0x08, sf);
|
||||||
|
|
||||||
/* TODO figure out
|
/* First step is always 0x500, not sure if it's a bug or a feature but the game just takes it as is and
|
||||||
* First step seems to always be a special value for the decoder, unsure of meaning.
|
* ends up reading 0 from out-of-bounds memory area which causes a pop at the start. Yikes.
|
||||||
* 0 = too quiet and max = 88 = waveform starts a bit off and clicky. First hist is usually +-1,
|
* It gets clampled later so the rest of the sound plays ok.
|
||||||
* other frames look, fine not sure what are they aiming for.
|
* We put 89 here as our special index which contains 0 to simulate this.
|
||||||
*/
|
*/
|
||||||
if (vgmstream->ch[i].adpcm_step_index == 0x500) {
|
if (vgmstream->ch[i].adpcm_step_index == 0x500) {
|
||||||
vgmstream->ch[i].adpcm_step_index = 88;
|
vgmstream->ch[i].adpcm_step_index = 89;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,18 +4,18 @@
|
||||||
|
|
||||||
|
|
||||||
/* ACB (Atom Cue sheet Binary) - CRI container of memory audio, often together with a .awb wave bank */
|
/* ACB (Atom Cue sheet Binary) - CRI container of memory audio, often together with a .awb wave bank */
|
||||||
VGMSTREAM * init_vgmstream_acb(STREAMFILE *streamFile) {
|
VGMSTREAM* init_vgmstream_acb(STREAMFILE* sf) {
|
||||||
VGMSTREAM *vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
STREAMFILE *temp_streamFile = NULL;
|
STREAMFILE* temp_sf = NULL;
|
||||||
off_t subfile_offset;
|
off_t subfile_offset;
|
||||||
size_t subfile_size;
|
size_t subfile_size;
|
||||||
utf_context *utf = NULL;
|
utf_context *utf = NULL;
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
if (!check_extensions(streamFile, "acb"))
|
if (!check_extensions(sf, "acb"))
|
||||||
goto fail;
|
goto fail;
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x40555446) /* "@UTF" */
|
if (read_32bitBE(0x00,sf) != 0x40555446) /* "@UTF" */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* .acb is a cue sheet that uses @UTF (CRI's generic table format) to store row/columns
|
/* .acb is a cue sheet that uses @UTF (CRI's generic table format) to store row/columns
|
||||||
|
@ -28,7 +28,7 @@ VGMSTREAM * init_vgmstream_acb(STREAMFILE *streamFile) {
|
||||||
uint32_t offset = 0, size = 0;
|
uint32_t offset = 0, size = 0;
|
||||||
uint32_t table_offset = 0x00;
|
uint32_t table_offset = 0x00;
|
||||||
|
|
||||||
utf = utf_open(streamFile, table_offset, &rows, &name);
|
utf = utf_open(sf, table_offset, &rows, &name);
|
||||||
if (!utf) goto fail;
|
if (!utf) goto fail;
|
||||||
|
|
||||||
if (rows != 1 || strcmp(name, "Header") != 0)
|
if (rows != 1 || strcmp(name, "Header") != 0)
|
||||||
|
@ -49,41 +49,57 @@ VGMSTREAM * init_vgmstream_acb(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
//;VGM_LOG("ACB: subfile offset=%lx + %x\n", subfile_offset, subfile_size);
|
//;VGM_LOG("ACB: subfile offset=%lx + %x\n", subfile_offset, subfile_size);
|
||||||
|
|
||||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, "awb");
|
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, "awb");
|
||||||
if (!temp_streamFile) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
vgmstream = init_vgmstream_awb_memory(temp_streamFile, streamFile);
|
vgmstream = init_vgmstream_awb_memory(temp_sf, sf);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
/* name-loading for this for memory .awb will be called from init_vgmstream_awb_memory */
|
/* name-loading for this for memory .awb will be called from init_vgmstream_awb_memory */
|
||||||
|
|
||||||
utf_close(utf);
|
utf_close(utf);
|
||||||
close_streamfile(temp_streamFile);
|
close_streamfile(temp_sf);
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
utf_close(utf);
|
utf_close(utf);
|
||||||
close_streamfile(temp_streamFile);
|
close_streamfile(temp_sf);
|
||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************** */
|
/* ************************************** */
|
||||||
|
|
||||||
//todo maybe use reopen sf? since internal buffer is going to be read
|
/* extra config for .acb with lots of sounds, since there is a lot of IO back and forth,
|
||||||
#define ACB_TABLE_BUFFER_SIZE 0x4000
|
* ex. +7000 acb+awb subsongs in Ultra Despair Girls (PC) */
|
||||||
|
//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_CUE 0x40000
|
||||||
|
#define ACB_TABLE_BUFFER_BLOCK 0x8000
|
||||||
|
#define ACB_TABLE_BUFFER_SEQUENCE 0x40000
|
||||||
|
#define ACB_TABLE_BUFFER_TRACK 0x10000
|
||||||
|
#define ACB_TABLE_BUFFER_TRACKCOMMAND 0x20000
|
||||||
|
#define ACB_TABLE_BUFFER_SYNTH 0x40000
|
||||||
|
#define ACB_TABLE_BUFFER_WAVEFORM 0x20000
|
||||||
|
|
||||||
STREAMFILE* setup_acb_streamfile(STREAMFILE *sf, size_t buffer_size) {
|
#define ACB_MAX_NAMELIST 255
|
||||||
STREAMFILE *new_sf = NULL;
|
#define ACB_MAX_NAME 1024 /* even more is possible in rare cases [Senran Kagura Burst Re:Newal (PC)] */
|
||||||
|
|
||||||
|
|
||||||
|
STREAMFILE* setup_acb_streamfile(STREAMFILE* sf, size_t buffer_size) {
|
||||||
|
STREAMFILE* new_sf = NULL;
|
||||||
|
|
||||||
|
/* buffer seems better than reopening when opening multiple subsongs at the same time with STDIO,
|
||||||
|
* even though there is more buffer trashing, maybe concurrent IO is slower */
|
||||||
new_sf = open_wrap_streamfile(sf);
|
new_sf = open_wrap_streamfile(sf);
|
||||||
new_sf = open_buffer_streamfile_f(new_sf, buffer_size);
|
new_sf = open_buffer_streamfile_f(new_sf, buffer_size);
|
||||||
|
//new_sf = reopen_streamfile(sf, buffer_size);
|
||||||
return new_sf;
|
return new_sf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
STREAMFILE *acbFile; /* original reference, don't close */
|
STREAMFILE* acbFile; /* original reference, don't close */
|
||||||
|
|
||||||
/* keep track of these tables so they can be closed when done */
|
/* keep track of these tables so they can be closed when done */
|
||||||
utf_context *Header;
|
utf_context *Header;
|
||||||
|
@ -97,14 +113,14 @@ typedef struct {
|
||||||
utf_context *SynthTable;
|
utf_context *SynthTable;
|
||||||
utf_context *WaveformTable;
|
utf_context *WaveformTable;
|
||||||
|
|
||||||
STREAMFILE *CueNameSf;
|
STREAMFILE* CueNameSf;
|
||||||
STREAMFILE *CueSf;
|
STREAMFILE* CueSf;
|
||||||
STREAMFILE *BlockSf;
|
STREAMFILE* BlockSf;
|
||||||
STREAMFILE *SequenceSf;
|
STREAMFILE* SequenceSf;
|
||||||
STREAMFILE *TrackSf;
|
STREAMFILE* TrackSf;
|
||||||
STREAMFILE *TrackCommandSf;
|
STREAMFILE* TrackCommandSf;
|
||||||
STREAMFILE *SynthSf;
|
STREAMFILE* SynthSf;
|
||||||
STREAMFILE *WaveformSf;
|
STREAMFILE* WaveformSf;
|
||||||
|
|
||||||
/* config */
|
/* config */
|
||||||
int is_memory;
|
int is_memory;
|
||||||
|
@ -120,12 +136,12 @@ typedef struct {
|
||||||
int16_t cuename_index;
|
int16_t cuename_index;
|
||||||
const char * cuename_name;
|
const char * cuename_name;
|
||||||
int awbname_count;
|
int awbname_count;
|
||||||
int16_t awbname_list[255];
|
int16_t awbname_list[ACB_MAX_NAMELIST];
|
||||||
char name[1024];
|
char name[ACB_MAX_NAME];
|
||||||
|
|
||||||
} acb_header;
|
} acb_header;
|
||||||
|
|
||||||
static int open_utf_subtable(acb_header* acb, STREAMFILE* *TableSf, utf_context* *Table, const char* TableName, int* rows) {
|
static int open_utf_subtable(acb_header* acb, STREAMFILE* *TableSf, utf_context* *Table, const char* TableName, int* rows, int buffer) {
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
|
|
||||||
/* already loaded */
|
/* already loaded */
|
||||||
|
@ -135,22 +151,35 @@ static int open_utf_subtable(acb_header* acb, STREAMFILE* *TableSf, utf_context*
|
||||||
if (!utf_query_data(acb->Header, 0, TableName, &offset, NULL))
|
if (!utf_query_data(acb->Header, 0, TableName, &offset, NULL))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* open a buffered streamfile to avoid so much IO back and forth between all the tables */
|
*TableSf = setup_acb_streamfile(acb->acbFile, buffer);
|
||||||
*TableSf = setup_acb_streamfile(acb->acbFile, ACB_TABLE_BUFFER_SIZE);
|
|
||||||
if (!*TableSf) goto fail;
|
if (!*TableSf) goto fail;
|
||||||
|
|
||||||
*Table = utf_open(*TableSf, offset, rows, NULL);
|
*Table = utf_open(*TableSf, offset, rows, NULL);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//todo safeops, avoid recalc lens
|
||||||
|
static void acb_cat(char* dst, int dst_max, const char* src) {
|
||||||
|
int dst_len = strlen(dst);
|
||||||
|
int src_len = strlen(dst);
|
||||||
|
if (dst_len + src_len > dst_max - 1)
|
||||||
|
return;
|
||||||
|
strcat(dst, src);
|
||||||
|
}
|
||||||
|
static void acb_cpy(char* dst, int dst_max, const char* src) {
|
||||||
|
int src_len = strlen(dst);
|
||||||
|
if (src_len > dst_max - 1)
|
||||||
|
return;
|
||||||
|
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 Waveform_Streaming) {
|
||||||
//todo safe string ops
|
|
||||||
|
|
||||||
/* ignore name repeats */
|
/* ignore name repeats */
|
||||||
if (acb->awbname_count) {
|
if (acb->awbname_count) {
|
||||||
|
@ -161,22 +190,22 @@ static void add_acb_name(acb_header* acb, int8_t Waveform_Streaming) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* since waveforms can be reused by cues multiple names are a thing */
|
/* since waveforms can be reused by cues, multiple names are a thing */
|
||||||
if (acb->awbname_count) {
|
if (acb->awbname_count) {
|
||||||
strcat(acb->name, "; ");
|
acb_cat(acb->name, sizeof(acb->name), "; ");
|
||||||
strcat(acb->name, acb->cuename_name);
|
acb_cat(acb->name, sizeof(acb->name), acb->cuename_name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
strcpy(acb->name, acb->cuename_name);
|
acb_cpy(acb->name, sizeof(acb->name), acb->cuename_name);
|
||||||
}
|
}
|
||||||
if (Waveform_Streaming == 2 && acb->is_memory) {
|
if (Waveform_Streaming == 2 && acb->is_memory) {
|
||||||
strcat(acb->name, " [pre]");
|
acb_cat(acb->name, sizeof(acb->name), " [pre]");
|
||||||
}
|
}
|
||||||
|
|
||||||
acb->awbname_list[acb->awbname_count] = acb->cuename_index;
|
acb->awbname_list[acb->awbname_count] = acb->cuename_index;
|
||||||
acb->awbname_count++;
|
acb->awbname_count++;
|
||||||
if (acb->awbname_count >= 254)
|
if (acb->awbname_count >= ACB_MAX_NAMELIST)
|
||||||
acb->awbname_count = 254; /* ??? */
|
acb->awbname_count = ACB_MAX_NAMELIST - 1; /* ??? */
|
||||||
|
|
||||||
//;VGM_LOG("ACB: found cue for waveid=%i: %s\n", acb->target_waveid, acb->cuename_name);
|
//;VGM_LOG("ACB: found cue for waveid=%i: %s\n", acb->target_waveid, acb->cuename_name);
|
||||||
}
|
}
|
||||||
|
@ -187,7 +216,7 @@ static int load_acb_waveform(acb_header* acb, int16_t Index) {
|
||||||
uint8_t Waveform_Streaming;
|
uint8_t Waveform_Streaming;
|
||||||
|
|
||||||
/* read Waveform[Index] */
|
/* read Waveform[Index] */
|
||||||
if (!open_utf_subtable(acb, &acb->WaveformSf, &acb->WaveformTable, "WaveformTable", NULL))
|
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", &Waveform_Id)) { /* older versions use Id */
|
||||||
if (acb->is_memory) {
|
if (acb->is_memory) {
|
||||||
|
@ -228,7 +257,7 @@ static int load_acb_synth(acb_header* acb, int16_t Index) {
|
||||||
|
|
||||||
|
|
||||||
/* read Synth[Index] */
|
/* read Synth[Index] */
|
||||||
if (!open_utf_subtable(acb, &acb->SynthSf, &acb->SynthTable, "SynthTable", NULL))
|
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", &Synth_Type))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -306,7 +335,7 @@ static int load_acb_track_event_command(acb_header* acb, int16_t Index) {
|
||||||
|
|
||||||
|
|
||||||
/* read Track[Index] */
|
/* read Track[Index] */
|
||||||
if (!open_utf_subtable(acb, &acb->TrackSf, &acb->TrackTable, "TrackTable", NULL))
|
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", &Track_EventIndex))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -315,7 +344,7 @@ static int load_acb_track_event_command(acb_header* acb, int16_t Index) {
|
||||||
/* 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))
|
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, Track_EventIndex, "Command", &Track_Command_offset, &Track_Command_size))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -323,7 +352,7 @@ static int load_acb_track_event_command(acb_header* acb, int16_t Index) {
|
||||||
}
|
}
|
||||||
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))
|
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, Track_EventIndex, "Command", &Track_Command_offset, &Track_Command_size))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -405,7 +434,7 @@ static int load_acb_sequence(acb_header* acb, int16_t Index) {
|
||||||
|
|
||||||
|
|
||||||
/* read Sequence[Index] */
|
/* read Sequence[Index] */
|
||||||
if (!open_utf_subtable(acb, &acb->SequenceSf, &acb->SequenceTable, "SequenceTable", NULL))
|
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", &Sequence_NumTracks))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -448,7 +477,7 @@ static int load_acb_block(acb_header* acb, int16_t Index) {
|
||||||
|
|
||||||
|
|
||||||
/* read Block[Index] */
|
/* read Block[Index] */
|
||||||
if (!open_utf_subtable(acb, &acb->BlockSf, &acb->BlockTable, "BlockTable", NULL))
|
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", &Block_NumTracks))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -481,7 +510,7 @@ static int load_acb_cue(acb_header* acb, int16_t Index) {
|
||||||
|
|
||||||
|
|
||||||
/* read Cue[Index] */
|
/* read Cue[Index] */
|
||||||
if (!open_utf_subtable(acb, &acb->CueSf, &acb->CueTable, "CueTable", NULL))
|
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", &Cue_ReferenceType))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -540,7 +569,7 @@ static int load_acb_cuename(acb_header* acb, int16_t Index) {
|
||||||
|
|
||||||
|
|
||||||
/* read CueName[Index] */
|
/* read CueName[Index] */
|
||||||
if (!open_utf_subtable(acb, &acb->CueNameSf, &acb->CueNameTable, "CueNameTable", NULL))
|
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", &CueName_CueIndex))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -562,12 +591,12 @@ fail:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void load_acb_wave_name(STREAMFILE *streamFile, VGMSTREAM* vgmstream, int waveid, int is_memory) {
|
void load_acb_wave_name(STREAMFILE* sf, VGMSTREAM* vgmstream, int waveid, int is_memory) {
|
||||||
acb_header acb = {0};
|
acb_header acb = {0};
|
||||||
int i, CueName_rows;
|
int i, CueName_rows;
|
||||||
|
|
||||||
|
|
||||||
if (!streamFile || !vgmstream || waveid < 0)
|
if (!sf || !vgmstream || waveid < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Normally games load a .acb + .awb, and asks the .acb to play a cue by name or index.
|
/* Normally games load a .acb + .awb, and asks the .acb to play a cue by name or index.
|
||||||
|
@ -594,7 +623,7 @@ void load_acb_wave_name(STREAMFILE *streamFile, VGMSTREAM* vgmstream, int waveid
|
||||||
|
|
||||||
//;VGM_LOG("ACB: find waveid=%i\n", waveid);
|
//;VGM_LOG("ACB: find waveid=%i\n", waveid);
|
||||||
|
|
||||||
acb.acbFile = streamFile;
|
acb.acbFile = sf;
|
||||||
|
|
||||||
acb.Header = utf_open(acb.acbFile, 0x00, NULL, NULL);
|
acb.Header = utf_open(acb.acbFile, 0x00, NULL, NULL);
|
||||||
if (!acb.Header) goto fail;
|
if (!acb.Header) goto fail;
|
||||||
|
@ -606,7 +635,7 @@ void load_acb_wave_name(STREAMFILE *streamFile, VGMSTREAM* vgmstream, int waveid
|
||||||
|
|
||||||
|
|
||||||
/* read all possible cue names and find which waveids are referenced by it */
|
/* read all possible cue names and find which waveids are referenced by it */
|
||||||
if (!open_utf_subtable(&acb, &acb.CueNameSf, &acb.CueNameTable, "CueNameTable", &CueName_rows))
|
if (!open_utf_subtable(&acb, &acb.CueNameSf, &acb.CueNameTable, "CueNameTable", &CueName_rows, ACB_TABLE_BUFFER_CUENAME))
|
||||||
goto fail;
|
goto fail;
|
||||||
for (i = 0; i < CueName_rows; i++) {
|
for (i = 0; i < CueName_rows; i++) {
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,15 @@
|
||||||
#include "aix_streamfile.h"
|
#include "aix_streamfile.h"
|
||||||
|
|
||||||
|
|
||||||
#define MAX_SEGMENTS 50 /* usually segment0=intro, segment1=loop/main, sometimes ~5, rarely ~40 */
|
/* usually segment0=intro, segment1=loop/main, sometimes ~5, rarely ~40~115
|
||||||
|
* as pseudo dynamic/multi-song container [Sega Ages 2500 Vol 28 Tetris Collection (PS2)] */
|
||||||
|
#define MAX_SEGMENTS 120
|
||||||
|
|
||||||
static VGMSTREAM *build_segmented_vgmstream(STREAMFILE *streamFile, off_t *segment_offsets, size_t *segment_sizes, int32_t *segment_samples, int segment_count, int layer_count);
|
static VGMSTREAM* build_segmented_vgmstream(STREAMFILE* sf, off_t* segment_offsets, size_t* segment_sizes, int32_t* segment_samples, int segment_count, int layer_count);
|
||||||
|
|
||||||
/* AIX - N segments with M layers (2ch ADX) inside [SoulCalibur IV (PS3), Dragon Ball Z: Burst Limit (PS3)] */
|
/* AIX - N segments with M layers (2ch ADX) inside [SoulCalibur IV (PS3), Dragon Ball Z: Burst Limit (PS3)] */
|
||||||
VGMSTREAM * init_vgmstream_aix(STREAMFILE *sf) {
|
VGMSTREAM* init_vgmstream_aix(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
|
|
||||||
off_t segment_offsets[MAX_SEGMENTS] = {0};
|
off_t segment_offsets[MAX_SEGMENTS] = {0};
|
||||||
size_t segment_sizes[MAX_SEGMENTS] = {0};
|
size_t segment_sizes[MAX_SEGMENTS] = {0};
|
||||||
|
@ -106,8 +108,8 @@ fail:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VGMSTREAM *build_layered_vgmstream(STREAMFILE *streamFile, off_t segment_offset, size_t segment_size, int layer_count) {
|
static VGMSTREAM *build_layered_vgmstream(STREAMFILE* sf, off_t segment_offset, size_t segment_size, int layer_count) {
|
||||||
VGMSTREAM *vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
layered_layout_data* data = NULL;
|
layered_layout_data* data = NULL;
|
||||||
int i;
|
int i;
|
||||||
STREAMFILE* temp_sf = NULL;
|
STREAMFILE* temp_sf = NULL;
|
||||||
|
@ -119,7 +121,7 @@ static VGMSTREAM *build_layered_vgmstream(STREAMFILE *streamFile, off_t segment_
|
||||||
|
|
||||||
for (i = 0; i < layer_count; i++) {
|
for (i = 0; i < layer_count; i++) {
|
||||||
/* build the layer STREAMFILE */
|
/* build the layer STREAMFILE */
|
||||||
temp_sf = setup_aix_streamfile(streamFile, segment_offset, segment_size, i, "adx");
|
temp_sf = setup_aix_streamfile(sf, segment_offset, segment_size, i, "adx");
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
/* build the sub-VGMSTREAM */
|
/* build the sub-VGMSTREAM */
|
||||||
|
@ -149,9 +151,9 @@ fail:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VGMSTREAM *build_segmented_vgmstream(STREAMFILE *streamFile, off_t *segment_offsets, size_t *segment_sizes, int32_t *segment_samples, int segment_count, int layer_count) {
|
static VGMSTREAM *build_segmented_vgmstream(STREAMFILE* sf, off_t* segment_offsets, size_t* segment_sizes, int32_t* segment_samples, int segment_count, int layer_count) {
|
||||||
VGMSTREAM *vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
segmented_layout_data *data = NULL;
|
segmented_layout_data* data = NULL;
|
||||||
int i, loop_flag, loop_start_segment, loop_end_segment;
|
int i, loop_flag, loop_start_segment, loop_end_segment;
|
||||||
|
|
||||||
|
|
||||||
|
@ -161,7 +163,7 @@ static VGMSTREAM *build_segmented_vgmstream(STREAMFILE *streamFile, off_t *segme
|
||||||
|
|
||||||
for (i = 0; i < segment_count; i++) {
|
for (i = 0; i < segment_count; i++) {
|
||||||
/* build the layered sub-VGMSTREAM */
|
/* build the layered sub-VGMSTREAM */
|
||||||
data->segments[i] = build_layered_vgmstream(streamFile, segment_offsets[i], segment_sizes[i], layer_count);
|
data->segments[i] = build_layered_vgmstream(sf, segment_offsets[i], segment_sizes[i], layer_count);
|
||||||
if (!data->segments[i]) goto fail;
|
if (!data->segments[i]) goto fail;
|
||||||
|
|
||||||
data->segments[i]->num_samples = segment_samples[i]; /* just in case */
|
data->segments[i]->num_samples = segment_samples[i]; /* just in case */
|
||||||
|
@ -177,7 +179,7 @@ static VGMSTREAM *build_segmented_vgmstream(STREAMFILE *streamFile, off_t *segme
|
||||||
* - 2 segments: intro + loop [SoulCalibur IV (PS3)]
|
* - 2 segments: intro + loop [SoulCalibur IV (PS3)]
|
||||||
* - 3 segments: intro + loop + end [Dragon Ball Z: Burst Limit (PS3), Metroid: Other M (Wii)]
|
* - 3 segments: intro + loop + end [Dragon Ball Z: Burst Limit (PS3), Metroid: Other M (Wii)]
|
||||||
* - 4/5 segments: intros + loop + ends [Danball Senki (PSP)]
|
* - 4/5 segments: intros + loop + ends [Danball Senki (PSP)]
|
||||||
* - 39 segments: no loops but multiple segments for dynamic parts? [Tetris Collection (PS2)] */
|
* - +39 segments: no loops but multiple segments for dynamic parts? [Tetris Collection (PS2)] */
|
||||||
loop_flag = (segment_count > 0 && segment_count <= 5);
|
loop_flag = (segment_count > 0 && segment_count <= 5);
|
||||||
loop_start_segment = (segment_count > 3) ? 2 : 1;
|
loop_start_segment = (segment_count > 3) ? 2 : 1;
|
||||||
loop_end_segment = (segment_count > 3) ? (segment_count - 2) : 1;
|
loop_end_segment = (segment_count > 3) ? (segment_count - 2) : 1;
|
||||||
|
|
|
@ -5,7 +5,11 @@ typedef struct {
|
||||||
const char* key;
|
const char* key;
|
||||||
} bnsfkey_info;
|
} bnsfkey_info;
|
||||||
|
|
||||||
/* Known keys, extracted from games' exe/files */
|
/* Known keys, from games' exe (iM@S, near "nus" strings) or files (Tales, config in audio bigfiles).
|
||||||
|
*
|
||||||
|
* In memdumps, first 16 chars of key can be found XORed with "Ua#oK3P94vdxX,ft" after AES 'Td'
|
||||||
|
* mix tables (that end with 8D4697A3 A38D4697 97A38D46 4697A38D), then can be cross referenced
|
||||||
|
* with other strings (max 24 chars) in the memdump. */
|
||||||
static const bnsfkey_info s14key_list[] = {
|
static const bnsfkey_info s14key_list[] = {
|
||||||
|
|
||||||
/* THE iDOLM@STER 2 (PS3/X360) */
|
/* THE iDOLM@STER 2 (PS3/X360) */
|
||||||
|
@ -17,6 +21,9 @@ static const bnsfkey_info s14key_list[] = {
|
||||||
/* Tales of Berseria (PS3) */
|
/* Tales of Berseria (PS3) */
|
||||||
{"SPSLOC13"},
|
{"SPSLOC13"},
|
||||||
|
|
||||||
|
/* THE iDOLM@STER: One For All (PS3) */
|
||||||
|
{"86c215d7655eefb5c77ae92c"},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif/*_BNSF_KEYS_H_*/
|
#endif /*_BNSF_KEYS_H_*/
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
//todo move to utils or something
|
//todo move to utils or something
|
||||||
|
|
||||||
static void block_callback_default(STREAMFILE *sf, deblock_io_data *data) {
|
static void block_callback_default(STREAMFILE* sf, deblock_io_data* data) {
|
||||||
data->block_size = data->cfg.chunk_size;
|
data->block_size = data->cfg.chunk_size;
|
||||||
data->skip_size = data->cfg.skip_size;
|
data->skip_size = data->cfg.skip_size;
|
||||||
data->data_size = data->block_size - data->skip_size;
|
data->data_size = data->block_size - data->skip_size;
|
||||||
|
@ -10,7 +10,7 @@ static void block_callback_default(STREAMFILE *sf, deblock_io_data *data) {
|
||||||
//;VGM_LOG("DEBLOCK: of=%lx, bs=%lx, ss=%lx, ds=%lx\n", data->physical_offset, data->block_size, data->skip_size, data->data_size);
|
//;VGM_LOG("DEBLOCK: of=%lx, bs=%lx, ss=%lx, ds=%lx\n", data->physical_offset, data->block_size, data->skip_size, data->data_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t deblock_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_t length, deblock_io_data* data) {
|
static size_t deblock_io_read(STREAMFILE* sf, uint8_t* dest, off_t offset, size_t length, deblock_io_data* data) {
|
||||||
size_t total_read = 0;
|
size_t total_read = 0;
|
||||||
|
|
||||||
//;VGM_LOG("DEBLOCK: of=%lx, sz=%x, po=%lx\n", offset, length, data->physical_offset);
|
//;VGM_LOG("DEBLOCK: of=%lx, sz=%x, po=%lx\n", offset, length, data->physical_offset);
|
||||||
|
@ -25,9 +25,7 @@ static size_t deblock_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_
|
||||||
data->skip_size = 0;
|
data->skip_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;
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read blocks */
|
/* read blocks */
|
||||||
|
@ -98,6 +96,10 @@ static size_t deblock_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_
|
||||||
to_read = length;
|
to_read = length;
|
||||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, sf);
|
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, sf);
|
||||||
|
|
||||||
|
if (data->cfg.read_callback) {
|
||||||
|
data->cfg.read_callback(dest, data, bytes_consumed, bytes_done);
|
||||||
|
}
|
||||||
|
|
||||||
total_read += bytes_done;
|
total_read += bytes_done;
|
||||||
dest += bytes_done;
|
dest += bytes_done;
|
||||||
offset += bytes_done;
|
offset += bytes_done;
|
||||||
|
@ -112,7 +114,7 @@ static size_t deblock_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_
|
||||||
return total_read;
|
return total_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t deblock_io_size(STREAMFILE *streamfile, deblock_io_data* data) {
|
static size_t deblock_io_size(STREAMFILE* sf, deblock_io_data* data) {
|
||||||
uint8_t buf[0x04];
|
uint8_t buf[0x04];
|
||||||
|
|
||||||
if (data->logical_size)
|
if (data->logical_size)
|
||||||
|
@ -124,7 +126,7 @@ static size_t deblock_io_size(STREAMFILE *streamfile, deblock_io_data* data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
|
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
|
||||||
deblock_io_read(streamfile, buf, 0x7FFFFFFF, 1, data);
|
deblock_io_read(sf, buf, 0x7FFFFFFF, 1, data);
|
||||||
data->logical_size = data->logical_offset;
|
data->logical_size = data->logical_offset;
|
||||||
|
|
||||||
//todo tests:
|
//todo tests:
|
||||||
|
@ -141,8 +143,8 @@ static size_t deblock_io_size(STREAMFILE *streamfile, deblock_io_data* data) {
|
||||||
* decoder can't easily use blocked layout, or some other weird feature. It "filters" data so
|
* decoder can't easily use blocked layout, or some other weird feature. It "filters" data so
|
||||||
* reader only sees clean data without blocks. Must pass setup config and a callback that sets
|
* reader only sees clean data without blocks. Must pass setup config and a callback that sets
|
||||||
* sizes of a single block. */
|
* sizes of a single block. */
|
||||||
STREAMFILE* open_io_deblock_streamfile_f(STREAMFILE *sf, deblock_config_t *cfg) {
|
STREAMFILE* open_io_deblock_streamfile_f(STREAMFILE* sf, deblock_config_t *cfg) {
|
||||||
STREAMFILE *new_sf = NULL;
|
STREAMFILE* new_sf = NULL;
|
||||||
deblock_io_data io_data = {0};
|
deblock_io_data io_data = {0};
|
||||||
|
|
||||||
/* prepare data */
|
/* prepare data */
|
||||||
|
|
|
@ -34,7 +34,9 @@ struct deblock_config_t {
|
||||||
size_t interleave_last_count;
|
size_t interleave_last_count;
|
||||||
|
|
||||||
/* callback that setups deblock_io_data state, normally block_size and data_size */
|
/* callback that setups deblock_io_data state, normally block_size and data_size */
|
||||||
void (*block_callback)(STREAMFILE *sf, deblock_io_data *data);
|
void (*block_callback)(STREAMFILE* sf, deblock_io_data* data);
|
||||||
|
/* callback that alters block, with the current position into the block (0=beginning) */
|
||||||
|
void (*read_callback)(uint8_t* dst, deblock_io_data* data, size_t block_pos, size_t read_size);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct deblock_io_data {
|
struct deblock_io_data {
|
||||||
|
@ -56,6 +58,6 @@ struct deblock_io_data {
|
||||||
off_t physical_end;
|
off_t physical_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
STREAMFILE* open_io_deblock_streamfile_f(STREAMFILE *sf, deblock_config_t *cfg);
|
STREAMFILE* open_io_deblock_streamfile_f(STREAMFILE* sf, deblock_config_t* cfg);
|
||||||
|
|
||||||
#endif /* _DEBLOCK_STREAMFILE_H_ */
|
#endif /* _DEBLOCK_STREAMFILE_H_ */
|
||||||
|
|
|
@ -503,6 +503,9 @@ fail:
|
||||||
static STREAMFILE *open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) {
|
static STREAMFILE *open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) {
|
||||||
static const char *const mapfile_pairs[][2] = {
|
static const char *const mapfile_pairs[][2] = {
|
||||||
/* standard cases, replace map part with mus part (from the end to preserve prefixes) */
|
/* standard cases, replace map part with mus part (from the end to preserve prefixes) */
|
||||||
|
{"game.mpf", "Game_Stream.mus"}, /* Skate */
|
||||||
|
{"ipod.mpf", "Ipod_Stream.mus"},
|
||||||
|
{"world.mpf", "World_Stream.mus"},
|
||||||
{"FreSkate.mpf", "track.mus,ram.mus"}, /* Skate It */
|
{"FreSkate.mpf", "track.mus,ram.mus"}, /* Skate It */
|
||||||
{"nsf_sing.mpf", "track_main.mus"}, /* Need for Speed: Nitro */
|
{"nsf_sing.mpf", "track_main.mus"}, /* Need for Speed: Nitro */
|
||||||
{"nsf_wii.mpf", "Track.mus"}, /* Need for Speed: Nitro */
|
{"nsf_wii.mpf", "Track.mus"}, /* Need for Speed: Nitro */
|
||||||
|
|
|
@ -264,7 +264,6 @@ fail:
|
||||||
|
|
||||||
/* EA BNK with variable header - from EA games SFXs; also created by sx.exe */
|
/* EA BNK with variable header - from EA games SFXs; also created by sx.exe */
|
||||||
VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE* sf) {
|
VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE* sf) {
|
||||||
off_t offset;
|
|
||||||
int target_stream = sf->stream_index;
|
int target_stream = sf->stream_index;
|
||||||
|
|
||||||
/* check extension */
|
/* check extension */
|
||||||
|
@ -276,15 +275,8 @@ VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE* sf) {
|
||||||
if (!check_extensions(sf,"bnk,sdt,mus,abk,ast"))
|
if (!check_extensions(sf,"bnk,sdt,mus,abk,ast"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* check header (doesn't use EA blocks, otherwise very similar to SCHl) */
|
|
||||||
if (read_32bitBE(0x100,sf) == EA_BNK_HEADER_LE)
|
|
||||||
offset = 0x100; /* Harry Potter and the Goblet of Fire (PS2) .mus have weird extra 0x100 bytes */
|
|
||||||
else
|
|
||||||
offset = 0x00;
|
|
||||||
|
|
||||||
if (target_stream == 0) target_stream = 1;
|
if (target_stream == 0) target_stream = 1;
|
||||||
|
return parse_bnk_header(sf, 0x00, target_stream - 1, 0);
|
||||||
return parse_bnk_header(sf, offset, target_stream - 1, 0);
|
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -3,34 +3,28 @@
|
||||||
|
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
|
|
||||||
static int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile);
|
static int read_pos_file(uint8_t* buf, size_t bufsize, STREAMFILE* sf);
|
||||||
|
static int find_ogg_loops(ffmpeg_codec_data* data, int32_t* p_loop_start, int32_t* p_loop_end);
|
||||||
|
|
||||||
/**
|
/* parses any file supported by FFmpeg and not handled elsewhere (mainly: MP4/AAC, MP3, MPC, FLAC) */
|
||||||
* Generic init FFmpeg and vgmstream for any file supported by FFmpeg.
|
VGMSTREAM* init_vgmstream_ffmpeg(STREAMFILE* sf) {
|
||||||
* Called by vgmstream when trying to identify the file type (if the player allows it).
|
VGMSTREAM* vgmstream = NULL;
|
||||||
*/
|
ffmpeg_codec_data* data = NULL;
|
||||||
VGMSTREAM * init_vgmstream_ffmpeg(STREAMFILE *streamFile) {
|
|
||||||
return init_vgmstream_ffmpeg_offset( streamFile, 0, streamFile->get_size(streamFile) );
|
|
||||||
}
|
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size) {
|
|
||||||
VGMSTREAM *vgmstream = NULL;
|
|
||||||
ffmpeg_codec_data *data = NULL;
|
|
||||||
int loop_flag = 0;
|
int loop_flag = 0;
|
||||||
int32_t loop_start = 0, loop_end = 0, num_samples = 0;
|
int32_t loop_start = 0, loop_end = 0, num_samples = 0;
|
||||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
int total_subsongs, target_subsong = sf->stream_index;
|
||||||
|
|
||||||
/* no checks */
|
/* no checks */
|
||||||
//if (!check_extensions(streamFile, "..."))
|
//if (!check_extensions(sf, "..."))
|
||||||
// goto fail;
|
// goto fail;
|
||||||
|
|
||||||
/* don't try to open headers and other mini files */
|
/* don't try to open headers and other mini files */
|
||||||
if (get_streamfile_size(streamFile) <= 0x1000)
|
if (get_streamfile_size(sf) <= 0x1000)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
/* init ffmpeg */
|
/* init ffmpeg */
|
||||||
data = init_ffmpeg_offset(streamFile, start, size);
|
data = init_ffmpeg_offset(sf, 0, get_streamfile_size(sf));
|
||||||
if (!data) return NULL;
|
if (!data) return NULL;
|
||||||
|
|
||||||
total_subsongs = data->streamCount;
|
total_subsongs = data->streamCount;
|
||||||
|
@ -41,38 +35,43 @@ VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start,
|
||||||
{
|
{
|
||||||
uint8_t posbuf[4+4+4];
|
uint8_t posbuf[4+4+4];
|
||||||
|
|
||||||
if ( read_pos_file(posbuf, 4+4+4, streamFile) ) {
|
if (read_pos_file(posbuf, 4+4+4, sf)) {
|
||||||
loop_start = get_32bitLE(posbuf+0);
|
loop_start = get_s32le(posbuf+0);
|
||||||
loop_end = get_32bitLE(posbuf+4);
|
loop_end = get_s32le(posbuf+4);
|
||||||
loop_flag = 1; /* incorrect looping will be validated outside */
|
loop_flag = 1; /* incorrect looping will be validated outside */
|
||||||
/* FFmpeg can't always determine totalSamples correctly so optionally load it (can be 0/NULL)
|
/* FFmpeg can't always determine totalSamples correctly so optionally load it (can be 0/NULL)
|
||||||
* won't crash and will output silence if no loop points and bigger than actual stream's samples */
|
* won't crash and will output silence if no loop points and bigger than actual stream's samples */
|
||||||
num_samples = get_32bitLE(posbuf+8);
|
num_samples = get_s32le(posbuf+8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* try to read Ogg loop tags (abridged) */
|
||||||
|
if (loop_flag == 0 && read_u32be(0x00, sf) == 0x4F676753) { /* "OggS" */
|
||||||
|
loop_flag = find_ogg_loops(data, &loop_start, &loop_end);
|
||||||
|
}
|
||||||
|
|
||||||
/* hack for AAC files (will return 0 samples if not an actual file) */
|
/* hack for AAC files (will return 0 samples if not an actual file) */
|
||||||
if (!num_samples && check_extensions(streamFile, "aac,laac")) {
|
if (!num_samples && check_extensions(sf, "aac,laac")) {
|
||||||
num_samples = aac_get_samples(streamFile, 0x00, get_streamfile_size(streamFile));
|
num_samples = aac_get_samples(sf, 0x00, get_streamfile_size(sf));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VGM_USE_MPEG
|
#ifdef VGM_USE_MPEG
|
||||||
/* hack for MP3 files (will return 0 samples if not an actual file)
|
/* hack for MP3 files (will return 0 samples if not an actual file)
|
||||||
* .mus: Marc Ecko's Getting Up (PC) */
|
* .mus: Marc Ecko's Getting Up (PC) */
|
||||||
if (!num_samples && check_extensions(streamFile, "mp3,lmp3,mus")) {
|
if (!num_samples && check_extensions(sf, "mp3,lmp3,mus")) {
|
||||||
num_samples = mpeg_get_samples(streamFile, 0x00, get_streamfile_size(streamFile));
|
num_samples = mpeg_get_samples(sf, 0x00, get_streamfile_size(sf));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* hack for MPC, that seeks/resets incorrectly due to seek table shenanigans */
|
/* hack for MPC, that seeks/resets incorrectly due to seek table shenanigans */
|
||||||
if (read_32bitBE(0x00, streamFile) == 0x4D502B07 || /* "MP+\7" (Musepack V7) */
|
if (read_u32be(0x00, sf) == 0x4D502B07 || /* "MP+\7" (Musepack V7) */
|
||||||
read_32bitBE(0x00, streamFile) == 0x4D50434B) { /* "MPCK" (Musepack V8) */
|
read_u32be(0x00, sf) == 0x4D50434B) { /* "MPCK" (Musepack V8) */
|
||||||
ffmpeg_set_force_seek(data);
|
ffmpeg_set_force_seek(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* default but often inaccurate when calculated using bitrate (wrong for VBR) */
|
/* default but often inaccurate when calculated using bitrate (wrong for VBR) */
|
||||||
if (!num_samples) {
|
if (!num_samples) {
|
||||||
num_samples = data->totalSamples;
|
num_samples = data->totalSamples; /* may be 0 if FFmpeg can't precalculate it */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,15 +86,8 @@ VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start,
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
vgmstream->num_samples = num_samples;
|
vgmstream->num_samples = num_samples;
|
||||||
if (loop_flag) {
|
|
||||||
vgmstream->loop_start_sample = loop_start;
|
vgmstream->loop_start_sample = loop_start;
|
||||||
vgmstream->loop_end_sample = loop_end;
|
vgmstream->loop_end_sample = loop_end;
|
||||||
}
|
|
||||||
|
|
||||||
/* this may happen for some streams if FFmpeg can't determine it (ex. AAC) */
|
|
||||||
if (vgmstream->num_samples <= 0)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
vgmstream->channel_layout = ffmpeg_get_channel_layout(vgmstream->codec_data);
|
vgmstream->channel_layout = ffmpeg_get_channel_layout(vgmstream->codec_data);
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
@ -111,46 +103,94 @@ fail:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/* open file containing looping data and copy to buffer, returns true if found and copied */
|
||||||
* open file containing looping data and copy to buffer
|
int read_pos_file(uint8_t* buf, size_t bufsize, STREAMFILE* sf) {
|
||||||
*
|
|
||||||
* returns true if found and copied
|
|
||||||
*/
|
|
||||||
int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile) {
|
|
||||||
char posname[PATH_LIMIT];
|
char posname[PATH_LIMIT];
|
||||||
char filename[PATH_LIMIT];
|
char filename[PATH_LIMIT];
|
||||||
/*size_t bytes_read;*/
|
/*size_t bytes_read;*/
|
||||||
STREAMFILE * streamFilePos= NULL;
|
STREAMFILE* sf_pos = NULL;
|
||||||
|
|
||||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
get_streamfile_name(sf,filename,sizeof(filename));
|
||||||
|
|
||||||
if (strlen(filename)+4 > sizeof(posname)) goto fail;
|
if (strlen(filename)+4 > sizeof(posname))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* try to open a posfile using variations: "(name.ext).pos" */
|
/* try to open a posfile using variations: "(name.ext).pos" */
|
||||||
{
|
{
|
||||||
strcpy(posname, filename);
|
strcpy(posname, filename);
|
||||||
strcat(posname, ".pos");
|
strcat(posname, ".pos");
|
||||||
streamFilePos = streamFile->open(streamFile,posname,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
sf_pos = open_streamfile(sf, posname);;
|
||||||
if (streamFilePos) goto found;
|
if (sf_pos) goto found;
|
||||||
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
found:
|
found:
|
||||||
//if (get_streamfile_size(streamFilePos) != bufsize) goto fail;
|
//if (get_streamfile_size(sf_pos) != bufsize) goto fail;
|
||||||
|
|
||||||
/* allow pos files to be of different sizes in case of new features, just fill all we can */
|
/* allow pos files to be of different sizes in case of new features, just fill all we can */
|
||||||
memset(buf, 0, bufsize);
|
memset(buf, 0, bufsize);
|
||||||
read_streamfile(buf, 0, bufsize, streamFilePos);
|
read_streamfile(buf, 0, bufsize, sf_pos);
|
||||||
|
|
||||||
close_streamfile(streamFilePos);
|
close_streamfile(sf_pos);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (streamFilePos) close_streamfile(streamFilePos);
|
close_streamfile(sf_pos);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* loop tag handling could be unified with ogg_vorbis.c, but that one has a extra features too */
|
||||||
|
static int find_ogg_loops(ffmpeg_codec_data* data, int32_t* p_loop_start, int32_t* p_loop_end) {
|
||||||
|
char* endptr;
|
||||||
|
const char* value;
|
||||||
|
int loop_flag = 0;
|
||||||
|
int32_t loop_start = -1, loop_end = -1;
|
||||||
|
|
||||||
|
// Try to detect the loop flags based on current file metadata
|
||||||
|
value = ffmpeg_get_metadata_value(data, "LoopStart");
|
||||||
|
if (value != NULL) {
|
||||||
|
loop_start = strtol(value, &endptr, 10);
|
||||||
|
loop_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = ffmpeg_get_metadata_value(data, "LoopEnd");
|
||||||
|
if (value != NULL) {
|
||||||
|
loop_end = strtol(value, &endptr, 10);
|
||||||
|
loop_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loop_flag) {
|
||||||
|
if (loop_end <= 0) {
|
||||||
|
// Detected a loop, but loop_end is still undefined or wrong. Try to calculate it.
|
||||||
|
value = ffmpeg_get_metadata_value(data, "LoopLength");
|
||||||
|
if (value != NULL) {
|
||||||
|
int loop_length = strtol(value, &endptr, 10);
|
||||||
|
|
||||||
|
if (loop_start != -1) loop_end = loop_start + loop_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loop_end <= 0) {
|
||||||
|
// Looks a calculation was not possible, or tag value is wrongly set. Use the end of track as end value
|
||||||
|
loop_end = data->totalSamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loop_start <= 0) {
|
||||||
|
// Weird edge case: loopend is defined and there's a loop, but loopstart was never defined. Reset to sane value
|
||||||
|
loop_start = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Every other attempt to detect loop information failed, reset start/end flags to sane values
|
||||||
|
loop_start = 0;
|
||||||
|
loop_end = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*p_loop_start = loop_start;
|
||||||
|
*p_loop_end = loop_end;
|
||||||
|
return loop_flag;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
|
|
||||||
|
|
||||||
/* simplified struct based on the original definitions */
|
/* simplified struct based on the original definitions */
|
||||||
typedef enum { MPEG, IMA, PSX, XMA2, DSP, CELT, PCM8, PCM16 } fsb_codec_t;
|
typedef enum { MPEG, IMA, PSX, XMA, DSP, CELT, PCM8, PCM16 } fsb_codec_t;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* main header */
|
/* main header */
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
@ -103,31 +103,31 @@ typedef struct {
|
||||||
|
|
||||||
/* ********************************************************************************** */
|
/* ********************************************************************************** */
|
||||||
|
|
||||||
static layered_layout_data* build_layered_fsb_celt(STREAMFILE *streamFile, fsb_header* fsb, int is_new_lib);
|
static layered_layout_data* build_layered_fsb_celt(STREAMFILE* sf, fsb_header* fsb, int is_new_lib);
|
||||||
|
|
||||||
/* FSB1~4 - from games using FMOD audio middleware */
|
/* FSB1~4 - from games using FMOD audio middleware */
|
||||||
VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
VGMSTREAM* init_vgmstream_fsb(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
int target_subsong = streamFile->stream_index;
|
int target_subsong = sf->stream_index;
|
||||||
fsb_header fsb = {0};
|
fsb_header fsb = {0};
|
||||||
|
|
||||||
|
|
||||||
/* checks
|
/* checks
|
||||||
* .fsb: standard
|
* .fsb: standard
|
||||||
* .bnk: Hard Corps Uprising (PS3) */
|
* .bnk: Hard Corps Uprising (PS3) */
|
||||||
if ( !check_extensions(streamFile, "fsb,bnk") )
|
if ( !check_extensions(sf, "fsb,bnk") )
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* check header */
|
/* check header */
|
||||||
fsb.id = read_32bitBE(0x00,streamFile);
|
fsb.id = read_32bitBE(0x00,sf);
|
||||||
if (fsb.id == 0x46534231) { /* "FSB1" (somewhat different from other fsbs) */
|
if (fsb.id == 0x46534231) { /* "FSB1" (somewhat different from other fsbs) */
|
||||||
fsb.meta_type = meta_FSB1;
|
fsb.meta_type = meta_FSB1;
|
||||||
fsb.base_header_size = 0x10;
|
fsb.base_header_size = 0x10;
|
||||||
fsb.sample_header_min = 0x40;
|
fsb.sample_header_min = 0x40;
|
||||||
|
|
||||||
/* main header */
|
/* main header */
|
||||||
fsb.total_subsongs = read_32bitLE(0x04,streamFile);
|
fsb.total_subsongs = read_32bitLE(0x04,sf);
|
||||||
fsb.sample_data_size = read_32bitLE(0x08,streamFile);
|
fsb.sample_data_size = read_32bitLE(0x08,sf);
|
||||||
fsb.sample_headers_size = 0x40;
|
fsb.sample_headers_size = 0x40;
|
||||||
fsb.version = 0;
|
fsb.version = 0;
|
||||||
fsb.flags = 0;
|
fsb.flags = 0;
|
||||||
|
@ -140,13 +140,13 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
fsb.name_offset = header_offset;
|
fsb.name_offset = header_offset;
|
||||||
fsb.name_size = 0x20;
|
fsb.name_size = 0x20;
|
||||||
fsb.num_samples = read_32bitLE(header_offset+0x20,streamFile);
|
fsb.num_samples = read_32bitLE(header_offset+0x20,sf);
|
||||||
fsb.stream_size = read_32bitLE(header_offset+0x24,streamFile);
|
fsb.stream_size = read_32bitLE(header_offset+0x24,sf);
|
||||||
fsb.sample_rate = read_32bitLE(header_offset+0x28,streamFile);
|
fsb.sample_rate = read_32bitLE(header_offset+0x28,sf);
|
||||||
/* 0x2c:? 0x2e:? 0x30:? 0x32:? */
|
/* 0x2c:? 0x2e:? 0x30:? 0x32:? */
|
||||||
fsb.mode = read_32bitLE(header_offset+0x34,streamFile);
|
fsb.mode = read_32bitLE(header_offset+0x34,sf);
|
||||||
fsb.loop_start = read_32bitLE(header_offset+0x38,streamFile);
|
fsb.loop_start = read_32bitLE(header_offset+0x38,sf);
|
||||||
fsb.loop_end = read_32bitLE(header_offset+0x3c,streamFile);
|
fsb.loop_end = read_32bitLE(header_offset+0x3c,sf);
|
||||||
|
|
||||||
VGM_ASSERT(fsb.loop_end > fsb.num_samples, "FSB: loop end over samples (%i vs %i)\n", fsb.loop_end, fsb.num_samples);
|
VGM_ASSERT(fsb.loop_end > fsb.num_samples, "FSB: loop end over samples (%i vs %i)\n", fsb.loop_end, fsb.num_samples);
|
||||||
fsb.channels = (fsb.mode & FSOUND_STEREO) ? 2 : 1;
|
fsb.channels = (fsb.mode & FSOUND_STEREO) ? 2 : 1;
|
||||||
|
@ -177,12 +177,12 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* main header */
|
/* main header */
|
||||||
fsb.total_subsongs = read_32bitLE(0x04,streamFile);
|
fsb.total_subsongs = read_32bitLE(0x04,sf);
|
||||||
fsb.sample_headers_size = read_32bitLE(0x08,streamFile);
|
fsb.sample_headers_size = read_32bitLE(0x08,sf);
|
||||||
fsb.sample_data_size = read_32bitLE(0x0c,streamFile);
|
fsb.sample_data_size = read_32bitLE(0x0c,sf);
|
||||||
if (fsb.base_header_size > 0x10) {
|
if (fsb.base_header_size > 0x10) {
|
||||||
fsb.version = read_32bitLE(0x10,streamFile);
|
fsb.version = read_32bitLE(0x10,sf);
|
||||||
fsb.flags = read_32bitLE(0x14,streamFile);
|
fsb.flags = read_32bitLE(0x14,sf);
|
||||||
/* FSB4: 0x18(8):hash 0x20(10):guid */
|
/* FSB4: 0x18(8):hash 0x20(10):guid */
|
||||||
} else {
|
} else {
|
||||||
fsb.version = 0;
|
fsb.version = 0;
|
||||||
|
@ -214,24 +214,24 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
||||||
if ((fsb.flags & FMOD_FSB_SOURCE_BASICHEADERS) && i > 0) {
|
if ((fsb.flags & FMOD_FSB_SOURCE_BASICHEADERS) && i > 0) {
|
||||||
/* miniheader, all subsongs reuse first header [rare, ex. Biker Mice from Mars (PS2)] */
|
/* miniheader, all subsongs reuse first header [rare, ex. Biker Mice from Mars (PS2)] */
|
||||||
stream_header_size = 0x08;
|
stream_header_size = 0x08;
|
||||||
fsb.num_samples = read_32bitLE(header_offset+0x00,streamFile);
|
fsb.num_samples = read_32bitLE(header_offset+0x00,sf);
|
||||||
fsb.stream_size = read_32bitLE(header_offset+0x04,streamFile);
|
fsb.stream_size = read_32bitLE(header_offset+0x04,sf);
|
||||||
fsb.loop_start = 0;
|
fsb.loop_start = 0;
|
||||||
fsb.loop_end = 0;
|
fsb.loop_end = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* subsong header for normal files */
|
/* subsong header for normal files */
|
||||||
stream_header_size = (uint16_t)read_16bitLE(header_offset+0x00,streamFile);
|
stream_header_size = (uint16_t)read_16bitLE(header_offset+0x00,sf);
|
||||||
fsb.name_offset = header_offset+0x02;
|
fsb.name_offset = header_offset+0x02;
|
||||||
fsb.name_size = 0x20-0x02;
|
fsb.name_size = 0x20-0x02;
|
||||||
fsb.num_samples = read_32bitLE(header_offset+0x20,streamFile);
|
fsb.num_samples = read_32bitLE(header_offset+0x20,sf);
|
||||||
fsb.stream_size = read_32bitLE(header_offset+0x24,streamFile);
|
fsb.stream_size = read_32bitLE(header_offset+0x24,sf);
|
||||||
fsb.loop_start = read_32bitLE(header_offset+0x28,streamFile);
|
fsb.loop_start = read_32bitLE(header_offset+0x28,sf);
|
||||||
fsb.loop_end = read_32bitLE(header_offset+0x2c,streamFile);
|
fsb.loop_end = read_32bitLE(header_offset+0x2c,sf);
|
||||||
fsb.mode = read_32bitLE(header_offset+0x30,streamFile);
|
fsb.mode = read_32bitLE(header_offset+0x30,sf);
|
||||||
fsb.sample_rate = read_32bitLE(header_offset+0x34,streamFile);
|
fsb.sample_rate = read_32bitLE(header_offset+0x34,sf);
|
||||||
/* 0x38: defvol, 0x3a: defpan, 0x3c: defpri */
|
/* 0x38: defvol, 0x3a: defpan, 0x3c: defpri */
|
||||||
fsb.channels = read_16bitLE(header_offset+0x3e,streamFile);
|
fsb.channels = read_16bitLE(header_offset+0x3e,sf);
|
||||||
/* FSB3.1/4:
|
/* FSB3.1/4:
|
||||||
* 0x40: mindistance, 0x44: maxdistance, 0x48: varfreq/size_32bits
|
* 0x40: mindistance, 0x44: maxdistance, 0x48: varfreq/size_32bits
|
||||||
* 0x4c: varvol, 0x4e: fsb.varpan */
|
* 0x4c: varvol, 0x4e: fsb.varpan */
|
||||||
|
@ -269,7 +269,7 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
||||||
if (fsb.mode & FSOUND_MPEG) fsb.codec = MPEG;
|
if (fsb.mode & FSOUND_MPEG) fsb.codec = MPEG;
|
||||||
else if (fsb.mode & FSOUND_IMAADPCM) fsb.codec = IMA;
|
else if (fsb.mode & FSOUND_IMAADPCM) fsb.codec = IMA;
|
||||||
else if (fsb.mode & FSOUND_VAG) fsb.codec = PSX;
|
else if (fsb.mode & FSOUND_VAG) fsb.codec = PSX;
|
||||||
else if (fsb.mode & FSOUND_XMA) fsb.codec = XMA2;
|
else if (fsb.mode & FSOUND_XMA) fsb.codec = XMA;
|
||||||
else if (fsb.mode & FSOUND_GCADPCM) fsb.codec = DSP;
|
else if (fsb.mode & FSOUND_GCADPCM) fsb.codec = DSP;
|
||||||
else if (fsb.mode & FSOUND_CELT) fsb.codec = CELT;
|
else if (fsb.mode & FSOUND_CELT) fsb.codec = CELT;
|
||||||
else if (fsb.mode & FSOUND_8BITS) fsb.codec = PCM8;
|
else if (fsb.mode & FSOUND_8BITS) fsb.codec = PCM8;
|
||||||
|
@ -287,9 +287,9 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
||||||
//;VGM_ASSERT(fsb.flags & FMOD_FSB_SOURCE_ENCRYPTED, "FSB ENCRYPTED found\n");
|
//;VGM_ASSERT(fsb.flags & FMOD_FSB_SOURCE_ENCRYPTED, "FSB ENCRYPTED found\n");
|
||||||
|
|
||||||
/* sometimes there is garbage at the end or missing bytes due to improper ripping */
|
/* sometimes there is garbage at the end or missing bytes due to improper ripping */
|
||||||
VGM_ASSERT(fsb.base_header_size + fsb.sample_headers_size + fsb.sample_data_size != streamFile->get_size(streamFile),
|
VGM_ASSERT(fsb.base_header_size + fsb.sample_headers_size + fsb.sample_data_size != sf->get_size(sf),
|
||||||
"FSB wrong head/data_size found (expected 0x%x vs 0x%x)\n",
|
"FSB wrong head/data_size found (expected 0x%x vs 0x%x)\n",
|
||||||
fsb.base_header_size + fsb.sample_headers_size + fsb.sample_data_size, streamFile->get_size(streamFile));
|
fsb.base_header_size + fsb.sample_headers_size + fsb.sample_data_size, sf->get_size(sf));
|
||||||
|
|
||||||
/* autodetect unwanted loops */
|
/* autodetect unwanted loops */
|
||||||
{
|
{
|
||||||
|
@ -337,7 +337,7 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
||||||
vgmstream->stream_size = fsb.stream_size;
|
vgmstream->stream_size = fsb.stream_size;
|
||||||
vgmstream->meta_type = fsb.meta_type;
|
vgmstream->meta_type = fsb.meta_type;
|
||||||
if (fsb.name_offset)
|
if (fsb.name_offset)
|
||||||
read_string(vgmstream->stream_name,fsb.name_size+1, fsb.name_offset,streamFile);
|
read_string(vgmstream->stream_name,fsb.name_size+1, fsb.name_offset,sf);
|
||||||
|
|
||||||
switch(fsb.codec) {
|
switch(fsb.codec) {
|
||||||
#ifdef VGM_USE_MPEG
|
#ifdef VGM_USE_MPEG
|
||||||
|
@ -348,7 +348,7 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
||||||
(fsb.flags & FMOD_FSB_SOURCE_MPEG_PADDED4 ? 4 :
|
(fsb.flags & FMOD_FSB_SOURCE_MPEG_PADDED4 ? 4 :
|
||||||
(fsb.flags & FMOD_FSB_SOURCE_MPEG_PADDED ? 2 : 0)));
|
(fsb.flags & FMOD_FSB_SOURCE_MPEG_PADDED ? 2 : 0)));
|
||||||
|
|
||||||
vgmstream->codec_data = init_mpeg_custom(streamFile, fsb.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
|
vgmstream->codec_data = init_mpeg_custom(sf, fsb.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
|
@ -382,20 +382,25 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
case XMA2: { /* FSB3: The Bourne Conspiracy 2008 (X360), FSB4: Armored Core V (X360), Hard Corps (X360) */
|
case XMA: { /* FSB3: The Bourne Conspiracy 2008 (X360), FSB4: Armored Core V (X360), Hard Corps (X360) */
|
||||||
uint8_t buf[0x100];
|
uint8_t buf[0x100];
|
||||||
size_t bytes, block_size, block_count;
|
size_t bytes, block_size, block_count;
|
||||||
|
|
||||||
|
if (fsb.version != FMOD_FSB_VERSION_4_0) { /* 3.x, though no actual output changes [ex. Guitar Hero III (X360)] */
|
||||||
|
bytes = ffmpeg_make_riff_xma1(buf, sizeof(buf), fsb.num_samples, fsb.stream_size, fsb.channels, fsb.sample_rate, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
block_size = 0x8000; /* FSB default */
|
block_size = 0x8000; /* FSB default */
|
||||||
block_count = fsb.stream_size / block_size; /* not accurate but not needed (custom_data_offset+0x14 -1?) */
|
block_count = fsb.stream_size / block_size; /* not accurate but not needed (custom_data_offset+0x14 -1?) */
|
||||||
|
|
||||||
bytes = ffmpeg_make_riff_xma2(buf,0x100, fsb.num_samples, fsb.stream_size, fsb.channels, fsb.sample_rate, block_count, block_size);
|
bytes = ffmpeg_make_riff_xma2(buf, sizeof(buf), fsb.num_samples, fsb.stream_size, fsb.channels, fsb.sample_rate, block_count, block_size);
|
||||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, fsb.stream_offset,fsb.stream_size);
|
}
|
||||||
|
vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, fsb.stream_offset,fsb.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, fsb.stream_offset,fsb.stream_size, 0, 0,0); /* samples look ok */
|
xma_fix_raw_samples(vgmstream, sf, fsb.stream_offset,fsb.stream_size, 0, 0,0); /* samples look ok */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -411,7 +416,7 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
vgmstream->interleave_block_size = 0x2;
|
vgmstream->interleave_block_size = 0x2;
|
||||||
}
|
}
|
||||||
dsp_read_coefs_be(vgmstream, streamFile, fsb.extradata_offset, 0x2e);
|
dsp_read_coefs_be(vgmstream, sf, fsb.extradata_offset, 0x2e);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef VGM_USE_CELT
|
#ifdef VGM_USE_CELT
|
||||||
|
@ -421,8 +426,8 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
||||||
/* get libcelt version (set in the first subsong only, but try all extradata just in case) */
|
/* get libcelt version (set in the first subsong only, but try all extradata just in case) */
|
||||||
if (fsb.first_extradata_offset || fsb.extradata_offset) {
|
if (fsb.first_extradata_offset || fsb.extradata_offset) {
|
||||||
uint32_t lib = fsb.first_extradata_offset ?
|
uint32_t lib = fsb.first_extradata_offset ?
|
||||||
(uint32_t)read_32bitLE(fsb.first_extradata_offset, streamFile) :
|
(uint32_t)read_32bitLE(fsb.first_extradata_offset, sf) :
|
||||||
(uint32_t)read_32bitLE(fsb.extradata_offset, streamFile);;
|
(uint32_t)read_32bitLE(fsb.extradata_offset, sf);;
|
||||||
switch(lib) {
|
switch(lib) {
|
||||||
case 0x80000009: is_new_lib = 0; break; /* War Thunder (PC) */
|
case 0x80000009: is_new_lib = 0; break; /* War Thunder (PC) */
|
||||||
case 0x80000010: is_new_lib = 1; break; /* Vessel (PC) */
|
case 0x80000010: is_new_lib = 1; break; /* Vessel (PC) */
|
||||||
|
@ -431,7 +436,7 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* split FSBs? try to guess from observed bitstreams */
|
/* split FSBs? try to guess from observed bitstreams */
|
||||||
uint16_t frame = (uint16_t)read_16bitBE(fsb.stream_offset+0x04+0x04,streamFile);
|
uint16_t frame = (uint16_t)read_16bitBE(fsb.stream_offset+0x04+0x04,sf);
|
||||||
if ((frame & 0xF000) == 0x6000 || frame == 0xFFFE) {
|
if ((frame & 0xF000) == 0x6000 || frame == 0xFFFE) {
|
||||||
is_new_lib = 1;
|
is_new_lib = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -440,7 +445,7 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fsb.channels > 2) { /* multistreams */
|
if (fsb.channels > 2) { /* multistreams */
|
||||||
vgmstream->layout_data = build_layered_fsb_celt(streamFile, &fsb, is_new_lib);
|
vgmstream->layout_data = build_layered_fsb_celt(sf, &fsb, is_new_lib);
|
||||||
if (!vgmstream->layout_data) goto fail;
|
if (!vgmstream->layout_data) goto fail;
|
||||||
vgmstream->coding_type = coding_CELT_FSB;
|
vgmstream->coding_type = coding_CELT_FSB;
|
||||||
vgmstream->layout_type = layout_layered;
|
vgmstream->layout_type = layout_layered;
|
||||||
|
@ -476,7 +481,7 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ( !vgmstream_open_stream(vgmstream, streamFile, fsb.stream_offset) )
|
if ( !vgmstream_open_stream(vgmstream, sf, fsb.stream_offset) )
|
||||||
goto fail;
|
goto fail;
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
|
@ -486,9 +491,9 @@ fail:
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VGM_USE_CELT
|
#ifdef VGM_USE_CELT
|
||||||
static layered_layout_data* build_layered_fsb_celt(STREAMFILE *streamFile, fsb_header* fsb, int is_new_lib) {
|
static layered_layout_data* build_layered_fsb_celt(STREAMFILE* sf, fsb_header* fsb, int is_new_lib) {
|
||||||
layered_layout_data* data = NULL;
|
layered_layout_data* data = NULL;
|
||||||
STREAMFILE* temp_streamFile = NULL;
|
STREAMFILE* temp_sf = NULL;
|
||||||
int i, layers = (fsb->channels+1) / 2;
|
int i, layers = (fsb->channels+1) / 2;
|
||||||
|
|
||||||
|
|
||||||
|
@ -519,22 +524,23 @@ static layered_layout_data* build_layered_fsb_celt(STREAMFILE *streamFile, fsb_h
|
||||||
goto fail;
|
goto fail;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
temp_streamFile = setup_fsb_interleave_streamfile(streamFile, fsb->stream_offset, fsb->stream_size, layers, i, FSB_INT_CELT);
|
temp_sf = setup_fsb_interleave_streamfile(sf, fsb->stream_offset, fsb->stream_size, layers, i, FSB_INT_CELT);
|
||||||
if (!temp_streamFile) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
if ( !vgmstream_open_stream(data->layers[i], temp_streamFile, 0x00) ) {
|
if (!vgmstream_open_stream(data->layers[i], temp_sf, 0x00))
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
temp_sf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup layered VGMSTREAMs */
|
/* setup layered VGMSTREAMs */
|
||||||
if (!setup_layout_layered(data))
|
if (!setup_layout_layered(data))
|
||||||
goto fail;
|
goto fail;
|
||||||
close_streamfile(temp_streamFile);
|
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
close_streamfile(temp_streamFile);
|
close_streamfile(temp_sf);
|
||||||
free_layout_layered(data);
|
free_layout_layered(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -546,55 +552,55 @@ static STREAMFILE* setup_fsb4_wav_streamfile(STREAMFILE *streamfile, off_t subfi
|
||||||
|
|
||||||
/* FSB4 with "\0WAV" Header, found in Deadly Creatures (Wii).
|
/* FSB4 with "\0WAV" Header, found in Deadly Creatures (Wii).
|
||||||
* Has a 0x10 BE header that holds the filesize (unsure if this is from a proper rip). */
|
* Has a 0x10 BE header that holds the filesize (unsure if this is from a proper rip). */
|
||||||
VGMSTREAM * init_vgmstream_fsb4_wav(STREAMFILE *streamFile) {
|
VGMSTREAM* init_vgmstream_fsb4_wav(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
STREAMFILE *test_streamFile = NULL;
|
STREAMFILE *test_sf = NULL;
|
||||||
off_t subfile_start = 0x10;
|
off_t subfile_start = 0x10;
|
||||||
size_t subfile_size = get_streamfile_size(streamFile) - 0x10 - 0x10;
|
size_t subfile_size = get_streamfile_size(sf) - 0x10 - 0x10;
|
||||||
|
|
||||||
/* check extensions */
|
/* check extensions */
|
||||||
if ( !check_extensions(streamFile, "fsb,wii") )
|
if ( !check_extensions(sf, "fsb,wii") )
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x00574156) /* "\0WAV" */
|
if (read_32bitBE(0x00,sf) != 0x00574156) /* "\0WAV" */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* parse FSB subfile */
|
/* parse FSB subfile */
|
||||||
test_streamFile = setup_fsb4_wav_streamfile(streamFile, subfile_start,subfile_size);
|
test_sf = setup_fsb4_wav_streamfile(sf, subfile_start,subfile_size);
|
||||||
if (!test_streamFile) goto fail;
|
if (!test_sf) goto fail;
|
||||||
|
|
||||||
vgmstream = init_vgmstream_fsb(test_streamFile);
|
vgmstream = init_vgmstream_fsb(test_sf);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
/* init the VGMSTREAM */
|
/* init the VGMSTREAM */
|
||||||
close_streamfile(test_streamFile);
|
close_streamfile(test_sf);
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
close_streamfile(test_streamFile);
|
close_streamfile(test_sf);
|
||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static STREAMFILE* setup_fsb4_wav_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size) {
|
static STREAMFILE* setup_fsb4_wav_streamfile(STREAMFILE* sf, off_t subfile_offset, size_t subfile_size) {
|
||||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
STREAMFILE *temp_sf = NULL, *new_sf = NULL;
|
||||||
|
|
||||||
/* setup subfile */
|
/* setup subfile */
|
||||||
new_streamFile = open_wrap_streamfile(streamFile);
|
new_sf = open_wrap_streamfile(sf);
|
||||||
if (!new_streamFile) goto fail;
|
if (!new_sf) goto fail;
|
||||||
temp_streamFile = new_streamFile;
|
temp_sf = new_sf;
|
||||||
|
|
||||||
new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
|
new_sf = open_clamp_streamfile(temp_sf, subfile_offset,subfile_size);
|
||||||
if (!new_streamFile) goto fail;
|
if (!new_sf) goto fail;
|
||||||
temp_streamFile = new_streamFile;
|
temp_sf = new_sf;
|
||||||
|
|
||||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"fsb");
|
new_sf = open_fakename_streamfile(temp_sf, NULL,"fsb");
|
||||||
if (!new_streamFile) goto fail;
|
if (!new_sf) goto fail;
|
||||||
temp_streamFile = new_streamFile;
|
temp_sf = new_sf;
|
||||||
|
|
||||||
return temp_streamFile;
|
return temp_sf;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
close_streamfile(temp_streamFile);
|
close_streamfile(temp_sf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,45 +33,45 @@ typedef struct {
|
||||||
|
|
||||||
/* ********************************************************************************** */
|
/* ********************************************************************************** */
|
||||||
|
|
||||||
static layered_layout_data* build_layered_fsb5_celt(STREAMFILE *streamFile, 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 *streamFile, 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 - FMOD Studio multiplatform format */
|
||||||
VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
fsb5_header fsb5 = {0};
|
fsb5_header fsb5 = {0};
|
||||||
int target_subsong = streamFile->stream_index;
|
int target_subsong = sf->stream_index;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
/* .fsb: standard
|
/* .fsb: standard
|
||||||
* .snd: Alchemy engine (also Unity) */
|
* .snd: Alchemy engine (also Unity) */
|
||||||
if (!check_extensions(streamFile,"fsb,snd"))
|
if (!check_extensions(sf,"fsb,snd"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x46534235) /* "FSB5" */
|
if (read_32bitBE(0x00,sf) != 0x46534235) /* "FSB5" */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* 0x00 is rare (seen in Tales from Space Vita) */
|
/* 0x00 is rare (seen in Tales from Space Vita) */
|
||||||
fsb5.version = read_32bitLE(0x04,streamFile);
|
fsb5.version = read_32bitLE(0x04,sf);
|
||||||
if (fsb5.version != 0x00 && fsb5.version != 0x01) goto fail;
|
if (fsb5.version != 0x00 && fsb5.version != 0x01) goto fail;
|
||||||
|
|
||||||
fsb5.total_subsongs = read_32bitLE(0x08,streamFile);
|
fsb5.total_subsongs = read_32bitLE(0x08,sf);
|
||||||
fsb5.sample_header_size = read_32bitLE(0x0C,streamFile);
|
fsb5.sample_header_size = read_32bitLE(0x0C,sf);
|
||||||
fsb5.name_table_size = read_32bitLE(0x10,streamFile);
|
fsb5.name_table_size = read_32bitLE(0x10,sf);
|
||||||
fsb5.sample_data_size = read_32bitLE(0x14,streamFile);
|
fsb5.sample_data_size = read_32bitLE(0x14,sf);
|
||||||
fsb5.codec = read_32bitLE(0x18,streamFile);
|
fsb5.codec = read_32bitLE(0x18,sf);
|
||||||
/* version 0x01 - 0x1c(4): zero, 0x24(16): hash, 0x34(8): unk
|
/* version 0x01 - 0x1c(4): zero, 0x24(16): hash, 0x34(8): unk
|
||||||
* version 0x00 has an extra field (always 0?) at 0x1c */
|
* version 0x00 has an extra field (always 0?) at 0x1c */
|
||||||
if (fsb5.version == 0x01) {
|
if (fsb5.version == 0x01) {
|
||||||
/* found by tests and assumed to be flags, no games known */
|
/* found by tests and assumed to be flags, no games known */
|
||||||
fsb5.flags = read_32bitLE(0x20,streamFile);
|
fsb5.flags = read_32bitLE(0x20,sf);
|
||||||
}
|
}
|
||||||
fsb5.base_header_size = (fsb5.version==0x00) ? 0x40 : 0x3C;
|
fsb5.base_header_size = (fsb5.version==0x00) ? 0x40 : 0x3C;
|
||||||
|
|
||||||
if ((fsb5.sample_header_size + fsb5.name_table_size + fsb5.sample_data_size + fsb5.base_header_size) != get_streamfile_size(streamFile)) {
|
if ((fsb5.sample_header_size + fsb5.name_table_size + fsb5.sample_data_size + fsb5.base_header_size) != get_streamfile_size(sf)) {
|
||||||
VGM_LOG("FSB5: bad size (%x + %x + %x + %x != %x)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(streamFile));
|
VGM_LOG("FSB5: bad size (%x + %x + %x + %x != %x)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(sf));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,8 +87,8 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
off_t data_offset = 0;
|
off_t data_offset = 0;
|
||||||
uint32_t sample_mode1, sample_mode2; /* maybe one uint64? */
|
uint32_t sample_mode1, sample_mode2; /* maybe one uint64? */
|
||||||
|
|
||||||
sample_mode1 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+0x00,streamFile);
|
sample_mode1 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+0x00,sf);
|
||||||
sample_mode2 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+0x04,streamFile);
|
sample_mode2 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+0x04,sf);
|
||||||
stream_header_size += 0x08;
|
stream_header_size += 0x08;
|
||||||
|
|
||||||
/* get samples */
|
/* get samples */
|
||||||
|
@ -133,7 +133,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
uint32_t extraflag, extraflag_type, extraflag_size, extraflag_end;
|
uint32_t extraflag, extraflag_type, extraflag_size, extraflag_end;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
extraflag = read_32bitLE(extraflag_offset,streamFile);
|
extraflag = read_32bitLE(extraflag_offset,sf);
|
||||||
extraflag_type = (extraflag >> 25) & 0x7F; /* bits 32..26 (7) */
|
extraflag_type = (extraflag >> 25) & 0x7F; /* bits 32..26 (7) */
|
||||||
extraflag_size = (extraflag >> 1) & 0xFFFFFF; /* bits 25..1 (24)*/
|
extraflag_size = (extraflag >> 1) & 0xFFFFFF; /* bits 25..1 (24)*/
|
||||||
extraflag_end = (extraflag & 0x01); /* bit 0 (1) */
|
extraflag_end = (extraflag & 0x01); /* bit 0 (1) */
|
||||||
|
@ -142,15 +142,15 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
if (i + 1 == target_subsong) {
|
if (i + 1 == target_subsong) {
|
||||||
switch(extraflag_type) {
|
switch(extraflag_type) {
|
||||||
case 0x01: /* channels */
|
case 0x01: /* channels */
|
||||||
fsb5.channels = read_8bit(extraflag_offset+0x04,streamFile);
|
fsb5.channels = read_8bit(extraflag_offset+0x04,sf);
|
||||||
break;
|
break;
|
||||||
case 0x02: /* sample rate */
|
case 0x02: /* sample rate */
|
||||||
fsb5.sample_rate = read_32bitLE(extraflag_offset+0x04,streamFile);
|
fsb5.sample_rate = read_32bitLE(extraflag_offset+0x04,sf);
|
||||||
break;
|
break;
|
||||||
case 0x03: /* loop info */
|
case 0x03: /* loop info */
|
||||||
fsb5.loop_start = read_32bitLE(extraflag_offset+0x04,streamFile);
|
fsb5.loop_start = read_32bitLE(extraflag_offset+0x04,sf);
|
||||||
if (extraflag_size > 0x04) { /* probably not needed */
|
if (extraflag_size > 0x04) { /* probably not needed */
|
||||||
fsb5.loop_end = read_32bitLE(extraflag_offset+0x08,streamFile);
|
fsb5.loop_end = read_32bitLE(extraflag_offset+0x08,sf);
|
||||||
fsb5.loop_end += 1; /* correct compared to FMOD's tools */
|
fsb5.loop_end += 1; /* correct compared to FMOD's tools */
|
||||||
}
|
}
|
||||||
//;VGM_LOG("FSB5: stream %i loop start=%i, loop end=%i, samples=%i\n", i, fsb5.loop_start, fsb5.loop_end, fsb5.num_samples);
|
//;VGM_LOG("FSB5: stream %i loop start=%i, loop end=%i, samples=%i\n", i, fsb5.loop_start, fsb5.loop_end, fsb5.num_samples);
|
||||||
|
@ -183,7 +183,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
case 0x05: /* unknown 32b */
|
case 0x05: /* unknown 32b */
|
||||||
/* rare, found in Tearaway (Vita) with value 0 in first stream and
|
/* rare, found in Tearaway (Vita) with value 0 in first stream and
|
||||||
* Shantae and the Seven Sirens (Mobile) with value 0x0003bd72 BE in #44 (Arena Town) */
|
* Shantae and the Seven Sirens (Mobile) with value 0x0003bd72 BE in #44 (Arena Town) */
|
||||||
VGM_LOG("FSB5: stream %i flag %x with value %08x\n", i, extraflag_type, read_32bitLE(extraflag_offset+0x04,streamFile));
|
VGM_LOG("FSB5: stream %i flag %x with value %08x\n", i, extraflag_type, read_32bitLE(extraflag_offset+0x04,sf));
|
||||||
break;
|
break;
|
||||||
case 0x06: /* XMA seek table */
|
case 0x06: /* XMA seek table */
|
||||||
/* no need for it */
|
/* no need for it */
|
||||||
|
@ -209,7 +209,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
break;
|
break;
|
||||||
case 0x0d: /* unknown 32b (config? usually 0x3fnnnn00 BE and sometimes 0x3dnnnn00 BE) */
|
case 0x0d: /* unknown 32b (config? usually 0x3fnnnn00 BE and sometimes 0x3dnnnn00 BE) */
|
||||||
/* 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,streamFile));
|
VGM_LOG("FSB5: stream %i flag %x with value %08x\n", i, extraflag_type, read_32bitLE(extraflag_offset+0x04,sf));
|
||||||
break;
|
break;
|
||||||
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);
|
||||||
|
@ -233,8 +233,8 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
else {
|
else {
|
||||||
off_t next_data_offset;
|
off_t next_data_offset;
|
||||||
uint32_t next_sample_mode1, next_sample_mode2;
|
uint32_t next_sample_mode1, next_sample_mode2;
|
||||||
next_sample_mode1 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+stream_header_size+0x00,streamFile);
|
next_sample_mode1 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+stream_header_size+0x00,sf);
|
||||||
next_sample_mode2 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+stream_header_size+0x04,streamFile);
|
next_sample_mode2 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+stream_header_size+0x04,sf);
|
||||||
next_data_offset = (((next_sample_mode2 & 0x03) << 25) | ((next_sample_mode1 >> 7) & 0x1FFFFFF)) << 5;
|
next_data_offset = (((next_sample_mode2 & 0x03) << 25) | ((next_sample_mode1 >> 7) & 0x1FFFFFF)) << 5;
|
||||||
|
|
||||||
fsb5.stream_size = next_data_offset - data_offset;
|
fsb5.stream_size = next_data_offset - data_offset;
|
||||||
|
@ -252,7 +252,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
/* get stream name */
|
/* get stream name */
|
||||||
if (fsb5.name_table_size) {
|
if (fsb5.name_table_size) {
|
||||||
off_t name_suboffset = fsb5.base_header_size + fsb5.sample_header_size + 0x04*(target_subsong-1);
|
off_t name_suboffset = fsb5.base_header_size + fsb5.sample_header_size + 0x04*(target_subsong-1);
|
||||||
fsb5.name_offset = fsb5.base_header_size + fsb5.sample_header_size + read_32bitLE(name_suboffset,streamFile);
|
fsb5.name_offset = fsb5.base_header_size + fsb5.sample_header_size + read_32bitLE(name_suboffset,sf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
vgmstream->stream_size = fsb5.stream_size;
|
vgmstream->stream_size = fsb5.stream_size;
|
||||||
vgmstream->meta_type = meta_FSB5;
|
vgmstream->meta_type = meta_FSB5;
|
||||||
if (fsb5.name_offset)
|
if (fsb5.name_offset)
|
||||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, fsb5.name_offset,streamFile);
|
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, fsb5.name_offset,sf);
|
||||||
|
|
||||||
switch (fsb5.codec) {
|
switch (fsb5.codec) {
|
||||||
case 0x00: /* FMOD_SOUND_FORMAT_NONE */
|
case 0x00: /* FMOD_SOUND_FORMAT_NONE */
|
||||||
|
@ -313,7 +313,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
vgmstream->interleave_block_size = 0x02;
|
vgmstream->interleave_block_size = 0x02;
|
||||||
}
|
}
|
||||||
dsp_read_coefs_be(vgmstream,streamFile,fsb5.extradata_offset,0x2E);
|
dsp_read_coefs_be(vgmstream,sf,fsb5.extradata_offset,0x2E);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x07: /* FMOD_SOUND_FORMAT_IMAADPCM [Skylanders] */
|
case 0x07: /* FMOD_SOUND_FORMAT_IMAADPCM [Skylanders] */
|
||||||
|
@ -347,12 +347,12 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
block_count = fsb5.stream_size / block_size + (fsb5.stream_size % block_size ? 1 : 0);
|
block_count = fsb5.stream_size / block_size + (fsb5.stream_size % block_size ? 1 : 0);
|
||||||
|
|
||||||
bytes = ffmpeg_make_riff_xma2(buf, 0x100, vgmstream->num_samples, fsb5.stream_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
|
bytes = ffmpeg_make_riff_xma2(buf, 0x100, vgmstream->num_samples, fsb5.stream_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
|
||||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, fsb5.stream_offset,fsb5.stream_size);
|
vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, fsb5.stream_offset,fsb5.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, fsb5.stream_offset,fsb5.stream_size, 0, 0,0); /* samples look ok */
|
xma_fix_raw_samples(vgmstream, sf, fsb5.stream_offset,fsb5.stream_size, 0, 0,0); /* samples look ok */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -363,7 +363,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
cfg.fsb_padding = (vgmstream->channels > 2 ? 16 : 4); /* observed default */
|
cfg.fsb_padding = (vgmstream->channels > 2 ? 16 : 4); /* observed default */
|
||||||
|
|
||||||
vgmstream->codec_data = init_mpeg_custom(streamFile, fsb5.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
|
vgmstream->codec_data = init_mpeg_custom(sf, fsb5.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
break;
|
break;
|
||||||
|
@ -375,7 +375,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
int is_multistream = fsb5.channels > 2;
|
int is_multistream = fsb5.channels > 2;
|
||||||
|
|
||||||
if (is_multistream) {
|
if (is_multistream) {
|
||||||
vgmstream->layout_data = build_layered_fsb5_celt(streamFile, &fsb5);
|
vgmstream->layout_data = build_layered_fsb5_celt(sf, &fsb5);
|
||||||
if (!vgmstream->layout_data) goto fail;
|
if (!vgmstream->layout_data) goto fail;
|
||||||
vgmstream->coding_type = coding_CELT_FSB;
|
vgmstream->coding_type = coding_CELT_FSB;
|
||||||
vgmstream->layout_type = layout_layered;
|
vgmstream->layout_type = layout_layered;
|
||||||
|
@ -398,7 +398,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
|
|
||||||
/* skip frame size in newer FSBs [Day of the Tentacle Remastered (Vita), Tearaway Unfolded (PS4)] */
|
/* skip frame size in newer FSBs [Day of the Tentacle Remastered (Vita), Tearaway Unfolded (PS4)] */
|
||||||
if (configs_size >= 0x08 && (uint8_t)read_8bit(configs_offset, streamFile) != 0xFE) { /* ATRAC9 sync */
|
if (configs_size >= 0x08 && (uint8_t)read_8bit(configs_offset, sf) != 0xFE) { /* ATRAC9 sync */
|
||||||
configs_offset += 0x04;
|
configs_offset += 0x04;
|
||||||
configs_size -= 0x04;
|
configs_size -= 0x04;
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
if (is_multistream) {
|
if (is_multistream) {
|
||||||
/* multichannel made of various streams [Little Big Planet (Vita)] */
|
/* multichannel made of various streams [Little Big Planet (Vita)] */
|
||||||
vgmstream->layout_data = build_layered_fsb5_atrac9(streamFile, &fsb5, configs_offset, configs_size);
|
vgmstream->layout_data = build_layered_fsb5_atrac9(sf, &fsb5, configs_offset, configs_size);
|
||||||
if (!vgmstream->layout_data) goto fail;
|
if (!vgmstream->layout_data) goto fail;
|
||||||
vgmstream->coding_type = coding_ATRAC9;
|
vgmstream->coding_type = coding_ATRAC9;
|
||||||
vgmstream->layout_type = layout_layered;
|
vgmstream->layout_type = layout_layered;
|
||||||
|
@ -417,7 +417,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
atrac9_config cfg = {0};
|
atrac9_config cfg = {0};
|
||||||
|
|
||||||
cfg.channels = vgmstream->channels;
|
cfg.channels = vgmstream->channels;
|
||||||
cfg.config_data = read_32bitBE(configs_offset,streamFile);
|
cfg.config_data = read_32bitBE(configs_offset,sf);
|
||||||
//cfg.encoder_delay = 0x100; //todo not used? num_samples seems to count all data
|
//cfg.encoder_delay = 0x100; //todo not used? num_samples seems to count all data
|
||||||
|
|
||||||
vgmstream->codec_data = init_atrac9(&cfg);
|
vgmstream->codec_data = init_atrac9(&cfg);
|
||||||
|
@ -434,14 +434,14 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
uint8_t buf[0x100];
|
uint8_t buf[0x100];
|
||||||
int bytes, format, average_bps, block_align;
|
int bytes, format, average_bps, block_align;
|
||||||
|
|
||||||
format = read_16bitBE(fsb5.extradata_offset+0x00,streamFile);
|
format = read_16bitBE(fsb5.extradata_offset+0x00,sf);
|
||||||
block_align = (uint16_t)read_16bitBE(fsb5.extradata_offset+0x02,streamFile);
|
block_align = (uint16_t)read_16bitBE(fsb5.extradata_offset+0x02,sf);
|
||||||
average_bps = (uint32_t)read_32bitBE(fsb5.extradata_offset+0x04,streamFile);
|
average_bps = (uint32_t)read_32bitBE(fsb5.extradata_offset+0x04,sf);
|
||||||
/* rest: seek entries + mini seek table? */
|
/* rest: seek entries + mini seek table? */
|
||||||
/* XWMA encoder only does up to 6ch (doesn't use FSB multistreams for more) */
|
/* XWMA encoder only does up to 6ch (doesn't use FSB multistreams for more) */
|
||||||
|
|
||||||
bytes = ffmpeg_make_riff_xwma(buf,0x100, format, fsb5.stream_size, vgmstream->channels, vgmstream->sample_rate, average_bps, block_align);
|
bytes = ffmpeg_make_riff_xwma(buf,0x100, format, fsb5.stream_size, vgmstream->channels, vgmstream->sample_rate, average_bps, block_align);
|
||||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, fsb5.stream_offset,fsb5.stream_size);
|
vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, fsb5.stream_offset,fsb5.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;
|
||||||
|
@ -455,11 +455,11 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
cfg.channels = vgmstream->channels;
|
cfg.channels = vgmstream->channels;
|
||||||
cfg.sample_rate = vgmstream->sample_rate;
|
cfg.sample_rate = vgmstream->sample_rate;
|
||||||
cfg.setup_id = read_32bitLE(fsb5.extradata_offset,streamFile);
|
cfg.setup_id = read_32bitLE(fsb5.extradata_offset,sf);
|
||||||
|
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
vgmstream->coding_type = coding_VORBIS_custom;
|
vgmstream->coding_type = coding_VORBIS_custom;
|
||||||
vgmstream->codec_data = init_vorbis_custom(streamFile, fsb5.stream_offset, VORBIS_FSB, &cfg);
|
vgmstream->codec_data = init_vorbis_custom(sf, fsb5.stream_offset, VORBIS_FSB, &cfg);
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -477,7 +477,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vgmstream_open_stream(vgmstream,streamFile,fsb5.stream_offset))
|
if (!vgmstream_open_stream(vgmstream,sf,fsb5.stream_offset))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
@ -488,15 +488,15 @@ fail:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static layered_layout_data* build_layered_fsb5_celt(STREAMFILE *streamFile, fsb5_header* fsb5) {
|
static layered_layout_data* build_layered_fsb5_celt(STREAMFILE* sf, fsb5_header* fsb5) {
|
||||||
layered_layout_data* data = NULL;
|
layered_layout_data* data = NULL;
|
||||||
STREAMFILE* temp_streamFile = NULL;
|
STREAMFILE* temp_sf = NULL;
|
||||||
int i, layers = (fsb5->channels+1) / 2;
|
int i, layers = (fsb5->channels+1) / 2;
|
||||||
size_t interleave;
|
size_t interleave;
|
||||||
|
|
||||||
if (read_32bitBE(fsb5->stream_offset+0x00,streamFile) != 0x17C30DF3) /* FSB CELT frame ID */
|
if (read_32bitBE(fsb5->stream_offset+0x00,sf) != 0x17C30DF3) /* FSB CELT frame ID */
|
||||||
goto fail;
|
goto fail;
|
||||||
interleave = 0x04+0x04+read_32bitLE(fsb5->stream_offset+0x04,streamFile); /* frame size */
|
interleave = 0x04+0x04+read_32bitLE(fsb5->stream_offset+0x04,sf); /* frame size */
|
||||||
|
|
||||||
//todo unknown interleave for max quality odd channel streams (found in test files)
|
//todo unknown interleave for max quality odd channel streams (found in test files)
|
||||||
/* FSB5 odd channels use 2ch+2ch...+1ch streams, and the last only goes up to 0x17a, and other
|
/* FSB5 odd channels use 2ch+2ch...+1ch streams, and the last only goes up to 0x17a, and other
|
||||||
|
@ -533,29 +533,31 @@ static layered_layout_data* build_layered_fsb5_celt(STREAMFILE *streamFile, fsb5
|
||||||
goto fail;
|
goto fail;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
temp_streamFile = setup_fsb5_streamfile(streamFile, fsb5->stream_offset, fsb5->stream_size, layers, i, interleave);
|
temp_sf = setup_fsb5_streamfile(sf, fsb5->stream_offset, fsb5->stream_size, layers, i, interleave);
|
||||||
if (!temp_streamFile) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
if (!vgmstream_open_stream(data->layers[i], temp_streamFile, 0x00))
|
if (!vgmstream_open_stream(data->layers[i], temp_sf, 0x00))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
temp_sf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup layered VGMSTREAMs */
|
/* setup layered VGMSTREAMs */
|
||||||
if (!setup_layout_layered(data))
|
if (!setup_layout_layered(data))
|
||||||
goto fail;
|
goto fail;
|
||||||
close_streamfile(temp_streamFile);
|
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
close_streamfile(temp_streamFile);
|
close_streamfile(temp_sf);
|
||||||
free_layout_layered(data);
|
free_layout_layered(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static layered_layout_data* build_layered_fsb5_atrac9(STREAMFILE *streamFile, 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) {
|
||||||
layered_layout_data* data = NULL;
|
layered_layout_data* data = NULL;
|
||||||
STREAMFILE* temp_streamFile = NULL;
|
STREAMFILE* temp_sf = NULL;
|
||||||
int i, layers = (configs_size / 0x04);
|
int i, layers = (configs_size / 0x04);
|
||||||
size_t interleave = 0;
|
size_t interleave = 0;
|
||||||
|
|
||||||
|
@ -566,7 +568,7 @@ static layered_layout_data* build_layered_fsb5_atrac9(STREAMFILE *streamFile, fs
|
||||||
|
|
||||||
/* open each layer subfile (2ch+2ch..+1/2ch) */
|
/* open each layer subfile (2ch+2ch..+1/2ch) */
|
||||||
for (i = 0; i < layers; i++) {
|
for (i = 0; i < layers; i++) {
|
||||||
uint32_t config = read_32bitBE(configs_offset + 0x04*i, streamFile);
|
uint32_t config = read_32bitBE(configs_offset + 0x04*i, sf);
|
||||||
int channel_index, layer_channels;
|
int channel_index, layer_channels;
|
||||||
size_t frame_size;
|
size_t frame_size;
|
||||||
|
|
||||||
|
@ -609,21 +611,23 @@ static layered_layout_data* build_layered_fsb5_atrac9(STREAMFILE *streamFile, fs
|
||||||
goto fail;
|
goto fail;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
temp_streamFile = setup_fsb5_streamfile(streamFile, fsb5->stream_offset, fsb5->stream_size, layers, i, interleave);
|
temp_sf = setup_fsb5_streamfile(sf, fsb5->stream_offset, fsb5->stream_size, layers, i, interleave);
|
||||||
if (!temp_streamFile) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
if (!vgmstream_open_stream(data->layers[i], temp_streamFile, 0x00))
|
if (!vgmstream_open_stream(data->layers[i], temp_sf, 0x00))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
temp_sf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup layered VGMSTREAMs */
|
/* setup layered VGMSTREAMs */
|
||||||
if (!setup_layout_layered(data))
|
if (!setup_layout_layered(data))
|
||||||
goto fail;
|
goto fail;
|
||||||
close_streamfile(temp_streamFile);
|
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
close_streamfile(temp_streamFile);
|
close_streamfile(temp_sf);
|
||||||
free_layout_layered(data);
|
free_layout_layered(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,53 +2,73 @@
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
/* FEV+FSB5 container [Just Cause 3 (PC), Shantae: Half-Genie Hero (Switch)] */
|
/* FEV+FSB5 container [Just Cause 3 (PC), Shantae: Half-Genie Hero (Switch)] */
|
||||||
VGMSTREAM * init_vgmstream_fsb5_fev_bank(STREAMFILE *streamFile) {
|
VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
STREAMFILE *temp_streamFile = NULL;
|
STREAMFILE *temp_sf = NULL;
|
||||||
off_t subfile_offset, chunk_offset, first_offset = 0x0c;
|
off_t subfile_offset, chunk_offset, first_offset = 0x0c;
|
||||||
size_t subfile_size, chunk_size;
|
size_t subfile_size, chunk_size;
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
if (!check_extensions(streamFile, "bank"))
|
if (!check_extensions(sf, "bank"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x52494646) /* "RIFF" */
|
if (read_32bitBE(0x00,sf) != 0x52494646) /* "RIFF" */
|
||||||
goto fail;
|
goto fail;
|
||||||
if (read_32bitBE(0x08,streamFile) != 0x46455620) /* "FEV " */
|
if (read_32bitBE(0x08,sf) != 0x46455620) /* "FEV " */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* .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).
|
||||||
* Format is RIFF with FMT (main), LIST (config) and SND (FSB5 data), we want the FSB5 offset inside LIST */
|
* Format is RIFF with FMT (main), LIST (config) and SND (FSB5 data), we want the FSB5 offset inside LIST */
|
||||||
if (!find_chunk_le(streamFile, 0x4C495354,first_offset,0, &chunk_offset,NULL)) /* "LIST" */
|
if (!find_chunk_le(sf, 0x4C495354,first_offset,0, &chunk_offset,NULL)) /* "LIST" */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (read_32bitBE(chunk_offset+0x00,streamFile) != 0x50524F4A || /* "PROJ" */
|
if (read_32bitBE(chunk_offset+0x00,sf) != 0x50524F4A || /* "PROJ" */
|
||||||
read_32bitBE(chunk_offset+0x04,streamFile) != 0x424E4B49) /* "BNKI" */
|
read_32bitBE(chunk_offset+0x04,sf) != 0x424E4B49) /* "BNKI" */
|
||||||
goto fail; /* event .fev has "OBCT" instead of "BNKI" */
|
goto fail; /* event .fev has "OBCT" instead of "BNKI" */
|
||||||
|
|
||||||
/* inside BNKI is a bunch of LIST each with event subchunks and finally the fsb offset */
|
/* inside BNKI is a bunch of LIST each with event subchunks and finally fsb offset */
|
||||||
first_offset = chunk_offset + 0x04;
|
first_offset = chunk_offset + 0x04;
|
||||||
if (!find_chunk_le(streamFile, 0x534E4448,first_offset,0, &chunk_offset,&chunk_size)) /* "SNDH" */
|
if (!find_chunk_le(sf, 0x534E4448,first_offset,0, &chunk_offset,&chunk_size)) /* "SNDH" */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (chunk_size != 0x0c)
|
/* 0x00: unknown (version? ex LE: 0x00080003, 0x00080005) */
|
||||||
goto fail; /* assuming only one FSB5 is possible */
|
{
|
||||||
subfile_offset = read_32bitLE(chunk_offset+0x04,streamFile);
|
int banks;
|
||||||
subfile_size = read_32bitLE(chunk_offset+0x08,streamFile);
|
|
||||||
|
|
||||||
|
/* 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) */
|
||||||
|
banks = (chunk_size - 0x04) / 0x08;
|
||||||
|
VGM_ASSERT(banks > 1, "FSB5FEV: multiple banks found\n");
|
||||||
|
|
||||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, "fsb");
|
/* Could try to set stream index based on FSB subsong ranges, also fixing num_streams and stream_index
|
||||||
if (!temp_streamFile) goto fail;
|
* kinda involved and hard to test so for now just ignore it and use first offset */
|
||||||
|
|
||||||
vgmstream = init_vgmstream_fsb5(temp_streamFile);
|
if (banks > 2)
|
||||||
close_streamfile(temp_streamFile);
|
goto fail;
|
||||||
|
if (banks == 2) {
|
||||||
|
off_t temp_offset = read_32bitLE(chunk_offset + 0x04 + 0x08*1 + 0x00,sf);
|
||||||
|
//size_t temp_size = read_32bitLE(chunk_offset + 0x04 + 0x08*1 + 0x04,sf);
|
||||||
|
|
||||||
|
int bank_subsongs = read_32bitLE(temp_offset + 0x08,sf);
|
||||||
|
if (bank_subsongs != 1) goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subfile_offset = read_32bitLE(chunk_offset+0x04,sf);
|
||||||
|
subfile_size = read_32bitLE(chunk_offset+0x08,sf);
|
||||||
|
|
||||||
|
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, "fsb");
|
||||||
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
|
vgmstream = init_vgmstream_fsb5(temp_sf);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,51 +1,48 @@
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "fsb_keys.h"
|
#include "fsb_keys.h"
|
||||||
|
#include "fsb_encrypted_streamfile.h"
|
||||||
#define FSB_KEY_MAX 128 /* probably 32 */
|
|
||||||
|
|
||||||
static STREAMFILE* setup_fsb_streamfile(STREAMFILE *streamFile, const uint8_t * key, size_t key_size, int is_alt);
|
|
||||||
|
|
||||||
|
|
||||||
/* fully encrypted FSBs */
|
/* fully encrypted FSBs */
|
||||||
VGMSTREAM * init_vgmstream_fsb_encrypted(STREAMFILE * streamFile) {
|
VGMSTREAM* init_vgmstream_fsb_encrypted(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
/* .fsb: standard
|
/* .fsb: standard
|
||||||
* .fsb.xen: various Guitar Hero (X360) */
|
* .fsb.xen: various Guitar Hero (X360/PC) */
|
||||||
if ( !check_extensions(streamFile, "fsb,xen") )
|
if (!check_extensions(sf, "fsb,xen"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* ignore non-encrypted FSB */
|
/* ignore non-encrypted FSB */
|
||||||
if ((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) == 0x46534200) /* "FSB\0" */
|
if ((read_u32be(0x00,sf) & 0xFFFFFF00) == 0x46534200) /* "FSB\0" */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
/* try fsbkey + all combinations of FSB4/5 and decryption algorithms */
|
/* try fsbkey + all combinations of FSB4/5 and decryption algorithms */
|
||||||
{
|
{
|
||||||
STREAMFILE *temp_streamFile = NULL;
|
STREAMFILE* temp_sf = NULL;
|
||||||
uint8_t key[FSB_KEY_MAX];
|
uint8_t key[FSB_KEY_MAX];
|
||||||
size_t key_size = read_key_file(key, FSB_KEY_MAX, streamFile);
|
size_t key_size = read_key_file(key, FSB_KEY_MAX, sf);
|
||||||
|
|
||||||
if (key_size) {
|
if (key_size) {
|
||||||
{
|
{
|
||||||
temp_streamFile = setup_fsb_streamfile(streamFile, key,key_size, 0);
|
temp_sf = setup_fsb_streamfile(sf, key,key_size, 0);
|
||||||
if (!temp_streamFile) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
if (!vgmstream) vgmstream = init_vgmstream_fsb(temp_streamFile);
|
if (!vgmstream) vgmstream = init_vgmstream_fsb(temp_sf);
|
||||||
if (!vgmstream) vgmstream = init_vgmstream_fsb5(temp_streamFile);
|
if (!vgmstream) vgmstream = init_vgmstream_fsb5(temp_sf);
|
||||||
|
|
||||||
close_streamfile(temp_streamFile);
|
close_streamfile(temp_sf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vgmstream) {
|
if (!vgmstream) {
|
||||||
temp_streamFile = setup_fsb_streamfile(streamFile, key,key_size, 1);
|
temp_sf = setup_fsb_streamfile(sf, key,key_size, 1);
|
||||||
if (!temp_streamFile) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
if (!vgmstream) vgmstream = init_vgmstream_fsb(temp_streamFile);
|
if (!vgmstream) vgmstream = init_vgmstream_fsb(temp_sf);
|
||||||
if (!vgmstream) vgmstream = init_vgmstream_fsb5(temp_streamFile);
|
if (!vgmstream) vgmstream = init_vgmstream_fsb5(temp_sf);
|
||||||
|
|
||||||
close_streamfile(temp_streamFile);
|
close_streamfile(temp_sf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,22 +51,25 @@ VGMSTREAM * init_vgmstream_fsb_encrypted(STREAMFILE * streamFile) {
|
||||||
/* try all keys until one works */
|
/* try all keys until one works */
|
||||||
if (!vgmstream) {
|
if (!vgmstream) {
|
||||||
int i;
|
int i;
|
||||||
STREAMFILE *temp_streamFile = NULL;
|
STREAMFILE* temp_sf = NULL;
|
||||||
|
|
||||||
for (i = 0; i < fsbkey_list_count; i++) {
|
for (i = 0; i < fsbkey_list_count; i++) {
|
||||||
fsbkey_info entry = fsbkey_list[i];
|
fsbkey_info entry = fsbkey_list[i];
|
||||||
//;VGM_LOG("fsbkey: size=%i, is_fsb5=%i, is_alt=%i\n", entry.fsbkey_size,entry.is_fsb5, entry.is_alt);
|
//;VGM_LOG("fsbkey: size=%i, is_fsb5=%i, is_alt=%i\n", entry.fsbkey_size,entry.is_fsb5, entry.is_alt);
|
||||||
|
|
||||||
temp_streamFile = setup_fsb_streamfile(streamFile, entry.fsbkey, entry.fsbkey_size, entry.is_alt);
|
temp_sf = setup_fsb_streamfile(sf, entry.fsbkey, entry.fsbkey_size, entry.is_alt);
|
||||||
if (!temp_streamFile) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
if (fsbkey_list[i].is_fsb5) {
|
if (fsbkey_list[i].is_fsb5) {
|
||||||
vgmstream = init_vgmstream_fsb5(temp_streamFile);
|
vgmstream = init_vgmstream_fsb5(temp_sf);
|
||||||
} else {
|
} else {
|
||||||
vgmstream = init_vgmstream_fsb(temp_streamFile);
|
vgmstream = init_vgmstream_fsb(temp_sf);
|
||||||
}
|
}
|
||||||
|
|
||||||
close_streamfile(temp_streamFile);
|
if (vgmstream)
|
||||||
|
dump_streamfile(temp_sf, 0);
|
||||||
|
|
||||||
|
close_streamfile(temp_sf);
|
||||||
if (vgmstream) break;
|
if (vgmstream) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,82 +83,3 @@ fail:
|
||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t key[FSB_KEY_MAX];
|
|
||||||
size_t key_size;
|
|
||||||
int is_alt;
|
|
||||||
} fsb_decryption_data;
|
|
||||||
|
|
||||||
/* Encrypted FSB info from guessfsb and fsbext */
|
|
||||||
static size_t fsb_decryption_read(STREAMFILE *streamfile, 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 */
|
|
||||||
0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
|
|
||||||
0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
|
|
||||||
0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
|
|
||||||
0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
|
|
||||||
0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
|
|
||||||
0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
|
|
||||||
0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
|
|
||||||
0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
|
|
||||||
0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
|
|
||||||
0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
|
|
||||||
0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
|
|
||||||
0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
|
|
||||||
0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
|
|
||||||
0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
|
|
||||||
0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
|
|
||||||
0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
|
|
||||||
};
|
|
||||||
size_t bytes_read;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
bytes_read = streamfile->read(streamfile, dest, offset, length);
|
|
||||||
|
|
||||||
/* decrypt data (inverted bits and xor) */
|
|
||||||
for (i = 0; i < bytes_read; i++) {
|
|
||||||
uint8_t xor = data->key[(offset + i) % data->key_size];
|
|
||||||
uint8_t val = dest[i];
|
|
||||||
if (data->is_alt) {
|
|
||||||
dest[i] = reverse_bits_table[val ^ xor];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dest[i] = reverse_bits_table[val] ^ xor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
static STREAMFILE* setup_fsb_streamfile(STREAMFILE *streamFile, const uint8_t * key, size_t key_size, int is_alt) {
|
|
||||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
|
||||||
fsb_decryption_data io_data = {0};
|
|
||||||
size_t io_data_size = sizeof(fsb_decryption_data);
|
|
||||||
|
|
||||||
/* setup decryption with key (external) */
|
|
||||||
if (!key_size || key_size > FSB_KEY_MAX) goto fail;
|
|
||||||
|
|
||||||
memcpy(io_data.key, key, key_size);
|
|
||||||
io_data.key_size = key_size;
|
|
||||||
io_data.is_alt = is_alt;
|
|
||||||
|
|
||||||
/* setup subfile */
|
|
||||||
new_streamFile = open_wrap_streamfile(streamFile);
|
|
||||||
if (!new_streamFile) goto fail;
|
|
||||||
temp_streamFile = new_streamFile;
|
|
||||||
|
|
||||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, fsb_decryption_read,NULL);
|
|
||||||
if (!new_streamFile) goto fail;
|
|
||||||
temp_streamFile = new_streamFile;
|
|
||||||
|
|
||||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"fsb");
|
|
||||||
if (!new_streamFile) goto fail;
|
|
||||||
temp_streamFile = new_streamFile;
|
|
||||||
|
|
||||||
return temp_streamFile;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
close_streamfile(temp_streamFile);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
#ifndef _FSB_ENCRYPTED_STREAMFILE_H_
|
||||||
|
#define _FSB_ENCRYPTED_H_
|
||||||
|
|
||||||
|
#define FSB_KEY_MAX 128 /* probably 32 */
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t key[FSB_KEY_MAX];
|
||||||
|
size_t key_size;
|
||||||
|
int is_alt;
|
||||||
|
} fsb_decryption_data;
|
||||||
|
|
||||||
|
/* 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 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,
|
||||||
|
0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
|
||||||
|
0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
|
||||||
|
0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
|
||||||
|
0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
|
||||||
|
0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
|
||||||
|
0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
|
||||||
|
0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
|
||||||
|
0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
|
||||||
|
0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
|
||||||
|
0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
|
||||||
|
0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
|
||||||
|
0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
|
||||||
|
0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
|
||||||
|
0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
|
||||||
|
0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
|
||||||
|
};
|
||||||
|
size_t bytes_read;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
bytes_read = read_streamfile(dest, offset, length, sf);
|
||||||
|
|
||||||
|
/* decrypt data (inverted bits and xor) */
|
||||||
|
for (i = 0; i < bytes_read; i++) {
|
||||||
|
uint8_t xor = data->key[(offset + i) % data->key_size];
|
||||||
|
uint8_t val = dest[i];
|
||||||
|
if (data->is_alt) {
|
||||||
|
dest[i] = reverse_bits_table[val ^ xor];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dest[i] = reverse_bits_table[val] ^ xor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
static STREAMFILE* setup_fsb_streamfile(STREAMFILE* sf, const uint8_t* key, size_t key_size, int is_alt) {
|
||||||
|
STREAMFILE* new_sf = NULL;
|
||||||
|
fsb_decryption_data io_data = {0};
|
||||||
|
size_t io_data_size = sizeof(fsb_decryption_data);
|
||||||
|
|
||||||
|
/* setup decryption with key (external) */
|
||||||
|
if (!key_size || key_size > FSB_KEY_MAX)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memcpy(io_data.key, key, key_size);
|
||||||
|
io_data.key_size = key_size;
|
||||||
|
io_data.is_alt = is_alt;
|
||||||
|
|
||||||
|
/* setup subfile */
|
||||||
|
new_sf = open_wrap_streamfile(sf);
|
||||||
|
new_sf = open_io_streamfile_f(new_sf, &io_data,io_data_size, fsb_decryption_read,NULL);
|
||||||
|
new_sf = open_fakename_streamfile(new_sf, NULL,"fsb");
|
||||||
|
return new_sf;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _FSB5_STREAMFILE_H_ */
|
|
@ -337,6 +337,9 @@ static const hcakey_info hcakey_list[] = {
|
||||||
/* I Chu EtoileStage (Android) */
|
/* I Chu EtoileStage (Android) */
|
||||||
{1433227444226663680}, // 13E3D8C45778A500
|
{1433227444226663680}, // 13E3D8C45778A500
|
||||||
|
|
||||||
|
/* 22/7 Ongaku no Jikan (Android) */
|
||||||
|
{20190906}, // 00000000013416BA
|
||||||
|
|
||||||
/* 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
|
||||||
|
|
||||||
|
|
82
Frameworks/vgmstream/vgmstream/src/meta/kat.c
Normal file
82
Frameworks/vgmstream/vgmstream/src/meta/kat.c
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
#include "meta.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
|
/* .KAT - standard sound bank format used on Dreamcast */
|
||||||
|
VGMSTREAM *init_vgmstream_kat(STREAMFILE *sf) {
|
||||||
|
VGMSTREAM *vgmstream = NULL;
|
||||||
|
uint32_t entry_offset, type, start_offset, data_size, sample_rate, channels, bit_depth, loop_start, loop_end;
|
||||||
|
int loop_flag;
|
||||||
|
int num_sounds, target_stream = sf->stream_index;
|
||||||
|
|
||||||
|
/* checks */
|
||||||
|
if (!check_extensions(sf, "kat"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
num_sounds = read_u32le(0x00, sf);
|
||||||
|
|
||||||
|
if (target_stream == 0) target_stream = 1;
|
||||||
|
if (target_stream < 0 || num_sounds == 0 || target_stream > num_sounds)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
entry_offset = 0x04 + (target_stream - 1) * 0x2c;
|
||||||
|
|
||||||
|
type = read_u32le(entry_offset + 0x00, sf);
|
||||||
|
if (type != 0x01) /* only type 0x01 is supported, other types are MIDI, programs, etc */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
bit_depth = read_u32le(entry_offset + 0x14, sf);
|
||||||
|
if (bit_depth != 4 && bit_depth != 8 && bit_depth != 16)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
start_offset = read_u32le(entry_offset + 0x04, sf);
|
||||||
|
data_size = read_u32le(entry_offset + 0x08, sf);
|
||||||
|
sample_rate = read_u32le(entry_offset + 0x0c, sf);
|
||||||
|
if (sample_rate > 48000)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
loop_flag = read_u32le(entry_offset + 0x10, sf);
|
||||||
|
loop_start = read_u32le(entry_offset + 0x1c, sf);
|
||||||
|
loop_end = read_u32le(entry_offset + 0x20, sf);
|
||||||
|
|
||||||
|
channels = 1; /* mono only */
|
||||||
|
|
||||||
|
/* build the VGMSTREAM */
|
||||||
|
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
/* fill in the vital statistics */
|
||||||
|
vgmstream->meta_type = meta_KAT;
|
||||||
|
vgmstream->sample_rate = sample_rate;
|
||||||
|
vgmstream->loop_start_sample = loop_start;
|
||||||
|
vgmstream->loop_end_sample = loop_end;
|
||||||
|
vgmstream->stream_size = data_size;
|
||||||
|
vgmstream->num_streams = num_sounds;
|
||||||
|
|
||||||
|
switch (bit_depth) {
|
||||||
|
case 4:
|
||||||
|
vgmstream->coding_type = coding_AICA_int;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
vgmstream->num_samples = yamaha_bytes_to_samples(data_size, channels);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
vgmstream->coding_type = coding_PCM8;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channels, 8);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
vgmstream->coding_type = coding_PCM16LE;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channels, 16);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||||
|
goto fail;
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
566
Frameworks/vgmstream/vgmstream/src/meta/ktsr.c
Normal file
566
Frameworks/vgmstream/vgmstream/src/meta/ktsr.c
Normal file
|
@ -0,0 +1,566 @@
|
||||||
|
#include "meta.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
#include "../layout/layout.h"
|
||||||
|
|
||||||
|
typedef enum { NONE, MSADPCM, DSP, GCADPCM, ATRAC9, KVS, /*KNS*/ } ktsr_codec;
|
||||||
|
|
||||||
|
#define MAX_CHANNELS 8
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int total_subsongs;
|
||||||
|
int target_subsong;
|
||||||
|
ktsr_codec codec;
|
||||||
|
|
||||||
|
int platform;
|
||||||
|
int format;
|
||||||
|
|
||||||
|
int channels;
|
||||||
|
int sample_rate;
|
||||||
|
int32_t num_samples;
|
||||||
|
int32_t loop_start;
|
||||||
|
int loop_flag;
|
||||||
|
off_t extra_offset;
|
||||||
|
uint32_t channel_layout;
|
||||||
|
|
||||||
|
int is_external;
|
||||||
|
off_t stream_offsets[MAX_CHANNELS];
|
||||||
|
size_t stream_sizes[MAX_CHANNELS];
|
||||||
|
|
||||||
|
off_t sound_name_offset;
|
||||||
|
off_t config_name_offset;
|
||||||
|
char name[255+1];
|
||||||
|
} ktsr_header;
|
||||||
|
|
||||||
|
static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf);
|
||||||
|
static layered_layout_data* build_layered_atrac9(ktsr_header* ktsr, STREAMFILE *sf, uint32_t config_data);
|
||||||
|
|
||||||
|
|
||||||
|
/* KTSR - Koei Tecmo sound resource countainer */
|
||||||
|
VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) {
|
||||||
|
VGMSTREAM* vgmstream = NULL;
|
||||||
|
STREAMFILE *sf_b = NULL;
|
||||||
|
ktsr_header ktsr = {0};
|
||||||
|
int target_subsong = sf->stream_index;
|
||||||
|
int separate_offsets = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* checks */
|
||||||
|
/* .ktsl2asbin: common [Atelier Ryza (PC/Switch), Nioh (PC)] */
|
||||||
|
if (!check_extensions(sf, "ktsl2asbin"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* KTSR can be a memory file (ktsl2asbin), streams (ktsl2stbin) and global config (ktsl2gcbin)
|
||||||
|
* This accepts ktsl2asbin with internal data, or opening external streams as subsongs.
|
||||||
|
* Some info from KTSR.bt */
|
||||||
|
|
||||||
|
if (read_u32be(0x00, sf) != 0x4B545352) /* "KTSR" */
|
||||||
|
goto fail;
|
||||||
|
if (read_u32be(0x04, sf) != 0x777B481A) /* hash(?) id: 0x777B481A=as, 0x0294DDFC=st, 0xC638E69E=gc */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
|
ktsr.target_subsong = target_subsong;
|
||||||
|
|
||||||
|
if (!parse_ktsr(&ktsr, sf))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* open companion body */
|
||||||
|
if (ktsr.is_external) {
|
||||||
|
sf_b = open_streamfile_by_ext(sf, "ktsl2stbin");
|
||||||
|
if (!sf_b) {
|
||||||
|
VGM_LOG("KTSR: companion file not found\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sf_b = sf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* build the VGMSTREAM */
|
||||||
|
vgmstream = allocate_vgmstream(ktsr.channels, ktsr.loop_flag);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
vgmstream->meta_type = meta_KTSR;
|
||||||
|
vgmstream->sample_rate = ktsr.sample_rate;
|
||||||
|
vgmstream->num_samples = ktsr.num_samples;
|
||||||
|
vgmstream->loop_start_sample = ktsr.loop_start;
|
||||||
|
vgmstream->loop_end_sample = ktsr.num_samples;
|
||||||
|
vgmstream->stream_size = ktsr.stream_sizes[0];
|
||||||
|
vgmstream->num_streams = ktsr.total_subsongs;
|
||||||
|
vgmstream->channel_layout = ktsr.channel_layout;
|
||||||
|
strcpy(vgmstream->stream_name, ktsr.name);
|
||||||
|
|
||||||
|
switch(ktsr.codec) {
|
||||||
|
|
||||||
|
case MSADPCM:
|
||||||
|
vgmstream->coding_type = coding_MSADPCM_int;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
separate_offsets = 1;
|
||||||
|
|
||||||
|
/* 0x00: samples per frame */
|
||||||
|
vgmstream->frame_size = read_u16le(ktsr.extra_offset + 0x02, sf_b);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DSP:
|
||||||
|
vgmstream->coding_type = coding_NGC_DSP;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
separate_offsets = 1;
|
||||||
|
|
||||||
|
dsp_read_coefs_le(vgmstream, sf, ktsr.extra_offset + 0x1c, 0x60);
|
||||||
|
dsp_read_hist_le (vgmstream, sf, ktsr.extra_offset + 0x40, 0x60);
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef VGM_USE_ATRAC9
|
||||||
|
case ATRAC9: {
|
||||||
|
/* 0x00: samples per frame */
|
||||||
|
/* 0x02: frame size */
|
||||||
|
uint32_t config_data = read_u32be(ktsr.extra_offset + 0x04, sf);
|
||||||
|
if ((config_data & 0xFF) == 0xFE) /* later versions(?) in LE */
|
||||||
|
config_data = read_u32le(ktsr.extra_offset + 0x04, sf);
|
||||||
|
|
||||||
|
vgmstream->layout_data = build_layered_atrac9(&ktsr, sf_b, config_data);
|
||||||
|
if (!vgmstream->layout_data) goto fail;
|
||||||
|
vgmstream->layout_type = layout_layered;
|
||||||
|
vgmstream->coding_type = coding_ATRAC9;
|
||||||
|
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
|
||||||
|
|
||||||
|
#ifdef VGM_USE_VORBIS
|
||||||
|
case KVS: {
|
||||||
|
VGMSTREAM *ogg_vgmstream = NULL; //TODO: meh
|
||||||
|
STREAMFILE *sf_kvs = setup_subfile_streamfile(sf_b, ktsr.stream_offsets[0], ktsr.stream_sizes[0], "kvs");
|
||||||
|
if (!sf_kvs) goto fail;
|
||||||
|
|
||||||
|
ogg_vgmstream = init_vgmstream_ogg_vorbis(sf_kvs);
|
||||||
|
close_streamfile(sf_kvs);
|
||||||
|
if (ogg_vgmstream) {
|
||||||
|
ogg_vgmstream->stream_size = vgmstream->stream_size;
|
||||||
|
ogg_vgmstream->num_streams = vgmstream->num_streams;
|
||||||
|
ogg_vgmstream->channel_layout = vgmstream->channel_layout;
|
||||||
|
/* loops look shared */
|
||||||
|
strcpy(ogg_vgmstream->stream_name, vgmstream->stream_name);
|
||||||
|
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
if (sf_b != sf) close_streamfile(sf_b);
|
||||||
|
return ogg_vgmstream;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!vgmstream_open_stream_bf(vgmstream, sf_b, ktsr.stream_offsets[0], 1))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
|
/* data offset per channel is absolute (not actual interleave since there is padding) in some cases */
|
||||||
|
if (separate_offsets) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < ktsr.channels; i++) {
|
||||||
|
vgmstream->ch[i].offset = ktsr.stream_offsets[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sf_b != sf) close_streamfile(sf_b);
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (sf_b != sf) close_streamfile(sf_b);
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static layered_layout_data* build_layered_atrac9(ktsr_header* ktsr, STREAMFILE* sf, uint32_t config_data) {
|
||||||
|
STREAMFILE* temp_sf = NULL;
|
||||||
|
layered_layout_data* data = NULL;
|
||||||
|
int layers = ktsr->channels;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
|
||||||
|
/* init layout */
|
||||||
|
data = init_layout_layered(layers);
|
||||||
|
if (!data) goto fail;
|
||||||
|
|
||||||
|
for (i = 0; i < layers; i++) {
|
||||||
|
data->layers[i] = allocate_vgmstream(1, 0);
|
||||||
|
if (!data->layers[i]) goto fail;
|
||||||
|
|
||||||
|
data->layers[i]->sample_rate = ktsr->sample_rate;
|
||||||
|
data->layers[i]->num_samples = ktsr->num_samples;
|
||||||
|
|
||||||
|
#ifdef VGM_USE_ATRAC9
|
||||||
|
{
|
||||||
|
atrac9_config cfg = {0};
|
||||||
|
|
||||||
|
cfg.config_data = config_data;
|
||||||
|
cfg.channels = 1;
|
||||||
|
cfg.encoder_delay = 256; /* observed default (ex. Attack on Titan PC vs Vita) */
|
||||||
|
|
||||||
|
data->layers[i]->codec_data = init_atrac9(&cfg);
|
||||||
|
if (!data->layers[i]->codec_data) goto fail;
|
||||||
|
data->layers[i]->coding_type = coding_ATRAC9;
|
||||||
|
data->layers[i]->layout_type = layout_none;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
goto fail;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
temp_sf = setup_subfile_streamfile(sf, ktsr->stream_offsets[i], ktsr->stream_sizes[i], NULL);
|
||||||
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
|
if (!vgmstream_open_stream(data->layers[i], temp_sf, 0x00))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
temp_sf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup layered VGMSTREAMs */
|
||||||
|
if (!setup_layout_layered(data))
|
||||||
|
goto fail;
|
||||||
|
return data;
|
||||||
|
fail:
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
free_layout_layered(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int parse_codec(ktsr_header* ktsr) {
|
||||||
|
|
||||||
|
/* platform + format to codec, simplified until more codec combos are found */
|
||||||
|
switch(ktsr->platform) {
|
||||||
|
case 0x01: /* PC */
|
||||||
|
if (ktsr->is_external)
|
||||||
|
ktsr->codec = KVS;
|
||||||
|
else if (ktsr->format == 0x00)
|
||||||
|
ktsr->codec = MSADPCM;
|
||||||
|
else
|
||||||
|
goto fail;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x03: /* VITA */
|
||||||
|
if (ktsr->is_external)
|
||||||
|
goto fail;
|
||||||
|
else if (ktsr->format == 0x01)
|
||||||
|
ktsr->codec = ATRAC9;
|
||||||
|
else
|
||||||
|
goto fail;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x04: /* Switch */
|
||||||
|
if (ktsr->is_external)
|
||||||
|
goto fail; /* KTSS? */
|
||||||
|
else if (ktsr->format == 0x00)
|
||||||
|
ktsr->codec = DSP;
|
||||||
|
else
|
||||||
|
goto fail;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
fail:
|
||||||
|
VGM_LOG("KTSR: unknown codec combo: ext=%x, fmt=%x, ptf=%x\n", ktsr->is_external, ktsr->format, ktsr->platform);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_ktsr_subfile(ktsr_header* ktsr, STREAMFILE* sf, off_t offset) {
|
||||||
|
off_t suboffset, starts_offset, sizes_offset;
|
||||||
|
int i;
|
||||||
|
uint32_t type;
|
||||||
|
|
||||||
|
type = read_u32be(offset + 0x00, sf);
|
||||||
|
//size = read_u32le(offset + 0x04, sf);
|
||||||
|
|
||||||
|
/* probably could check the flag in sound header, but the format is kinda messy */
|
||||||
|
switch(type) { /* hash-id? */
|
||||||
|
|
||||||
|
case 0x38D0437D: /* external [Nioh (PC), Atelier Ryza (PC)] */
|
||||||
|
/* 08 subtype? (ex. 0x522B86B9)
|
||||||
|
* 0c channels
|
||||||
|
* 10 ? (always 0x002706B8)
|
||||||
|
* 14 codec? (05=KVS)
|
||||||
|
* 18 sample rate
|
||||||
|
* 1c num samples
|
||||||
|
* 20 null?
|
||||||
|
* 24 loop start or -1 (loop end is num samples)
|
||||||
|
* 28 channel layout (or null?)
|
||||||
|
* 2c null
|
||||||
|
* 30 null
|
||||||
|
* 34 data offset (absolute to external stream, points to actual format and not to mini-header)
|
||||||
|
* 38 data size
|
||||||
|
* 3c always 0x0200
|
||||||
|
*/
|
||||||
|
|
||||||
|
ktsr->channels = read_u32le(offset + 0x0c, sf);
|
||||||
|
ktsr->format = read_u32le(offset + 0x14, sf);
|
||||||
|
/* other fields will be read in the external stream */
|
||||||
|
|
||||||
|
ktsr->channel_layout= read_u32le(offset + 0x28, sf);
|
||||||
|
|
||||||
|
ktsr->stream_offsets[0] = read_u32le(offset + 0x34, sf);
|
||||||
|
ktsr->stream_sizes[0] = read_u32le(offset + 0x38, sf);
|
||||||
|
ktsr->is_external = 1;
|
||||||
|
|
||||||
|
if (ktsr->format != 0x05) {
|
||||||
|
VGM_LOG("KTSR: unknown subcodec at %lx\n", offset);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x41FDBD4E: /* internal [Attack on Titan: Wings of Freedom (Vita)] */
|
||||||
|
case 0x6FF273F9: /* internal [Attack on Titan: Wings of Freedom (PC/Vita)] */
|
||||||
|
case 0x6FCAB62E: /* internal [Marvel Ultimate Alliance 3: The Black Order (Switch)] */
|
||||||
|
case 0x6AD86FE9: /* internal [Atelier Ryza (PC/Switch), Persona5 Scramble (Switch)] */
|
||||||
|
case 0x10250527: /* internal [Fire Emblem: Three Houses DLC (Switch)] */
|
||||||
|
/* 08 subtype? (0x6029DBD2, 0xD20A92F90, 0xDC6FF709)
|
||||||
|
* 0c channels
|
||||||
|
* 10 format? (00=platform's ADPCM? 01=ATRAC9?)
|
||||||
|
* 11 bps? (always 16)
|
||||||
|
* 12 null
|
||||||
|
* 14 sample rate
|
||||||
|
* 18 num samples
|
||||||
|
* 1c null or 0x100?
|
||||||
|
* 20 loop start or -1 (loop end is num samples)
|
||||||
|
* 24 channel layout or null
|
||||||
|
* 28 header offset (within subfile)
|
||||||
|
* 2c header size [B, C]
|
||||||
|
* 30 offset to data start offset [A, C] or to data start+size [B]
|
||||||
|
* 34 offset to data size [A, C] or same per channel
|
||||||
|
* 38 always 0x0200
|
||||||
|
* -- header
|
||||||
|
* -- data start offset
|
||||||
|
* -- data size
|
||||||
|
*/
|
||||||
|
|
||||||
|
ktsr->channels = read_u32le(offset + 0x0c, sf);
|
||||||
|
ktsr->format = read_u8 (offset + 0x10, sf);
|
||||||
|
ktsr->sample_rate = read_s32le(offset + 0x14, sf);
|
||||||
|
ktsr->num_samples = read_s32le(offset + 0x18, sf);
|
||||||
|
ktsr->loop_start = read_s32le(offset + 0x20, sf);
|
||||||
|
ktsr->channel_layout= read_u32le(offset + 0x24, sf);
|
||||||
|
ktsr->extra_offset = read_u32le(offset + 0x28, sf) + offset;
|
||||||
|
if (type == 0x41FDBD4E || type == 0x6FF273F9) /* v1 */
|
||||||
|
suboffset = offset + 0x2c;
|
||||||
|
else
|
||||||
|
suboffset = offset + 0x30;
|
||||||
|
|
||||||
|
if (ktsr->channels > MAX_CHANNELS) {
|
||||||
|
VGM_LOG("KTSR: max channels found\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
starts_offset = read_u32le(suboffset + 0x00, sf) + offset;
|
||||||
|
sizes_offset = read_u32le(suboffset + 0x04, sf) + offset;
|
||||||
|
for (i = 0; i < ktsr->channels; i++) {
|
||||||
|
ktsr->stream_offsets[i] = read_u32le(starts_offset + 0x04*i, sf) + offset;
|
||||||
|
ktsr->stream_sizes[i] = read_u32le(sizes_offset + 0x04*i, sf);
|
||||||
|
}
|
||||||
|
|
||||||
|
ktsr->loop_flag = (ktsr->loop_start >= 0);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* streams also have their own chunks like 0x09D4F415, not needed here */
|
||||||
|
VGM_LOG("KTSR: unknown subheader at %lx\n", offset);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parse_codec(ktsr))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
fail:
|
||||||
|
VGM_LOG("KTSR: error parsing subheader\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void build_name(ktsr_header* ktsr, STREAMFILE* sf) {
|
||||||
|
char sound_name[255] = {0};
|
||||||
|
char config_name[255] = {0};
|
||||||
|
|
||||||
|
/* names can be different or same but usually config is better */
|
||||||
|
if (ktsr->sound_name_offset) {
|
||||||
|
read_string(sound_name, sizeof(sound_name), ktsr->sound_name_offset, sf);
|
||||||
|
}
|
||||||
|
if (ktsr->config_name_offset) {
|
||||||
|
read_string(config_name, sizeof(config_name), ktsr->config_name_offset, sf);
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (longname[0] && shortname[0]) {
|
||||||
|
// snprintf(ktsr->name, sizeof(ktsr->name), "%s; %s", longname, shortname);
|
||||||
|
//}
|
||||||
|
if (config_name[0]) {
|
||||||
|
snprintf(ktsr->name, sizeof(ktsr->name), "%s", config_name);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (sound_name[0]) {
|
||||||
|
snprintf(ktsr->name, sizeof(ktsr->name), "%s", sound_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_longname(ktsr_header* ktsr, STREAMFILE* sf, uint32_t target_id) {
|
||||||
|
/* more configs than sounds is possible so we need target_id first */
|
||||||
|
off_t offset, end, name_offset;
|
||||||
|
uint32_t stream_id;
|
||||||
|
|
||||||
|
offset = 0x40;
|
||||||
|
end = get_streamfile_size(sf);
|
||||||
|
while (offset < end) {
|
||||||
|
uint32_t type = read_u32be(offset + 0x00, sf); /* hash-id? */
|
||||||
|
uint32_t size = read_u32le(offset + 0x04, sf);
|
||||||
|
switch(type) {
|
||||||
|
case 0xBD888C36: /* config */
|
||||||
|
stream_id = read_u32be(offset + 0x08, sf);
|
||||||
|
if (stream_id != target_id)
|
||||||
|
break;
|
||||||
|
|
||||||
|
name_offset = read_u32le(offset + 0x28, sf);
|
||||||
|
if (name_offset > 0)
|
||||||
|
ktsr->config_name_offset = offset + name_offset;
|
||||||
|
return; /* id found */
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) {
|
||||||
|
off_t offset, end, header_offset, name_offset;
|
||||||
|
uint32_t stream_id = 0, stream_count;
|
||||||
|
|
||||||
|
/* 00: KTSR
|
||||||
|
* 04: type
|
||||||
|
* 08: version?
|
||||||
|
* 0a: unknown (usually 00, 02/03 seen in Vita)
|
||||||
|
* 0b: platform (01=PC, 03=Vita, 04=Switch)
|
||||||
|
* 0c: game id?
|
||||||
|
* 10: null
|
||||||
|
* 14: null
|
||||||
|
* 18: file size
|
||||||
|
* 1c: file size
|
||||||
|
* up to 40: reserved
|
||||||
|
* until end: entries (totals not defined) */
|
||||||
|
|
||||||
|
ktsr->platform = read_u8(0x0b,sf);
|
||||||
|
|
||||||
|
if (read_u32le(0x18, sf) != read_u32le(0x1c, sf))
|
||||||
|
goto fail;
|
||||||
|
if (read_u32le(0x1c, sf) != get_streamfile_size(sf))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
offset = 0x40;
|
||||||
|
end = get_streamfile_size(sf);
|
||||||
|
while (offset < end) {
|
||||||
|
uint32_t type = read_u32be(offset + 0x00, sf); /* hash-id? */
|
||||||
|
uint32_t size = read_u32le(offset + 0x04, sf);
|
||||||
|
|
||||||
|
/* parse chunk-like subfiles, usually N configs then N songs */
|
||||||
|
switch(type) {
|
||||||
|
case 0x6172DBA8: /* padding (empty) */
|
||||||
|
case 0xBD888C36: /* config (floats, stream id, etc, may have extended name) */
|
||||||
|
case 0xC9C48EC1: /* unknown (has some string inside like "boss") */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC5CCCB70: /* sound (internal data or external stream) */
|
||||||
|
//VGM_LOG("info at %lx\n", offset);
|
||||||
|
ktsr->total_subsongs++;
|
||||||
|
|
||||||
|
/* sound table:
|
||||||
|
* 08: stream id (used in several places)
|
||||||
|
* 0c: unknown (low number but not version?)
|
||||||
|
* 0e: external flag
|
||||||
|
* 10: sub-streams?
|
||||||
|
* 14: offset to header offset
|
||||||
|
* 18: offset to name
|
||||||
|
* --: name
|
||||||
|
* --: header offset
|
||||||
|
* --: header
|
||||||
|
* --: subheader (varies) */
|
||||||
|
|
||||||
|
|
||||||
|
if (ktsr->total_subsongs == ktsr->target_subsong) {
|
||||||
|
//;VGM_LOG("KTSR: target at %lx\n", offset);
|
||||||
|
|
||||||
|
stream_id = read_u32be(offset + 0x08,sf);
|
||||||
|
//ktsr->is_external = read_u16le(offset + 0x0e,sf);
|
||||||
|
stream_count = read_u32le(offset + 0x10,sf);
|
||||||
|
if (stream_count != 1) {
|
||||||
|
VGM_LOG("KTSR: unknown stream count\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
header_offset = read_u32le(offset + 0x14, sf);
|
||||||
|
name_offset = read_u32le(offset + 0x18, sf);
|
||||||
|
if (name_offset > 0)
|
||||||
|
ktsr->sound_name_offset = offset + name_offset;
|
||||||
|
|
||||||
|
header_offset = read_u32le(offset + header_offset, sf) + offset;
|
||||||
|
|
||||||
|
if (!parse_ktsr_subfile(ktsr, sf, header_offset))
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* streams also have their own chunks like 0x09D4F415, not needed here */
|
||||||
|
VGM_LOG("KTSR: unknown chunk at %lx\n", offset);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ktsr->target_subsong > ktsr->total_subsongs)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
parse_longname(ktsr, sf, stream_id);
|
||||||
|
build_name(ktsr, sf);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
fail:
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -137,7 +137,6 @@ VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE *streamFile, uint16_t subkey);
|
||||||
|
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
VGMSTREAM * init_vgmstream_ffmpeg(STREAMFILE *streamFile);
|
VGMSTREAM * init_vgmstream_ffmpeg(STREAMFILE *streamFile);
|
||||||
VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size);
|
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE * streamFile);
|
VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE * streamFile);
|
||||||
#endif
|
#endif
|
||||||
|
@ -654,7 +653,10 @@ VGMSTREAM * init_vgmstream_naac(STREAMFILE * streamFile);
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE * streamFile);
|
VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE * streamFile);
|
||||||
VGMSTREAM * init_vgmstream_ubi_sm(STREAMFILE * streamFile);
|
VGMSTREAM * init_vgmstream_ubi_sm(STREAMFILE * streamFile);
|
||||||
|
VGMSTREAM * init_vgmstream_ubi_dat(STREAMFILE * streamFile);
|
||||||
VGMSTREAM * init_vgmstream_ubi_bnm(STREAMFILE * streamFile);
|
VGMSTREAM * init_vgmstream_ubi_bnm(STREAMFILE * streamFile);
|
||||||
|
VGMSTREAM * init_vgmstream_ubi_bnm_ps2(STREAMFILE * streamFile);
|
||||||
|
VGMSTREAM * init_vgmstream_ubi_blk(STREAMFILE * streamFile);
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_ezw(STREAMFILE * streamFile);
|
VGMSTREAM * init_vgmstream_ezw(STREAMFILE * streamFile);
|
||||||
|
|
||||||
|
@ -897,4 +899,12 @@ VGMSTREAM* init_vgmstream_diva(STREAMFILE* sf);
|
||||||
|
|
||||||
VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf);
|
VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf);
|
||||||
|
|
||||||
|
VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf);
|
||||||
|
|
||||||
|
VGMSTREAM* init_vgmstream_mups(STREAMFILE* sf);
|
||||||
|
|
||||||
|
VGMSTREAM* init_vgmstream_kat(STREAMFILE* sf);
|
||||||
|
|
||||||
|
VGMSTREAM* init_vgmstream_pcm_success(STREAMFILE* sf);
|
||||||
|
|
||||||
#endif /*_META_H*/
|
#endif /*_META_H*/
|
||||||
|
|
42
Frameworks/vgmstream/vgmstream/src/meta/mups.c
Normal file
42
Frameworks/vgmstream/vgmstream/src/meta/mups.c
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include "meta.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
#include "mups_streamfile.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* MUPS - from Watermelon/HUCARD games (same programmer) [Pier Solar and the Great Architects (PC), Ghost Blade HD (PC/Switch)] */
|
||||||
|
VGMSTREAM* init_vgmstream_mups(STREAMFILE* sf) {
|
||||||
|
VGMSTREAM* vgmstream = NULL;
|
||||||
|
STREAMFILE *temp_sf = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/* checks */
|
||||||
|
/* mups: header id?
|
||||||
|
* (extensionless): default? */
|
||||||
|
if (!check_extensions(sf, "mups,"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (read_u32be(0x00,sf) != 0x4D555053) /* "MUPS" */
|
||||||
|
goto fail;
|
||||||
|
if (read_u32be(0x08,sf) != 0x50737348) /* "PssH" */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* just an Ogg with changed OggS/vorbis words (see streamfile) */
|
||||||
|
temp_sf = setup_mups_streamfile(sf, 0x08);
|
||||||
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
|
#ifdef VGM_USE_VORBIS
|
||||||
|
vgmstream = init_vgmstream_ogg_vorbis(temp_sf);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
#else
|
||||||
|
goto fail;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
102
Frameworks/vgmstream/vgmstream/src/meta/mups_streamfile.h
Normal file
102
Frameworks/vgmstream/vgmstream/src/meta/mups_streamfile.h
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
#ifndef _MUPS_STREAMFILE_H_
|
||||||
|
#define _MUPS_STREAMFILE_H_
|
||||||
|
#include "deblock_streamfile.h"
|
||||||
|
|
||||||
|
static inline int32_t max32(int32_t val1, int32_t val2) {
|
||||||
|
if (val1 > val2)
|
||||||
|
return val2;
|
||||||
|
return val1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read_callback(uint8_t* dst, deblock_io_data* data, size_t block_pos, size_t read_size) {
|
||||||
|
static const uint8_t oggs[] = { 0x4F, 0x67, 0x67, 0x53 };
|
||||||
|
static const uint8_t vorbis[] = { 0x76, 0x6F, 0x72, 0x62, 0x69, 0x73 };
|
||||||
|
int i, min, max;
|
||||||
|
|
||||||
|
/* Swaps Xiph magic words back (resulting page checksum is ok).
|
||||||
|
* Reads can start/end anywhere, but block_pos = 0 is always page start */
|
||||||
|
|
||||||
|
/* change "PssH" back to "OggS" */
|
||||||
|
if (block_pos < 0x04) {
|
||||||
|
min = block_pos;
|
||||||
|
if (min < 0x00)
|
||||||
|
min = 0x00;
|
||||||
|
|
||||||
|
max = block_pos + read_size;
|
||||||
|
if (max > 0x04)
|
||||||
|
max = 0x04;
|
||||||
|
|
||||||
|
for (i = min; i < max; i++) {
|
||||||
|
dst[i] = oggs[i - 0x00];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first page also needs "psolar" to "vorbis" */
|
||||||
|
if (data->logical_offset == 0 && block_pos < 0x23) {
|
||||||
|
min = block_pos;
|
||||||
|
if (min < 0x1d)
|
||||||
|
min = 0x1d;
|
||||||
|
|
||||||
|
max = block_pos + read_size;
|
||||||
|
if (max > 0x23)
|
||||||
|
max = 0x23;
|
||||||
|
|
||||||
|
for (i = min; i < max; i++) {
|
||||||
|
dst[i] = vorbis[i - 0x1d];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_page_size(STREAMFILE* sf, off_t page_offset) {
|
||||||
|
static const int base_size = 0x1b;
|
||||||
|
uint8_t page[0x1b + 0x100];
|
||||||
|
uint8_t segments;
|
||||||
|
size_t page_size;
|
||||||
|
int i, bytes;
|
||||||
|
|
||||||
|
bytes = read_streamfile(page + 0x00, page_offset + 0x00, base_size, sf);
|
||||||
|
if (bytes != base_size) goto fail;
|
||||||
|
|
||||||
|
if (get_u32be(page + 0x00) != 0x50737348) /* "PssH" */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
segments = get_u8(page + 0x1a);
|
||||||
|
|
||||||
|
bytes = read_streamfile(page + base_size, page_offset + base_size, segments, sf);
|
||||||
|
if (bytes != segments) goto fail;
|
||||||
|
|
||||||
|
page_size = base_size + segments;
|
||||||
|
for (i = 0; i < segments; i++) {
|
||||||
|
uint8_t segment_size = get_u8(page + base_size + i);
|
||||||
|
page_size += segment_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return page_size;
|
||||||
|
fail:
|
||||||
|
return -1; /* not a valid page */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void block_callback(STREAMFILE* sf, deblock_io_data* data) {
|
||||||
|
off_t page_offset = data->physical_offset;
|
||||||
|
|
||||||
|
/* block size = OggS page size as we need read_callback called on page starts */
|
||||||
|
data->data_size = get_page_size(sf, page_offset);
|
||||||
|
data->block_size = data->data_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fixes MUPS streams that contain mutated OggS */
|
||||||
|
static STREAMFILE* setup_mups_streamfile(STREAMFILE* sf, off_t stream_offset) {
|
||||||
|
STREAMFILE* new_sf = NULL;
|
||||||
|
deblock_config_t cfg = {0};
|
||||||
|
|
||||||
|
cfg.stream_start = stream_offset;
|
||||||
|
cfg.block_callback = block_callback;
|
||||||
|
cfg.read_callback = read_callback;
|
||||||
|
|
||||||
|
new_sf = open_wrap_streamfile(sf);
|
||||||
|
new_sf = open_io_deblock_streamfile_f(new_sf, &cfg);
|
||||||
|
new_sf = open_fakename_streamfile_f(new_sf, NULL, "ogg");
|
||||||
|
return new_sf;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _MUPS_STREAMFILE_H_ */
|
|
@ -655,48 +655,6 @@ fail:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sadf - Procyon Studio Header Variant [Xenoblade Chronicles 2 (Switch)] (sfx) */
|
|
||||||
VGMSTREAM * init_vgmstream_sadf(STREAMFILE *streamFile) {
|
|
||||||
VGMSTREAM * vgmstream = NULL;
|
|
||||||
int channel_count, loop_flag;
|
|
||||||
off_t start_offset;
|
|
||||||
|
|
||||||
/* checks */
|
|
||||||
if (!check_extensions(streamFile, "sad"))
|
|
||||||
goto fail;
|
|
||||||
if (read_32bitBE(0x00, streamFile) != 0x73616466) /* "sadf" */
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
channel_count = read_8bit(0x18, streamFile);
|
|
||||||
loop_flag = read_8bit(0x19, streamFile);
|
|
||||||
start_offset = read_32bitLE(0x1C, streamFile);
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
|
||||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
|
||||||
if (!vgmstream) goto fail;
|
|
||||||
|
|
||||||
vgmstream->num_samples = read_32bitLE(0x28, streamFile);
|
|
||||||
vgmstream->sample_rate = read_32bitLE(0x24, streamFile);
|
|
||||||
if (loop_flag) {
|
|
||||||
vgmstream->loop_start_sample = read_32bitLE(0x2c, streamFile);
|
|
||||||
vgmstream->loop_end_sample = read_32bitLE(0x30, streamFile);
|
|
||||||
}
|
|
||||||
vgmstream->coding_type = coding_NGC_DSP;
|
|
||||||
vgmstream->layout_type = layout_interleave;
|
|
||||||
vgmstream->interleave_block_size = channel_count == 1 ? 0x8 :
|
|
||||||
read_32bitLE(0x20, streamFile) / channel_count;
|
|
||||||
vgmstream->meta_type = meta_DSP_SADF;
|
|
||||||
|
|
||||||
dsp_read_coefs_le(vgmstream, streamFile, 0x80, 0x80);
|
|
||||||
|
|
||||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
|
||||||
goto fail;
|
|
||||||
return vgmstream;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
close_vgmstream(vgmstream);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* IDSP - Traveller's Tales header + interleaved dsps [Lego Batman (Wii), Lego Dimensions (Wii U)] */
|
/* IDSP - Traveller's Tales header + interleaved dsps [Lego Batman (Wii), Lego Dimensions (Wii U)] */
|
||||||
VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile) {
|
||||||
|
|
68
Frameworks/vgmstream/vgmstream/src/meta/pcm_success.c
Normal file
68
Frameworks/vgmstream/vgmstream/src/meta/pcm_success.c
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#include "meta.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* PCM - from Success (related) games [Metal Saga (PS2), Tetris Kiwamemichi (PS2), Duel Masters: Rebirth of Super Dragon (PS2)] */
|
||||||
|
VGMSTREAM* init_vgmstream_pcm_success(STREAMFILE* sf) {
|
||||||
|
VGMSTREAM* vgmstream = NULL;
|
||||||
|
off_t start_offset;
|
||||||
|
int loop_flag, channels, sample_rate, interleave;
|
||||||
|
size_t data_size, loop_start, loop_end, loop_adjust;
|
||||||
|
|
||||||
|
|
||||||
|
/* checks */
|
||||||
|
if (!check_extensions(sf, "pcm"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (read_u32be(0x00,sf) != 0x50434D20) /* "PCM " */
|
||||||
|
goto fail;
|
||||||
|
if (read_u32le(0x04,sf) != 0x00010000) /* version? */
|
||||||
|
goto fail;
|
||||||
|
if (read_u32le(0x08,sf) + 0x8000 < get_streamfile_size(sf)) /* data size without padding */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
interleave = 0x800;
|
||||||
|
start_offset = 0x800;
|
||||||
|
|
||||||
|
sample_rate = read_s32le(0x0c,sf);
|
||||||
|
channels = read_s32le(0x10,sf);
|
||||||
|
loop_flag = read_s32le(0x14,sf);
|
||||||
|
|
||||||
|
data_size = read_s32le(0x18,sf) * interleave * channels;
|
||||||
|
/* loops seems slightly off, so 'adjust' meaning may need to be tweaked */
|
||||||
|
loop_adjust = read_s32le(0x1c,sf) * channels; /* from 0..<0x800 */
|
||||||
|
loop_start = read_s32le(0x20,sf) * interleave * channels + loop_adjust;
|
||||||
|
loop_adjust = read_s32le(0x24,sf) * channels; /* always 0x800 (0 if no loop flag) */
|
||||||
|
loop_end = read_s32le(0x28,sf) * interleave * channels + (interleave * channels - loop_adjust);
|
||||||
|
|
||||||
|
/* 0x2c: always 1? */
|
||||||
|
/* 0x30/40: padding garbage (also at file end) */
|
||||||
|
|
||||||
|
/* not always accurate and has padding */
|
||||||
|
if (data_size > get_streamfile_size(sf) - start_offset)
|
||||||
|
data_size = get_streamfile_size(sf) - start_offset;
|
||||||
|
|
||||||
|
|
||||||
|
/* build the VGMSTREAM */
|
||||||
|
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
vgmstream->meta_type = meta_PCM_SUCCESS;
|
||||||
|
vgmstream->sample_rate = sample_rate;
|
||||||
|
|
||||||
|
vgmstream->num_samples = ps_bytes_to_samples(data_size, channels);
|
||||||
|
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channels);
|
||||||
|
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, channels);
|
||||||
|
|
||||||
|
vgmstream->coding_type = coding_PSX;
|
||||||
|
vgmstream->layout_type = layout_interleave;
|
||||||
|
vgmstream->interleave_block_size = interleave;
|
||||||
|
|
||||||
|
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||||
|
goto fail;
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE *streamFile) {
|
||||||
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, loop_start = 0, loop_end = 0;
|
int32_t num_samples;
|
||||||
size_t file_size, data_size, unknown1, unknown2, interleave, padding_size;
|
size_t file_size, data_size, unknown1, unknown2, interleave, padding_size;
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,8 +65,6 @@ VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
vgmstream->sample_rate = sample_rate;
|
vgmstream->sample_rate = sample_rate;
|
||||||
vgmstream->num_samples = num_samples;
|
vgmstream->num_samples = num_samples;
|
||||||
vgmstream->loop_start_sample = loop_start;
|
|
||||||
vgmstream->loop_end_sample = loop_end;
|
|
||||||
vgmstream->stream_size = data_size;
|
vgmstream->stream_size = data_size;
|
||||||
|
|
||||||
vgmstream->coding_type = coding_PSX;
|
vgmstream->coding_type = coding_PSX;
|
||||||
|
|
|
@ -132,9 +132,10 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (fmt->codec) {
|
switch (fmt->codec) {
|
||||||
case 0x00: /* Yamaha AICA ADPCM [Headhunter (DC), Bomber hehhe (DC)] (unofficial) */
|
case 0x00: /* Yamaha AICA ADPCM [Headhunter (DC), Bomber hehhe (DC), Rayman 2 (DC)] (unofficial) */
|
||||||
if (fmt->bps != 4) goto fail;
|
if (fmt->bps != 4) goto fail;
|
||||||
if (fmt->block_size != 0x02*fmt->channel_count) goto fail;
|
if (fmt->block_size != 0x02*fmt->channel_count &&
|
||||||
|
fmt->block_size != 0x01*fmt->channel_count) goto fail;
|
||||||
fmt->coding_type = coding_AICA_int;
|
fmt->coding_type = coding_AICA_int;
|
||||||
fmt->interleave = 0x01;
|
fmt->interleave = 0x01;
|
||||||
break;
|
break;
|
||||||
|
@ -370,14 +371,25 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||||
uint16_t codec = read_16bitLE(0x14,streamFile);
|
uint16_t codec = read_16bitLE(0x14,streamFile);
|
||||||
if (riff_size+0x08+0x01 == file_size)
|
if (riff_size+0x08+0x01 == file_size)
|
||||||
riff_size += 0x01; /* [Shikkoku no Sharnoth (PC)] */
|
riff_size += 0x01; /* [Shikkoku no Sharnoth (PC)] */
|
||||||
|
|
||||||
else if (riff_size == file_size && codec == 0x0069)
|
else if (riff_size == file_size && codec == 0x0069)
|
||||||
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 == 0x0000)
|
|
||||||
riff_size -= 0x04; /* [Headhunter (DC), Bomber hehhe (DC)] */
|
|
||||||
else if (riff_size + 0x04 == file_size && codec == 0x0069)
|
else if (riff_size + 0x04 == file_size && codec == 0x0069)
|
||||||
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)
|
||||||
|
riff_size -= 0x04; /* [Headhunter (DC), Bomber hehhe (DC)] */
|
||||||
|
|
||||||
|
else if (riff_size == file_size && codec == 0x0000)
|
||||||
|
riff_size -= 0x08; /* [Rayman 2 (DC)] */
|
||||||
|
|
||||||
|
else if (riff_size + 0x02 + 0x08 == file_size && codec == 0x0000)
|
||||||
|
riff_size -= 0x02; /* [Rayman 2 (DC)]-dcz */
|
||||||
|
|
||||||
else if (riff_size == file_size && codec == 0x0300)
|
else if (riff_size == file_size && codec == 0x0300)
|
||||||
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 (riff_size >= file_size && read_32bitBE(0x24,streamFile) == 0x4E584246) /* "NXBF" */
|
||||||
riff_size = file_size - 0x08; /* [R:Racing Evolution (Xbox)] */
|
riff_size = file_size - 0x08; /* [R:Racing Evolution (Xbox)] */
|
||||||
}
|
}
|
||||||
|
@ -405,7 +417,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||||
if (!read_fmt(0, streamFile, current_chunk, &fmt, mwv))
|
if (!read_fmt(0, streamFile, current_chunk, &fmt, mwv))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* some Dreamcast/Naomi games again [Headhunter (DC), Bomber hehhe (DC)] */
|
/* some Dreamcast/Naomi games again [Headhunter (DC), Bomber hehhe (DC), Rayman 2 (DC)] */
|
||||||
if (fmt.codec == 0x0000 && chunk_size == 0x12)
|
if (fmt.codec == 0x0000 && chunk_size == 0x12)
|
||||||
chunk_size += 0x02;
|
chunk_size += 0x02;
|
||||||
break;
|
break;
|
||||||
|
@ -924,6 +936,7 @@ static size_t get_ue4_msadpcm_interleave(STREAMFILE *sf, riff_fmt_chunk *fmt, of
|
||||||
return v2_interleave; /* favor newer games */
|
return v2_interleave; /* favor newer games */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* same but big endian, seen in the spec and in Kitchenette (PC) */
|
||||||
VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
riff_fmt_chunk fmt = {0};
|
riff_fmt_chunk fmt = {0};
|
||||||
|
|
51
Frameworks/vgmstream/vgmstream/src/meta/sadf.c
Normal file
51
Frameworks/vgmstream/vgmstream/src/meta/sadf.c
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#include "meta.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
|
/* sadf - from Procyon Studio audio driver games [Xenoblade Chronicles 2 (Switch)] (sfx) */
|
||||||
|
VGMSTREAM* init_vgmstream_sadf(STREAMFILE* sf) {
|
||||||
|
VGMSTREAM* vgmstream = NULL;
|
||||||
|
int channel_count, loop_flag;
|
||||||
|
off_t start_offset;
|
||||||
|
|
||||||
|
|
||||||
|
/* checks */
|
||||||
|
/* .sad: assumed (from older sadX formats)
|
||||||
|
* .nop: assumed (from streamed files)
|
||||||
|
* (extensionless): name in .xsp bigfiles */
|
||||||
|
if (!check_extensions(sf, "sad,nop,"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (read_32bitBE(0x00, sf) != 0x73616466) /* "sadf" */
|
||||||
|
goto fail;
|
||||||
|
if (read_32bitBE(0x08, sf) != 0x6470636D) /* "dpcm" ("opus" is used too, see opus.c, "ipcm" supposedly too) */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
channel_count = read_8bit(0x18, sf);
|
||||||
|
loop_flag = read_8bit(0x19, sf);
|
||||||
|
start_offset = read_32bitLE(0x1C, sf);
|
||||||
|
|
||||||
|
/* build the VGMSTREAM */
|
||||||
|
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
vgmstream->num_samples = read_32bitLE(0x28, sf);
|
||||||
|
vgmstream->sample_rate = read_32bitLE(0x24, sf);
|
||||||
|
if (loop_flag) {
|
||||||
|
vgmstream->loop_start_sample = read_32bitLE(0x2c, sf);
|
||||||
|
vgmstream->loop_end_sample = read_32bitLE(0x30, sf);
|
||||||
|
}
|
||||||
|
vgmstream->coding_type = coding_NGC_DSP;
|
||||||
|
vgmstream->layout_type = layout_interleave;
|
||||||
|
vgmstream->interleave_block_size = channel_count == 1 ? 0x8 : read_32bitLE(0x20, sf) / channel_count;
|
||||||
|
vgmstream->meta_type = meta_SADF;
|
||||||
|
|
||||||
|
dsp_read_coefs_le(vgmstream, sf, 0x80, 0x80);
|
||||||
|
|
||||||
|
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||||
|
goto fail;
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -1,32 +1,30 @@
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../util.h"
|
|
||||||
|
|
||||||
/* sadl - from DS games with Procyon Studio audio driver */
|
/* sadl - from DS games with Procyon Studio audio driver [Professor Layton (DS), Soma Bringer (DS)] */
|
||||||
VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) {
|
VGMSTREAM* init_vgmstream_sadl(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
|
int channel_count, loop_flag;
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
int loop_flag, channel_count;
|
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
if (!check_extensions(streamFile, "sad"))
|
if (!check_extensions(sf, "sad"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x7361646c) /* "sadl" */
|
if (read_32bitBE(0x00,sf) != 0x7361646c) /* "sadl" */
|
||||||
goto fail;
|
goto fail;
|
||||||
if (read_32bitLE(0x40,streamFile) != get_streamfile_size(streamFile))
|
if (read_32bitLE(0x40,sf) != get_streamfile_size(sf))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
loop_flag = read_8bit(0x31,sf);
|
||||||
loop_flag = read_8bit(0x31,streamFile);
|
channel_count = read_8bit(0x32,sf);
|
||||||
channel_count = read_8bit(0x32,streamFile);
|
|
||||||
start_offset = 0x100;
|
start_offset = 0x100;
|
||||||
|
|
||||||
/* 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;
|
||||||
|
|
||||||
switch (read_8bit(0x33,streamFile) & 6) {
|
switch (read_8bit(0x33,sf) & 6) {
|
||||||
case 4:
|
case 4:
|
||||||
vgmstream->sample_rate = 32728;
|
vgmstream->sample_rate = 32728;
|
||||||
break;
|
break;
|
||||||
|
@ -42,20 +40,20 @@ VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) {
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = 0x10;
|
vgmstream->interleave_block_size = 0x10;
|
||||||
|
|
||||||
switch(read_8bit(0x33,streamFile) & 0xf0) {
|
switch(read_8bit(0x33,sf) & 0xf0) {
|
||||||
case 0x70: /* Ni no Kuni (DS), Professor Layton and the Curious Village (DS), Soma Bringer (DS) */
|
case 0x70: /* Ni no Kuni (DS), Professor Layton and the Curious Village (DS), Soma Bringer (DS) */
|
||||||
vgmstream->coding_type = coding_IMA_int;
|
vgmstream->coding_type = coding_IMA_int;
|
||||||
|
|
||||||
vgmstream->num_samples = (read_32bitLE(0x40,streamFile)-start_offset)/channel_count*2;
|
vgmstream->num_samples = (read_32bitLE(0x40,sf)-start_offset)/channel_count*2;
|
||||||
vgmstream->loop_start_sample = (read_32bitLE(0x54,streamFile)-start_offset)/channel_count*2;
|
vgmstream->loop_start_sample = (read_32bitLE(0x54,sf)-start_offset)/channel_count*2;
|
||||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xb0: /* Soma Bringer (DS), Rekishi Taisen Gettenka (DS) */
|
case 0xb0: /* Soma Bringer (DS), Rekishi Taisen Gettenka (DS) */
|
||||||
vgmstream->coding_type = coding_NDS_PROCYON;
|
vgmstream->coding_type = coding_NDS_PROCYON;
|
||||||
|
|
||||||
vgmstream->num_samples = (read_32bitLE(0x40,streamFile)-start_offset)/channel_count/16*30;
|
vgmstream->num_samples = (read_32bitLE(0x40,sf)-start_offset)/channel_count/16*30;
|
||||||
vgmstream->loop_start_sample = (read_32bitLE(0x54,streamFile)-start_offset)/channel_count/16*30;
|
vgmstream->loop_start_sample = (read_32bitLE(0x54,sf)-start_offset)/channel_count/16*30;
|
||||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -63,7 +61,7 @@ VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||||
goto fail;
|
goto fail;
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
|
@ -1473,6 +1473,7 @@ static STREAMFILE * setup_bao_streamfile(ubi_bao_header *bao, STREAMFILE *stream
|
||||||
if (!new_streamFile) goto fail;
|
if (!new_streamFile) goto fail;
|
||||||
stream_segments[0] = new_streamFile;
|
stream_segments[0] = new_streamFile;
|
||||||
|
|
||||||
|
if (bao->stream_size - bao->prefetch_size != 0) {
|
||||||
new_streamFile = open_atomic_bao(bao->cfg.file_type, bao->stream_id, 1, streamFile);
|
new_streamFile = open_atomic_bao(bao->cfg.file_type, bao->stream_id, 1, streamFile);
|
||||||
if (!new_streamFile) goto fail;
|
if (!new_streamFile) goto fail;
|
||||||
stream_segments[1] = new_streamFile;
|
stream_segments[1] = new_streamFile;
|
||||||
|
@ -1487,6 +1488,12 @@ static STREAMFILE * setup_bao_streamfile(ubi_bao_header *bao, STREAMFILE *stream
|
||||||
stream_segments[0] = NULL;
|
stream_segments[0] = NULL;
|
||||||
stream_segments[1] = NULL;
|
stream_segments[1] = NULL;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
/* weird but happens, streamed chunk is empty in this case */
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
stream_segments[0] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
new_streamFile = open_atomic_bao(bao->cfg.file_type, bao->stream_id, bao->is_external, streamFile);
|
new_streamFile = open_atomic_bao(bao->cfg.file_type, bao->stream_id, bao->is_external, streamFile);
|
||||||
if (!new_streamFile) goto fail;
|
if (!new_streamFile) goto fail;
|
||||||
|
@ -1507,6 +1514,7 @@ static STREAMFILE * setup_bao_streamfile(ubi_bao_header *bao, STREAMFILE *stream
|
||||||
if (!new_streamFile) goto fail;
|
if (!new_streamFile) goto fail;
|
||||||
stream_segments[0] = new_streamFile;
|
stream_segments[0] = new_streamFile;
|
||||||
|
|
||||||
|
if (bao->stream_size - bao->prefetch_size != 0) {
|
||||||
new_streamFile = open_streamfile_by_filename(streamFile, bao->resource_name);
|
new_streamFile = open_streamfile_by_filename(streamFile, bao->resource_name);
|
||||||
if (!new_streamFile) { VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name); goto fail; }
|
if (!new_streamFile) { VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name); goto fail; }
|
||||||
stream_segments[1] = new_streamFile;
|
stream_segments[1] = new_streamFile;
|
||||||
|
@ -1522,6 +1530,12 @@ static STREAMFILE * setup_bao_streamfile(ubi_bao_header *bao, STREAMFILE *stream
|
||||||
stream_segments[0] = NULL;
|
stream_segments[0] = NULL;
|
||||||
stream_segments[1] = NULL;
|
stream_segments[1] = NULL;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
/* weird but happens, streamed chunk is empty in this case */
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
stream_segments[0] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (bao->is_external) {
|
else if (bao->is_external) {
|
||||||
new_streamFile = open_streamfile_by_filename(streamFile, bao->resource_name);
|
new_streamFile = open_streamfile_by_filename(streamFile, bao->resource_name);
|
||||||
if (!new_streamFile) { VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name); goto fail; }
|
if (!new_streamFile) { VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name); goto fail; }
|
||||||
|
@ -1721,6 +1735,7 @@ static int config_bao_version(ubi_bao_header * bao, STREAMFILE *streamFile) {
|
||||||
case 0x001F0008: /* Rayman Raving Rabbids: TV Party (Wii)-package */
|
case 0x001F0008: /* Rayman Raving Rabbids: TV Party (Wii)-package */
|
||||||
case 0x001F0010: /* Prince of Persia 2008 (PC/PS3/X360)-atomic-forge, Far Cry 2 (PS3)-atomic-dunia? */
|
case 0x001F0010: /* Prince of Persia 2008 (PC/PS3/X360)-atomic-forge, Far Cry 2 (PS3)-atomic-dunia? */
|
||||||
case 0x001F0011: /* Naruto: The Broken Bond (X360)-package */
|
case 0x001F0011: /* Naruto: The Broken Bond (X360)-package */
|
||||||
|
case 0x0021000C: /* Splinter Cell: Conviction (E3 2009 Demo)(X360)-package */
|
||||||
case 0x0022000D: /* Just Dance (Wii)-package */
|
case 0x0022000D: /* Just Dance (Wii)-package */
|
||||||
case 0x0022001B: /* Prince of Persia: The Forgotten Sands (Wii)-package */
|
case 0x0022001B: /* Prince of Persia: The Forgotten Sands (Wii)-package */
|
||||||
config_bao_entry(bao, 0xA4, 0x28); /* PC/Wii: 0xA8 */
|
config_bao_entry(bao, 0xA4, 0x28); /* PC/Wii: 0xA8 */
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,37 +24,37 @@ typedef struct {
|
||||||
off_t stream_offset;
|
off_t stream_offset;
|
||||||
} xvag_header;
|
} xvag_header;
|
||||||
|
|
||||||
static int init_xvag_atrac9(STREAMFILE *streamFile, VGMSTREAM* vgmstream, xvag_header * xvag, off_t chunk_offset);
|
static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header * xvag, off_t chunk_offset);
|
||||||
static layered_layout_data* build_layered_xvag(STREAMFILE *streamFile, xvag_header * xvag, off_t chunk_offset, off_t start_offset);
|
static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header * xvag, off_t chunk_offset, off_t start_offset);
|
||||||
|
|
||||||
/* XVAG - Sony's Scream Tool/Stream Creator format (God of War III, Ratchet & Clank Future, The Last of Us, Uncharted) */
|
/* XVAG - Sony's Scream Tool/Stream Creator format (God of War III, Ratchet & Clank Future, The Last of Us, Uncharted) */
|
||||||
VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
VGMSTREAM* init_vgmstream_xvag(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
STREAMFILE* temp_streamFile = NULL;
|
STREAMFILE* temp_sf = NULL;
|
||||||
xvag_header xvag = {0};
|
xvag_header xvag = {0};
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||||
off_t start_offset, chunk_offset, first_offset = 0x20;
|
off_t start_offset, chunk_offset, first_offset = 0x20;
|
||||||
size_t chunk_size;
|
size_t chunk_size;
|
||||||
int total_subsongs = 0, target_subsong = streamFile->stream_index;
|
int total_subsongs = 0, target_subsong = sf->stream_index;
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
/* .xvag: standard
|
/* .xvag: standard
|
||||||
* (extensionless): The Last Of Us (PS3) speech files */
|
* (extensionless): The Last Of Us (PS3) speech files */
|
||||||
if (!check_extensions(streamFile,"xvag,"))
|
if (!check_extensions(sf,"xvag,"))
|
||||||
goto fail;
|
goto fail;
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x58564147) /* "XVAG" */
|
if (read_32bitBE(0x00,sf) != 0x58564147) /* "XVAG" */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* endian flag (XVAGs of the same game can use BE or LE, usually when reusing from other platforms) */
|
/* endian flag (XVAGs of the same game can use BE or LE, usually when reusing from other platforms) */
|
||||||
xvag.big_endian = read_8bit(0x08,streamFile) & 0x01;
|
xvag.big_endian = read_8bit(0x08,sf) & 0x01;
|
||||||
if (xvag.big_endian) {
|
if (xvag.big_endian) {
|
||||||
read_32bit = read_32bitBE;
|
read_32bit = read_32bitBE;
|
||||||
} else {
|
} else {
|
||||||
read_32bit = read_32bitLE;
|
read_32bit = read_32bitLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
start_offset = read_32bit(0x04,streamFile);
|
start_offset = read_32bit(0x04,sf);
|
||||||
/* 0x08: flags? (&0x01=big endian, 0x02=?, 0x06=full RIFF AT9?)
|
/* 0x08: flags? (&0x01=big endian, 0x02=?, 0x06=full RIFF AT9?)
|
||||||
* 0x09: flags2? (0x00/0x01/0x04, speaker mode?)
|
* 0x09: flags2? (0x00/0x01/0x04, speaker mode?)
|
||||||
* 0x0a: always 0?
|
* 0x0a: always 0?
|
||||||
|
@ -62,24 +62,24 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
|
|
||||||
/* "fmat": base format (always first) */
|
/* "fmat": base format (always first) */
|
||||||
if (!find_chunk(streamFile, 0x666D6174,first_offset,0, &chunk_offset,&chunk_size, xvag.big_endian, 1)) /*"fmat"*/
|
if (!find_chunk(sf, 0x666D6174,first_offset,0, &chunk_offset,&chunk_size, xvag.big_endian, 1)) /*"fmat"*/
|
||||||
goto fail;
|
goto fail;
|
||||||
xvag.channels = read_32bit(chunk_offset+0x00,streamFile);
|
xvag.channels = read_32bit(chunk_offset+0x00,sf);
|
||||||
xvag.codec = read_32bit(chunk_offset+0x04,streamFile);
|
xvag.codec = read_32bit(chunk_offset+0x04,sf);
|
||||||
xvag.num_samples = read_32bit(chunk_offset+0x08,streamFile);
|
xvag.num_samples = read_32bit(chunk_offset+0x08,sf);
|
||||||
/* 0x0c: samples again? */
|
/* 0x0c: samples again? */
|
||||||
VGM_ASSERT(xvag.num_samples != read_32bit(chunk_offset+0x0c,streamFile), "XVAG: num_samples values don't match\n");
|
VGM_ASSERT(xvag.num_samples != read_32bit(chunk_offset+0x0c,sf), "XVAG: num_samples values don't match\n");
|
||||||
|
|
||||||
xvag.factor = read_32bit(chunk_offset+0x10,streamFile); /* for interleave */
|
xvag.factor = read_32bit(chunk_offset+0x10,sf); /* for interleave */
|
||||||
xvag.sample_rate = read_32bit(chunk_offset+0x14,streamFile);
|
xvag.sample_rate = read_32bit(chunk_offset+0x14,sf);
|
||||||
xvag.data_size = read_32bit(chunk_offset+0x18,streamFile); /* not always accurate */
|
xvag.data_size = read_32bit(chunk_offset+0x18,sf); /* not always accurate */
|
||||||
|
|
||||||
/* extra data, seen in versions 0x61+ */
|
/* extra data, seen in versions 0x61+ */
|
||||||
if (chunk_size > 0x1c) {
|
if (chunk_size > 0x1c) {
|
||||||
/* number of interleaved subsongs */
|
/* number of interleaved subsongs */
|
||||||
xvag.subsongs = read_32bit(chunk_offset+0x1c,streamFile);
|
xvag.subsongs = read_32bit(chunk_offset+0x1c,sf);
|
||||||
/* number of interleaved layers (layers * channels_per_layer = channels) */
|
/* number of interleaved layers (layers * channels_per_layer = channels) */
|
||||||
xvag.layers = read_32bit(chunk_offset+0x20,streamFile);
|
xvag.layers = read_32bit(chunk_offset+0x20,sf);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
xvag.subsongs = 1;
|
xvag.subsongs = 1;
|
||||||
|
@ -99,9 +99,9 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
/* XVAG has no looping, but some PS3 PS-ADPCM seems to do full loops (without data flags) */
|
/* XVAG has no looping, but some PS3 PS-ADPCM seems to do full loops (without data flags) */
|
||||||
if (xvag.codec == 0x06 && xvag.subsongs == 1) {
|
if (xvag.codec == 0x06 && xvag.subsongs == 1) {
|
||||||
size_t file_size = get_streamfile_size(streamFile);
|
size_t file_size = get_streamfile_size(sf);
|
||||||
/* simply test if last frame is not empty = may loop */
|
/* simply test if last frame is not empty = may loop */
|
||||||
xvag.loop_flag = (read_8bit(file_size - 0x01, streamFile) != 0);
|
xvag.loop_flag = (read_8bit(file_size - 0x01, sf) != 0);
|
||||||
xvag.loop_start = 0;
|
xvag.loop_start = 0;
|
||||||
xvag.loop_end = ps_bytes_to_samples(file_size - start_offset, xvag.channels);
|
xvag.loop_end = ps_bytes_to_samples(file_size - start_offset, xvag.channels);
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
if (xvag.layers > 1 && !(xvag.layers*1 == vgmstream->channels || xvag.layers*2 == vgmstream->channels)) goto fail;
|
if (xvag.layers > 1 && !(xvag.layers*1 == vgmstream->channels || xvag.layers*2 == vgmstream->channels)) goto fail;
|
||||||
|
|
||||||
/* "mpin": mpeg info */
|
/* "mpin": mpeg info */
|
||||||
if (!find_chunk(streamFile, 0x6D70696E,first_offset,0, &chunk_offset,NULL, xvag.big_endian, 1)) /*"mpin"*/
|
if (!find_chunk(sf, 0x6D70696E,first_offset,0, &chunk_offset,NULL, xvag.big_endian, 1)) /*"mpin"*/
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* all layers/subsongs share the same config; not very useful but for posterity:
|
/* all layers/subsongs share the same config; not very useful but for posterity:
|
||||||
|
@ -182,18 +182,18 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
* - 0x34: data size
|
* - 0x34: data size
|
||||||
* (rest is padding)
|
* (rest is padding)
|
||||||
* */
|
* */
|
||||||
cfg.chunk_size = read_32bit(chunk_offset+0x1c,streamFile);
|
cfg.chunk_size = read_32bit(chunk_offset+0x1c,sf);
|
||||||
cfg.skip_samples = read_32bit(chunk_offset+0x20,streamFile);
|
cfg.skip_samples = read_32bit(chunk_offset+0x20,sf);
|
||||||
cfg.interleave = cfg.chunk_size * xvag.factor;
|
cfg.interleave = cfg.chunk_size * xvag.factor;
|
||||||
|
|
||||||
vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_XVAG, &cfg);
|
vgmstream->codec_data = init_mpeg_custom(sf, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_XVAG, &cfg);
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
/* interleaved subsongs, rarely [Sly Cooper: Thieves in Time (PS3)] */
|
/* interleaved subsongs, rarely [Sly Cooper: Thieves in Time (PS3)] */
|
||||||
if (xvag.subsongs > 1) {
|
if (xvag.subsongs > 1) {
|
||||||
temp_streamFile = setup_xvag_streamfile(streamFile, start_offset, cfg.interleave,cfg.chunk_size, (target_subsong-1), total_subsongs);
|
temp_sf = setup_xvag_streamfile(sf, start_offset, cfg.interleave,cfg.chunk_size, (target_subsong-1), total_subsongs);
|
||||||
if (!temp_streamFile) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
start_offset = 0;
|
start_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,13 +207,13 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
/* "a9in": ATRAC9 info */
|
/* "a9in": ATRAC9 info */
|
||||||
/* 0x00: frame size, 0x04: samples per frame, 0x0c: fact num_samples (no change), 0x10: encoder delay1 */
|
/* 0x00: frame size, 0x04: samples per frame, 0x0c: fact num_samples (no change), 0x10: encoder delay1 */
|
||||||
if (!find_chunk(streamFile, 0x6139696E,first_offset,0, &chunk_offset,NULL, xvag.big_endian, 1)) /*"a9in"*/
|
if (!find_chunk(sf, 0x6139696E,first_offset,0, &chunk_offset,NULL, xvag.big_endian, 1)) /*"a9in"*/
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (xvag.layers > 1) {
|
if (xvag.layers > 1) {
|
||||||
/* some Vita/PS4 multichannel [flower (Vita), Uncharted Collection (PS4)]. PS4 ATRAC9 also
|
/* some Vita/PS4 multichannel [flower (Vita), Uncharted Collection (PS4)]. PS4 ATRAC9 also
|
||||||
* does single-stream >2ch, but this can do configs ATRAC9 can't, like 5ch/14ch/etc */
|
* does single-stream >2ch, but this can do configs ATRAC9 can't, like 5ch/14ch/etc */
|
||||||
vgmstream->layout_data = build_layered_xvag(streamFile, &xvag, chunk_offset, start_offset);
|
vgmstream->layout_data = build_layered_xvag(sf, &xvag, chunk_offset, start_offset);
|
||||||
if (!vgmstream->layout_data) goto fail;
|
if (!vgmstream->layout_data) goto fail;
|
||||||
vgmstream->coding_type = coding_ATRAC9;
|
vgmstream->coding_type = coding_ATRAC9;
|
||||||
vgmstream->layout_type = layout_layered;
|
vgmstream->layout_type = layout_layered;
|
||||||
|
@ -222,12 +222,12 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* interleaved subsongs (section layers) */
|
/* interleaved subsongs (section layers) */
|
||||||
size_t frame_size = read_32bit(chunk_offset+0x00,streamFile);
|
size_t frame_size = read_32bit(chunk_offset+0x00,sf);
|
||||||
|
|
||||||
if (!init_xvag_atrac9(streamFile, vgmstream, &xvag, chunk_offset))
|
if (!init_xvag_atrac9(sf, vgmstream, &xvag, chunk_offset))
|
||||||
goto fail;
|
goto fail;
|
||||||
temp_streamFile = setup_xvag_streamfile(streamFile, start_offset, frame_size*xvag.factor,frame_size, (target_subsong-1), total_subsongs);
|
temp_sf = setup_xvag_streamfile(sf, start_offset, frame_size*xvag.factor,frame_size, (target_subsong-1), total_subsongs);
|
||||||
if (!temp_streamFile) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
start_offset = 0;
|
start_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,25 +240,25 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!vgmstream_open_stream(vgmstream,temp_streamFile ? temp_streamFile : streamFile,start_offset))
|
if (!vgmstream_open_stream(vgmstream,temp_sf ? temp_sf : sf,start_offset))
|
||||||
goto fail;
|
goto fail;
|
||||||
close_streamfile(temp_streamFile);
|
close_streamfile(temp_sf);
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
close_streamfile(temp_streamFile);
|
close_streamfile(temp_sf);
|
||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VGM_USE_ATRAC9
|
#ifdef VGM_USE_ATRAC9
|
||||||
static int init_xvag_atrac9(STREAMFILE *streamFile, VGMSTREAM* vgmstream, xvag_header * xvag, off_t chunk_offset) {
|
static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header * xvag, off_t chunk_offset) {
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = xvag->big_endian ? read_32bitBE : read_32bitLE;
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = xvag->big_endian ? read_32bitBE : read_32bitLE;
|
||||||
atrac9_config cfg = {0};
|
atrac9_config cfg = {0};
|
||||||
|
|
||||||
cfg.channels = vgmstream->channels;
|
cfg.channels = vgmstream->channels;
|
||||||
cfg.config_data = read_32bitBE(chunk_offset+0x08,streamFile);
|
cfg.config_data = read_32bitBE(chunk_offset+0x08,sf);
|
||||||
cfg.encoder_delay = read_32bit(chunk_offset+0x14,streamFile);
|
cfg.encoder_delay = read_32bit(chunk_offset+0x14,sf);
|
||||||
|
|
||||||
vgmstream->codec_data = init_atrac9(&cfg);
|
vgmstream->codec_data = init_atrac9(&cfg);
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
|
@ -271,9 +271,9 @@ fail:
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static layered_layout_data* build_layered_xvag(STREAMFILE *streamFile, xvag_header * xvag, off_t chunk_offset, off_t start_offset) {
|
static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header * xvag, off_t chunk_offset, off_t start_offset) {
|
||||||
layered_layout_data* data = NULL;
|
layered_layout_data* data = NULL;
|
||||||
STREAMFILE* temp_streamFile = NULL;
|
STREAMFILE* temp_sf = NULL;
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = xvag->big_endian ? read_32bitBE : read_32bitLE;
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = xvag->big_endian ? read_32bitBE : read_32bitLE;
|
||||||
int i, layers = xvag->layers;
|
int i, layers = xvag->layers;
|
||||||
|
|
||||||
|
@ -296,12 +296,12 @@ static layered_layout_data* build_layered_xvag(STREAMFILE *streamFile, xvag_head
|
||||||
switch(xvag->codec) {
|
switch(xvag->codec) {
|
||||||
#ifdef VGM_USE_ATRAC9
|
#ifdef VGM_USE_ATRAC9
|
||||||
case 0x09: {
|
case 0x09: {
|
||||||
size_t frame_size = read_32bit(chunk_offset+0x00,streamFile);
|
size_t frame_size = read_32bit(chunk_offset+0x00,sf);
|
||||||
|
|
||||||
if (!init_xvag_atrac9(streamFile, data->layers[i], xvag, chunk_offset))
|
if (!init_xvag_atrac9(sf, data->layers[i], xvag, chunk_offset))
|
||||||
goto fail;
|
goto fail;
|
||||||
temp_streamFile = setup_xvag_streamfile(streamFile, start_offset, frame_size*xvag->factor,frame_size, i, layers);
|
temp_sf = setup_xvag_streamfile(sf, start_offset, frame_size*xvag->factor,frame_size, i, layers);
|
||||||
if (!temp_streamFile) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -309,9 +309,11 @@ static layered_layout_data* build_layered_xvag(STREAMFILE *streamFile, xvag_head
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !vgmstream_open_stream(data->layers[i], temp_streamFile, 0x00) )
|
if (!vgmstream_open_stream(data->layers[i], temp_sf, 0x00))
|
||||||
goto fail;
|
goto fail;
|
||||||
close_streamfile(temp_streamFile);
|
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
temp_sf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup layered VGMSTREAMs */
|
/* setup layered VGMSTREAMs */
|
||||||
|
@ -320,7 +322,7 @@ static layered_layout_data* build_layered_xvag(STREAMFILE *streamFile, xvag_head
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
close_streamfile(temp_streamFile);
|
close_streamfile(temp_sf);
|
||||||
free_layout_layered(data);
|
free_layout_layered(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -680,9 +680,12 @@ STREAMFILE* open_fakename_streamfile(STREAMFILE *streamfile, const char *fakenam
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fakeext) {
|
if (fakeext) {
|
||||||
char * ext = strrchr(this_sf->fakename,'.');
|
char* ext = strrchr(this_sf->fakename,'.');
|
||||||
if (ext != NULL)
|
if (ext != NULL) {
|
||||||
ext[1] = '\0'; /* truncate past dot */
|
ext[1] = '\0'; /* truncate past dot */
|
||||||
|
} else {
|
||||||
|
strcat(this_sf->fakename, "."); /* no extension = add dot */
|
||||||
|
}
|
||||||
strcat(this_sf->fakename, fakeext);
|
strcat(this_sf->fakename, fakeext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1187,6 +1190,9 @@ static int find_chunk_internal(STREAMFILE *streamFile, uint32_t chunk_id, off_t
|
||||||
uint32_t chunk_size = read_32bit_size(offset + 0x04,streamFile);
|
uint32_t chunk_size = read_32bit_size(offset + 0x04,streamFile);
|
||||||
//;VGM_LOG("CHUNK: type=%x, size=%x at %lx\n", chunk_type, chunk_size, offset);
|
//;VGM_LOG("CHUNK: type=%x, size=%x at %lx\n", chunk_type, chunk_size, offset);
|
||||||
|
|
||||||
|
if (chunk_type == 0xFFFFFFFF || chunk_size == 0xFFFFFFFF)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (chunk_type == chunk_id) {
|
if (chunk_type == chunk_id) {
|
||||||
if (out_chunk_offset) *out_chunk_offset = offset + 0x08;
|
if (out_chunk_offset) *out_chunk_offset = offset + 0x08;
|
||||||
if (out_chunk_size) *out_chunk_size = chunk_size;
|
if (out_chunk_size) *out_chunk_size = chunk_size;
|
||||||
|
|
|
@ -61,8 +61,6 @@ void interleave_stereo(sample_t * buffer, int32_t sample_count) {
|
||||||
else
|
else
|
||||||
belongs = (tomove-sample_count)*2+1;
|
belongs = (tomove-sample_count)*2+1;
|
||||||
|
|
||||||
printf("move %d to %d\n",tomove,belongs);
|
|
||||||
|
|
||||||
temp = buffer[belongs];
|
temp = buffer[belongs];
|
||||||
buffer[belongs] = moving;
|
buffer[belongs] = moving;
|
||||||
moving = temp;
|
moving = temp;
|
||||||
|
@ -100,6 +98,14 @@ void put_32bitBE(uint8_t * buf, int32_t i) {
|
||||||
buf[3] = (uint8_t)(i & 0xFF);
|
buf[3] = (uint8_t)(i & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int round10(int val) {
|
||||||
|
int round_val = val % 10;
|
||||||
|
if (round_val < 5) /* half-down rounding */
|
||||||
|
return val - round_val;
|
||||||
|
else
|
||||||
|
return val + (10 - round_val);
|
||||||
|
}
|
||||||
|
|
||||||
void swap_samples_le(sample_t *buf, int count) {
|
void swap_samples_le(sample_t *buf, int count) {
|
||||||
/* Windows can't be BE... I think */
|
/* Windows can't be BE... I think */
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#ifndef _UTIL_H
|
#ifndef _UTIL_H
|
||||||
#define _UTIL_H
|
#define _UTIL_H
|
||||||
|
|
||||||
|
/* very common functions, so static inline in .h is useful to avoid some call overhead */
|
||||||
|
|
||||||
/* host endian independent multi-byte integer reading */
|
/* host endian independent multi-byte integer reading */
|
||||||
|
|
||||||
static inline int16_t get_16bitBE(uint8_t * p) {
|
static inline int16_t get_16bitBE(uint8_t * p) {
|
||||||
|
@ -91,13 +93,9 @@ static inline int clamp16(int32_t val) {
|
||||||
else return val;
|
else return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int round10(int val) {
|
/* less common functions, no need to inline */
|
||||||
int round_val = val % 10;
|
|
||||||
if (round_val < 5) /* half-down rounding */
|
int round10(int val);
|
||||||
return val - round_val;
|
|
||||||
else
|
|
||||||
return val + (10 - round_val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return a file's extension (a pointer to the first character of the
|
/* return a file's extension (a pointer to the first character of the
|
||||||
* extension in the original filename or the ending null byte if no extension */
|
* extension in the original filename or the ending null byte if no extension */
|
||||||
|
|
|
@ -351,6 +351,9 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||||
init_vgmstream_ubi_sb,
|
init_vgmstream_ubi_sb,
|
||||||
init_vgmstream_ubi_sm,
|
init_vgmstream_ubi_sm,
|
||||||
init_vgmstream_ubi_bnm,
|
init_vgmstream_ubi_bnm,
|
||||||
|
init_vgmstream_ubi_bnm_ps2,
|
||||||
|
init_vgmstream_ubi_dat,
|
||||||
|
init_vgmstream_ubi_blk,
|
||||||
init_vgmstream_ezw,
|
init_vgmstream_ezw,
|
||||||
init_vgmstream_vxn,
|
init_vgmstream_vxn,
|
||||||
init_vgmstream_ea_snr_sns,
|
init_vgmstream_ea_snr_sns,
|
||||||
|
@ -494,6 +497,10 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||||
init_vgmstream_bkhd_fx,
|
init_vgmstream_bkhd_fx,
|
||||||
init_vgmstream_diva,
|
init_vgmstream_diva,
|
||||||
init_vgmstream_imuse,
|
init_vgmstream_imuse,
|
||||||
|
init_vgmstream_ktsr,
|
||||||
|
init_vgmstream_mups,
|
||||||
|
init_vgmstream_kat,
|
||||||
|
init_vgmstream_pcm_success,
|
||||||
|
|
||||||
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
|
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
|
||||||
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
|
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
|
||||||
|
|
|
@ -317,7 +317,6 @@ typedef enum {
|
||||||
meta_DSP_WII_WSD, /* Phantom Brave (WII) */
|
meta_DSP_WII_WSD, /* Phantom Brave (WII) */
|
||||||
meta_WII_NDP, /* Vertigo (Wii) */
|
meta_WII_NDP, /* Vertigo (Wii) */
|
||||||
meta_DSP_YGO, /* Konami: Yu-Gi-Oh! The Falsebound Kingdom (NGC), Hikaru no Go 3 (NGC) */
|
meta_DSP_YGO, /* Konami: Yu-Gi-Oh! The Falsebound Kingdom (NGC), Hikaru no Go 3 (NGC) */
|
||||||
meta_DSP_SADF, /* Procyon Studio SADF - Xenoblade Chronicles 2 (Switch) */
|
|
||||||
|
|
||||||
meta_STRM, /* Nintendo STRM */
|
meta_STRM, /* Nintendo STRM */
|
||||||
meta_RSTM, /* Nintendo RSTM (Revolution Stream, similar to STRM) */
|
meta_RSTM, /* Nintendo RSTM (Revolution Stream, similar to STRM) */
|
||||||
|
@ -430,7 +429,7 @@ typedef enum {
|
||||||
meta_NGC_SSM, /* Golden Gashbell Full Power */
|
meta_NGC_SSM, /* Golden Gashbell Full Power */
|
||||||
meta_PS2_JOE, /* Wall-E / Pixar games */
|
meta_PS2_JOE, /* Wall-E / Pixar games */
|
||||||
meta_NGC_YMF, /* WWE WrestleMania X8 */
|
meta_NGC_YMF, /* WWE WrestleMania X8 */
|
||||||
meta_SADL, /* .sad */
|
meta_SADL,
|
||||||
meta_PS2_CCC, /* Tokyo Xtreme Racer DRIFT 2 */
|
meta_PS2_CCC, /* Tokyo Xtreme Racer DRIFT 2 */
|
||||||
meta_FAG, /* Jackie Chan - Stuntmaster */
|
meta_FAG, /* Jackie Chan - Stuntmaster */
|
||||||
meta_PS2_MIHB, /* Merged MIH+MIB */
|
meta_PS2_MIHB, /* Merged MIH+MIB */
|
||||||
|
@ -691,6 +690,7 @@ typedef enum {
|
||||||
meta_WV2, /* Slave Zero (PC) */
|
meta_WV2, /* Slave Zero (PC) */
|
||||||
meta_XAU_KONAMI, /* Yu-Gi-Oh - The Dawn of Destiny (Xbox) */
|
meta_XAU_KONAMI, /* Yu-Gi-Oh - The Dawn of Destiny (Xbox) */
|
||||||
meta_DERF, /* Stupid Invaders (PC) */
|
meta_DERF, /* Stupid Invaders (PC) */
|
||||||
|
meta_SADF,
|
||||||
meta_UTK,
|
meta_UTK,
|
||||||
meta_NXA,
|
meta_NXA,
|
||||||
meta_ADPCM_CAPCOM,
|
meta_ADPCM_CAPCOM,
|
||||||
|
@ -739,6 +739,9 @@ typedef enum {
|
||||||
meta_WWISE_FX,
|
meta_WWISE_FX,
|
||||||
meta_DIVA,
|
meta_DIVA,
|
||||||
meta_IMUSE,
|
meta_IMUSE,
|
||||||
|
meta_KTSR,
|
||||||
|
meta_KAT,
|
||||||
|
meta_PCM_SUCCESS,
|
||||||
} meta_t;
|
} meta_t;
|
||||||
|
|
||||||
/* standard WAVEFORMATEXTENSIBLE speaker positions */
|
/* standard WAVEFORMATEXTENSIBLE speaker positions */
|
||||||
|
|
Loading…
Reference in a new issue