Updated VGMStream to r1050-2323-g2e1739e6

CQTexperiment
Christopher Snowhill 2019-06-20 20:43:24 -07:00
parent a6b0e0e8ae
commit 412a094b94
124 changed files with 9592 additions and 3227 deletions

View File

@ -206,7 +206,6 @@
834FE10F215C79ED000A5D3D /* sdf.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0E6215C79EC000A5D3D /* sdf.c */; };
834FE110215C79ED000A5D3D /* msv.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0E7215C79EC000A5D3D /* msv.c */; };
834FE111215C79ED000A5D3D /* ck.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0E8215C79EC000A5D3D /* ck.c */; };
8350270D1ED119D200C25929 /* ps3_mta2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8350270C1ED119D200C25929 /* ps3_mta2.c */; };
835027131ED119E000C25929 /* mta2_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 835027121ED119E000C25929 /* mta2_decoder.c */; };
8350C0551E071881009E0A93 /* xma.c in Sources */ = {isa = PBXBuildFile; fileRef = 8350C0541E071881009E0A93 /* xma.c */; };
8350C05A1E071990009E0A93 /* ps2_svag_snk.c in Sources */ = {isa = PBXBuildFile; fileRef = 8350C0591E071990009E0A93 /* ps2_svag_snk.c */; };
@ -241,7 +240,6 @@
836F6F3A18BDC2190095E648 /* sdx2_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DFC18BDC2180095E648 /* sdx2_decoder.c */; };
836F6F3B18BDC2190095E648 /* ws_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DFD18BDC2180095E648 /* ws_decoder.c */; };
836F6F3C18BDC2190095E648 /* xa_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DFE18BDC2180095E648 /* xa_decoder.c */; };
836F6F3E18BDC2190095E648 /* aix_layout.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0118BDC2180095E648 /* aix_layout.c */; };
836F6F4118BDC2190095E648 /* blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0418BDC2180095E648 /* blocked.c */; };
836F6F4A18BDC2190095E648 /* interleave.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E0D18BDC2180095E648 /* interleave.c */; };
836F6F4D18BDC2190095E648 /* layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 836F6E1018BDC2180095E648 /* layout.h */; };
@ -264,7 +262,6 @@
836F6F7718BDC2190095E648 /* capdsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E3B18BDC2180095E648 /* capdsp.c */; };
836F6F7818BDC2190095E648 /* Cstr.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E3C18BDC2180095E648 /* Cstr.c */; };
836F6F7918BDC2190095E648 /* dc_asd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E3D18BDC2180095E648 /* dc_asd.c */; };
836F6F7A18BDC2190095E648 /* dc_dcsw_dcs.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E3E18BDC2180095E648 /* dc_dcsw_dcs.c */; };
836F6F7B18BDC2190095E648 /* dc_idvi.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E3F18BDC2180095E648 /* dc_idvi.c */; };
836F6F7C18BDC2190095E648 /* dc_kcey.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4018BDC2180095E648 /* dc_kcey.c */; };
836F6F7D18BDC2190095E648 /* dc_str.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4118BDC2180095E648 /* dc_str.c */; };
@ -346,7 +343,6 @@
836F6FDA18BDC2190095E648 /* ps2_hgc1.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9E18BDC2180095E648 /* ps2_hgc1.c */; };
836F6FDB18BDC2190095E648 /* ps2_hsf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9F18BDC2180095E648 /* ps2_hsf.c */; };
836F6FDC18BDC2190095E648 /* ps2_iab.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA018BDC2180095E648 /* ps2_iab.c */; };
836F6FDD18BDC2190095E648 /* ps2_ikm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA118BDC2180095E648 /* ps2_ikm.c */; };
836F6FDE18BDC2190095E648 /* ps2_ild.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA218BDC2180095E648 /* ps2_ild.c */; };
836F6FDF18BDC2190095E648 /* ps2_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA318BDC2180095E648 /* ps2_int.c */; };
836F6FE018BDC2190095E648 /* ps2_joe.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA418BDC2180095E648 /* ps2_joe.c */; };
@ -358,8 +354,6 @@
836F6FE818BDC2190095E648 /* ps2_mic.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EAC18BDC2180095E648 /* ps2_mic.c */; };
836F6FE918BDC2190095E648 /* ps2_mihb.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EAD18BDC2180095E648 /* ps2_mihb.c */; };
836F6FEA18BDC2190095E648 /* ps2_msa.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EAE18BDC2180095E648 /* ps2_msa.c */; };
836F6FEC18BDC2190095E648 /* ps2_mtaf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB018BDC2180095E648 /* ps2_mtaf.c */; };
836F6FED18BDC2190095E648 /* ps2_npsf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB118BDC2180095E648 /* ps2_npsf.c */; };
836F6FEE18BDC2190095E648 /* ps2_p2bt.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB218BDC2180095E648 /* ps2_p2bt.c */; };
836F6FEF18BDC2190095E648 /* ps2_pnb.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB318BDC2180095E648 /* ps2_pnb.c */; };
836F6FF218BDC2190095E648 /* ps2_rnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB618BDC2180095E648 /* ps2_rnd.c */; };
@ -388,7 +382,6 @@
836F700F18BDC2190095E648 /* ps2_xa30.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED318BDC2190095E648 /* ps2_xa30.c */; };
836F701118BDC2190095E648 /* ps3_cps.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED518BDC2190095E648 /* ps3_cps.c */; };
836F701218BDC2190095E648 /* ps3_ivag.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED618BDC2190095E648 /* ps3_ivag.c */; };
836F701418BDC2190095E648 /* ps3_msf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED818BDC2190095E648 /* ps3_msf.c */; };
836F701518BDC2190095E648 /* ps3_past.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED918BDC2190095E648 /* ps3_past.c */; };
836F701B18BDC2190095E648 /* psx_gms.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EDF18BDC2190095E648 /* psx_gms.c */; };
836F701D18BDC2190095E648 /* raw.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EE118BDC2190095E648 /* raw.c */; };
@ -508,6 +501,30 @@
83AB8C751E8072A100086084 /* nub_vag.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AB8C731E8072A100086084 /* nub_vag.c */; };
83AB8C761E8072A100086084 /* x360_ast.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AB8C741E8072A100086084 /* x360_ast.c */; };
83BAFB6C19F45EB3005DAB60 /* bfstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 83BAFB6B19F45EB3005DAB60 /* bfstm.c */; };
83C7280F22BC893D00678B4A /* xwb_xsb.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C727FB22BC893800678B4A /* xwb_xsb.h */; };
83C7281022BC893D00678B4A /* nps.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C727FC22BC893900678B4A /* nps.c */; };
83C7281122BC893D00678B4A /* 9tav_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C727FD22BC893900678B4A /* 9tav_streamfile.h */; };
83C7281222BC893D00678B4A /* 9tav.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C727FE22BC893900678B4A /* 9tav.c */; };
83C7281322BC893D00678B4A /* mta2.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C727FF22BC893900678B4A /* mta2.c */; };
83C7281422BC893D00678B4A /* ffdl.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7280022BC893A00678B4A /* ffdl.c */; };
83C7281522BC893D00678B4A /* txth_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C7280122BC893A00678B4A /* txth_streamfile.h */; };
83C7281622BC893D00678B4A /* xwma_konami_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C7280222BC893A00678B4A /* xwma_konami_streamfile.h */; };
83C7281722BC893D00678B4A /* mtaf.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7280322BC893A00678B4A /* mtaf.c */; };
83C7281822BC893D00678B4A /* sfh_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C7280422BC893B00678B4A /* sfh_streamfile.h */; };
83C7281922BC893D00678B4A /* fsb5_fev.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7280522BC893B00678B4A /* fsb5_fev.c */; };
83C7281A22BC893D00678B4A /* mus_vc.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7280622BC893B00678B4A /* mus_vc.c */; };
83C7281B22BC893D00678B4A /* strm_abylight.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7280722BC893B00678B4A /* strm_abylight.c */; };
83C7281C22BC893D00678B4A /* sfh.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7280822BC893C00678B4A /* sfh.c */; };
83C7281D22BC893D00678B4A /* ikm.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7280922BC893C00678B4A /* ikm.c */; };
83C7281E22BC893D00678B4A /* msf.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7280A22BC893C00678B4A /* msf.c */; };
83C7281F22BC893D00678B4A /* xwma_konami.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7280B22BC893C00678B4A /* xwma_konami.c */; };
83C7282022BC893D00678B4A /* dcs_wav.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7280C22BC893D00678B4A /* dcs_wav.c */; };
83C7282122BC893D00678B4A /* msf_konami.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7280D22BC893D00678B4A /* msf_konami.c */; };
83C7282222BC893D00678B4A /* mta2_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C7280E22BC893D00678B4A /* mta2_streamfile.h */; };
83C7282722BC8C1500678B4A /* plugins.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C7282322BC8C1300678B4A /* plugins.h */; };
83C7282822BC8C1500678B4A /* mixing.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C7282422BC8C1400678B4A /* mixing.h */; };
83C7282922BC8C1500678B4A /* mixing.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7282522BC8C1400678B4A /* mixing.c */; };
83C7282A22BC8C1500678B4A /* plugins.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7282622BC8C1400678B4A /* plugins.c */; };
83CAB8E21F0B0752001BC993 /* wii_04sw.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CAB8E11F0B0745001BC993 /* wii_04sw.c */; };
83CAB8E31F0B0755001BC993 /* pc_xa30.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CAB8DC1F0B0744001BC993 /* pc_xa30.c */; };
83CD428A1F787879000F77BE /* libswresample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83CD42851F787878000F77BE /* libswresample.a */; };
@ -849,7 +866,6 @@
834FE0E6215C79EC000A5D3D /* sdf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sdf.c; sourceTree = "<group>"; };
834FE0E7215C79EC000A5D3D /* msv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = msv.c; sourceTree = "<group>"; };
834FE0E8215C79EC000A5D3D /* ck.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ck.c; sourceTree = "<group>"; };
8350270C1ED119D200C25929 /* ps3_mta2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_mta2.c; sourceTree = "<group>"; };
835027121ED119E000C25929 /* mta2_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mta2_decoder.c; sourceTree = "<group>"; };
8350C0541E071881009E0A93 /* xma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xma.c; sourceTree = "<group>"; };
8350C0591E071990009E0A93 /* ps2_svag_snk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_svag_snk.c; sourceTree = "<group>"; };
@ -886,7 +902,6 @@
836F6DFC18BDC2180095E648 /* sdx2_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sdx2_decoder.c; sourceTree = "<group>"; };
836F6DFD18BDC2180095E648 /* ws_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ws_decoder.c; sourceTree = "<group>"; };
836F6DFE18BDC2180095E648 /* xa_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xa_decoder.c; sourceTree = "<group>"; };
836F6E0118BDC2180095E648 /* aix_layout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aix_layout.c; sourceTree = "<group>"; };
836F6E0418BDC2180095E648 /* blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked.c; sourceTree = "<group>"; };
836F6E0D18BDC2180095E648 /* interleave.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = interleave.c; sourceTree = "<group>"; };
836F6E1018BDC2180095E648 /* layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = layout.h; sourceTree = "<group>"; };
@ -909,7 +924,6 @@
836F6E3B18BDC2180095E648 /* capdsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = capdsp.c; sourceTree = "<group>"; };
836F6E3C18BDC2180095E648 /* Cstr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Cstr.c; sourceTree = "<group>"; };
836F6E3D18BDC2180095E648 /* dc_asd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_asd.c; sourceTree = "<group>"; };
836F6E3E18BDC2180095E648 /* dc_dcsw_dcs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_dcsw_dcs.c; sourceTree = "<group>"; };
836F6E3F18BDC2180095E648 /* dc_idvi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_idvi.c; sourceTree = "<group>"; };
836F6E4018BDC2180095E648 /* dc_kcey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_kcey.c; sourceTree = "<group>"; };
836F6E4118BDC2180095E648 /* dc_str.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_str.c; sourceTree = "<group>"; };
@ -991,7 +1005,6 @@
836F6E9E18BDC2180095E648 /* ps2_hgc1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_hgc1.c; sourceTree = "<group>"; };
836F6E9F18BDC2180095E648 /* ps2_hsf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_hsf.c; sourceTree = "<group>"; };
836F6EA018BDC2180095E648 /* ps2_iab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_iab.c; sourceTree = "<group>"; };
836F6EA118BDC2180095E648 /* ps2_ikm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_ikm.c; sourceTree = "<group>"; };
836F6EA218BDC2180095E648 /* ps2_ild.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_ild.c; sourceTree = "<group>"; };
836F6EA318BDC2180095E648 /* ps2_int.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_int.c; sourceTree = "<group>"; };
836F6EA418BDC2180095E648 /* ps2_joe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_joe.c; sourceTree = "<group>"; };
@ -1003,8 +1016,6 @@
836F6EAC18BDC2180095E648 /* ps2_mic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_mic.c; sourceTree = "<group>"; };
836F6EAD18BDC2180095E648 /* ps2_mihb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_mihb.c; sourceTree = "<group>"; };
836F6EAE18BDC2180095E648 /* ps2_msa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_msa.c; sourceTree = "<group>"; };
836F6EB018BDC2180095E648 /* ps2_mtaf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_mtaf.c; sourceTree = "<group>"; };
836F6EB118BDC2180095E648 /* ps2_npsf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_npsf.c; sourceTree = "<group>"; };
836F6EB218BDC2180095E648 /* ps2_p2bt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_p2bt.c; sourceTree = "<group>"; };
836F6EB318BDC2180095E648 /* ps2_pnb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_pnb.c; sourceTree = "<group>"; };
836F6EB618BDC2180095E648 /* ps2_rnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rnd.c; sourceTree = "<group>"; };
@ -1033,7 +1044,6 @@
836F6ED318BDC2190095E648 /* ps2_xa30.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_xa30.c; sourceTree = "<group>"; };
836F6ED518BDC2190095E648 /* ps3_cps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_cps.c; sourceTree = "<group>"; };
836F6ED618BDC2190095E648 /* ps3_ivag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_ivag.c; sourceTree = "<group>"; };
836F6ED818BDC2190095E648 /* ps3_msf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_msf.c; sourceTree = "<group>"; };
836F6ED918BDC2190095E648 /* ps3_past.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_past.c; sourceTree = "<group>"; };
836F6EDF18BDC2190095E648 /* psx_gms.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = psx_gms.c; sourceTree = "<group>"; };
836F6EE118BDC2190095E648 /* raw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = raw.c; sourceTree = "<group>"; };
@ -1152,6 +1162,30 @@
83AB8C731E8072A100086084 /* nub_vag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nub_vag.c; sourceTree = "<group>"; };
83AB8C741E8072A100086084 /* x360_ast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x360_ast.c; sourceTree = "<group>"; };
83BAFB6B19F45EB3005DAB60 /* bfstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bfstm.c; sourceTree = "<group>"; };
83C727FB22BC893800678B4A /* xwb_xsb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xwb_xsb.h; sourceTree = "<group>"; };
83C727FC22BC893900678B4A /* nps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nps.c; sourceTree = "<group>"; };
83C727FD22BC893900678B4A /* 9tav_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 9tav_streamfile.h; sourceTree = "<group>"; };
83C727FE22BC893900678B4A /* 9tav.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = 9tav.c; sourceTree = "<group>"; };
83C727FF22BC893900678B4A /* mta2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mta2.c; sourceTree = "<group>"; };
83C7280022BC893A00678B4A /* ffdl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffdl.c; sourceTree = "<group>"; };
83C7280122BC893A00678B4A /* txth_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = txth_streamfile.h; sourceTree = "<group>"; };
83C7280222BC893A00678B4A /* xwma_konami_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xwma_konami_streamfile.h; sourceTree = "<group>"; };
83C7280322BC893A00678B4A /* mtaf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mtaf.c; sourceTree = "<group>"; };
83C7280422BC893B00678B4A /* sfh_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sfh_streamfile.h; sourceTree = "<group>"; };
83C7280522BC893B00678B4A /* fsb5_fev.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fsb5_fev.c; sourceTree = "<group>"; };
83C7280622BC893B00678B4A /* mus_vc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mus_vc.c; sourceTree = "<group>"; };
83C7280722BC893B00678B4A /* strm_abylight.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = strm_abylight.c; sourceTree = "<group>"; };
83C7280822BC893C00678B4A /* sfh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sfh.c; sourceTree = "<group>"; };
83C7280922BC893C00678B4A /* ikm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ikm.c; sourceTree = "<group>"; };
83C7280A22BC893C00678B4A /* msf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = msf.c; sourceTree = "<group>"; };
83C7280B22BC893C00678B4A /* xwma_konami.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xwma_konami.c; sourceTree = "<group>"; };
83C7280C22BC893D00678B4A /* dcs_wav.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dcs_wav.c; sourceTree = "<group>"; };
83C7280D22BC893D00678B4A /* msf_konami.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = msf_konami.c; sourceTree = "<group>"; };
83C7280E22BC893D00678B4A /* mta2_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mta2_streamfile.h; sourceTree = "<group>"; };
83C7282322BC8C1300678B4A /* plugins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = plugins.h; sourceTree = "<group>"; };
83C7282422BC8C1400678B4A /* mixing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mixing.h; 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>"; };
83CAB8DC1F0B0744001BC993 /* pc_xa30.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pc_xa30.c; sourceTree = "<group>"; };
83CAB8E11F0B0745001BC993 /* wii_04sw.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = wii_04sw.c; sourceTree = "<group>"; };
83CD42851F787878000F77BE /* libswresample.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libswresample.a; path = ../../ThirdParty/ffmpeg/lib/libswresample.a; sourceTree = "<group>"; };
@ -1305,6 +1339,10 @@
836F6DFF18BDC2180095E648 /* layout */,
836F6E2718BDC2180095E648 /* meta */,
83A3F0711E3AD8B900D6A794 /* formats.c */,
83C7282522BC8C1400678B4A /* mixing.c */,
83C7282422BC8C1400678B4A /* mixing.h */,
83C7282622BC8C1400678B4A /* plugins.c */,
83C7282322BC8C1300678B4A /* plugins.h */,
83A3F0731E3AD8B900D6A794 /* stack_alloc.h */,
836F6F1718BDC2190095E648 /* streamfile.c */,
836F6F1818BDC2190095E648 /* streamfile.h */,
@ -1394,7 +1432,6 @@
836F6DFF18BDC2180095E648 /* layout */ = {
isa = PBXGroup;
children = (
836F6E0118BDC2180095E648 /* aix_layout.c */,
8306B08E2098454E000302D4 /* blocked_adm.c */,
8306B0882098454C000302D4 /* blocked_ast.c */,
83AA5D1B1F6E2F7F0020821C /* blocked_awc.c */,
@ -1447,6 +1484,8 @@
isa = PBXGroup;
children = (
836F6E2918BDC2180095E648 /* 2dx9.c */,
83C727FD22BC893900678B4A /* 9tav_streamfile.h */,
83C727FE22BC893900678B4A /* 9tav.c */,
8351F32A2212B57000A606E4 /* 208.c */,
834FE0C8215C79E7000A5D3D /* a2m.c */,
8306B0C82098458D000302D4 /* aax_utf.h */,
@ -1493,10 +1532,10 @@
834FE0D8215C79EA000A5D3D /* csmp.c */,
836F6E3C18BDC2180095E648 /* Cstr.c */,
836F6E3D18BDC2180095E648 /* dc_asd.c */,
836F6E3E18BDC2180095E648 /* dc_dcsw_dcs.c */,
836F6E3F18BDC2180095E648 /* dc_idvi.c */,
836F6E4018BDC2180095E648 /* dc_kcey.c */,
836F6E4118BDC2180095E648 /* dc_str.c */,
83C7280C22BC893D00678B4A /* dcs_wav.c */,
8349A8EE1FE6257C00E26435 /* dec.c */,
834FE0CD215C79E8000A5D3D /* derf.c */,
836F6E4318BDC2180095E648 /* dmsg_segh.c */,
@ -1516,6 +1555,7 @@
836F6E4A18BDC2180095E648 /* excitebots.c */,
8349A8EF1FE6257C00E26435 /* ezw.c */,
832BF80821E05135006F50F1 /* fag.c */,
83C7280022BC893A00678B4A /* ffdl.c */,
838BDB6D1D3B043C0022CA6F /* ffmpeg.c */,
836F6E4B18BDC2180095E648 /* ffw.c */,
8349A8FD1FE6257F00E26435 /* flx.c */,
@ -1523,6 +1563,7 @@
834FE0C4215C79E6000A5D3D /* fsb_interleave_streamfile.h */,
83A21F7E201D8980000F04B9 /* fsb_keys.h */,
836F6E4C18BDC2180095E648 /* fsb.c */,
83C7280522BC893B00678B4A /* fsb5_fev.c */,
834FE0E3215C79EC000A5D3D /* fsb5_interleave_streamfile.h */,
83F5F8821908D0A400C8E65F /* fsb5.c */,
834D3A6D19F47C98001C54F6 /* g1l.c */,
@ -1540,6 +1581,7 @@
834FE0DF215C79EB000A5D3D /* hd3_bd3.c */,
836F6E5318BDC2180095E648 /* his.c */,
834FE0E0215C79EB000A5D3D /* idsp_ie.c */,
83C7280922BC893C00678B4A /* ikm.c */,
832BF81121E05149006F50F1 /* imc.c */,
836F6E5518BDC2180095E648 /* ios_psnd.c */,
836F6E5618BDC2180095E648 /* ish_isd.c */,
@ -1561,12 +1603,18 @@
836F6E6018BDC2180095E648 /* mp4.c */,
8306B0CB2098458E000302D4 /* msb_msh.c */,
832BF81721E0514A006F50F1 /* msf_banpresto.c */,
83C7280D22BC893D00678B4A /* msf_konami.c */,
832BF80B21E05148006F50F1 /* msf_tamasoft.c */,
83C7280A22BC893C00678B4A /* msf.c */,
83709E011ECBC1A4005C03D3 /* mss.c */,
834FE0E7215C79EC000A5D3D /* msv.c */,
836F6E6118BDC2180095E648 /* msvp.c */,
83C7280E22BC893D00678B4A /* mta2_streamfile.h */,
83C727FF22BC893900678B4A /* mta2.c */,
83C7280322BC893A00678B4A /* mtaf.c */,
832BF81221E05149006F50F1 /* mul.c */,
836F6E6218BDC2180095E648 /* mus_acm.c */,
83C7280622BC893B00678B4A /* mus_vc.c */,
836F6E6318BDC2180095E648 /* musc.c */,
836F6E6418BDC2180095E648 /* musx.c */,
836F6E6518BDC2180095E648 /* myspd.c */,
@ -1598,6 +1646,7 @@
8349A8FA1FE6257E00E26435 /* ngc_vid1.c */,
836F6E7E18BDC2180095E648 /* ngc_ymf.c */,
836F6E7F18BDC2180095E648 /* ngca.c */,
83C727FC22BC893900678B4A /* nps.c */,
834FE0E1215C79EB000A5D3D /* nub_idsp.c */,
83AB8C731E8072A100086084 /* nub_vag.c */,
83345A4B1F8AEB2700B2EAA4 /* nub_xma.c */,
@ -1647,7 +1696,6 @@
836F6E9E18BDC2180095E648 /* ps2_hgc1.c */,
836F6E9F18BDC2180095E648 /* ps2_hsf.c */,
836F6EA018BDC2180095E648 /* ps2_iab.c */,
836F6EA118BDC2180095E648 /* ps2_ikm.c */,
836F6EA218BDC2180095E648 /* ps2_ild.c */,
836F6EA318BDC2180095E648 /* ps2_int.c */,
836F6EA418BDC2180095E648 /* ps2_joe.c */,
@ -1659,8 +1707,6 @@
836F6EAC18BDC2180095E648 /* ps2_mic.c */,
836F6EAD18BDC2180095E648 /* ps2_mihb.c */,
836F6EAE18BDC2180095E648 /* ps2_msa.c */,
836F6EB018BDC2180095E648 /* ps2_mtaf.c */,
836F6EB118BDC2180095E648 /* ps2_npsf.c */,
836F6EB218BDC2180095E648 /* ps2_p2bt.c */,
8349A8F21FE6257D00E26435 /* ps2_pcm.c */,
836F6EB318BDC2180095E648 /* ps2_pnb.c */,
@ -1694,8 +1740,6 @@
836F6ED318BDC2190095E648 /* ps2_xa30.c */,
836F6ED518BDC2190095E648 /* ps3_cps.c */,
836F6ED618BDC2190095E648 /* ps3_ivag.c */,
836F6ED818BDC2190095E648 /* ps3_msf.c */,
8350270C1ED119D200C25929 /* ps3_mta2.c */,
836F6ED918BDC2190095E648 /* ps3_past.c */,
836F6EDF18BDC2190095E648 /* psx_gms.c */,
836F6EE118BDC2190095E648 /* raw.c */,
@ -1719,6 +1763,8 @@
834FE0E6215C79EC000A5D3D /* sdf.c */,
836F6EEF18BDC2190095E648 /* sdt.c */,
836F6EF018BDC2190095E648 /* seg.c */,
83C7280422BC893B00678B4A /* sfh_streamfile.h */,
83C7280822BC893C00678B4A /* sfh.c */,
836F6EF118BDC2190095E648 /* sfl.c */,
831BA6111EAC61A500CF89B0 /* sgxd.c */,
839E21EA1F2EDB0500EE54D7 /* sk_aud.c */,
@ -1737,6 +1783,7 @@
836F6EF618BDC2190095E648 /* str_asr.c */,
836F6EF718BDC2190095E648 /* str_snds.c */,
834FE0C2215C79E6000A5D3D /* str_wav.c */,
83C7280722BC893B00678B4A /* strm_abylight.c */,
836F6EF818BDC2190095E648 /* stx.c */,
834FE0D7215C79EA000A5D3D /* svg.c */,
836F6EF918BDC2190095E648 /* svs.c */,
@ -1744,6 +1791,7 @@
83709E031ECBC1A4005C03D3 /* ta_aac.c */,
836F6EFA18BDC2190095E648 /* thp.c */,
836F6EFB18BDC2190095E648 /* tun.c */,
83C7280122BC893A00678B4A /* txth_streamfile.h */,
830165971F256BD000CA0941 /* txth.c */,
8306B0D22098458F000302D4 /* txtp.c */,
8351F32B2212B57000A606E4 /* ubi_bao_streamfile.h */,
@ -1809,8 +1857,11 @@
836F6F1218BDC2190095E648 /* xss.c */,
834FE0C6215C79E7000A5D3D /* xvag_streamfile.h */,
83345A4E1F8AEB2800B2EAA4 /* xvag.c */,
83C727FB22BC893800678B4A /* xwb_xsb.h */,
836F6F1318BDC2190095E648 /* xwb.c */,
83A21F7D201D8980000F04B9 /* xwc.c */,
83C7280222BC893A00678B4A /* xwma_konami_streamfile.h */,
83C7280B22BC893C00678B4A /* xwma_konami.c */,
832BF81621E0514A006F50F1 /* xwma.c */,
836F6F1418BDC2190095E648 /* ydsp.c */,
836F6F1518BDC2190095E648 /* zsd.c */,
@ -1857,6 +1908,7 @@
files = (
836F705518BDC2190095E648 /* streamtypes.h in Headers */,
836F6F3518BDC2190095E648 /* nwa_decoder.h in Headers */,
83C7282222BC893D00678B4A /* mta2_streamfile.h in Headers */,
83A21F87201D8981000F04B9 /* fsb_keys.h in Headers */,
834FE0EC215C79ED000A5D3D /* kma9_streamfile.h in Headers */,
8349A90F1FE6258200E26435 /* aix_streamfile.h in Headers */,
@ -1864,6 +1916,7 @@
8351F32E2212B57000A606E4 /* ubi_bao_streamfile.h in Headers */,
8349A9111FE6258200E26435 /* bar_streamfile.h in Headers */,
836F6F2718BDC2190095E648 /* g72x_state.h in Headers */,
83C7282822BC8C1500678B4A /* mixing.h in Headers */,
832BF82C21E0514B006F50F1 /* hca_keys_awb.h in Headers */,
8306B0E020984590000302D4 /* ppst_streamfile.h in Headers */,
834FE0BA215C798C000A5D3D /* ea_mt_decoder_utk.h in Headers */,
@ -1873,22 +1926,28 @@
836F705418BDC2190095E648 /* streamfile.h in Headers */,
83A3F0761E3AD8B900D6A794 /* stack_alloc.h in Headers */,
8323894B1D22419B00482226 /* clHCA.h in Headers */,
83C7281122BC893D00678B4A /* 9tav_streamfile.h in Headers */,
83C7280F22BC893D00678B4A /* xwb_xsb.h in Headers */,
83C7281622BC893D00678B4A /* xwma_konami_streamfile.h in Headers */,
839E21E81F2EDAF100EE54D7 /* mpeg_decoder.h in Headers */,
834FE10C215C79ED000A5D3D /* fsb5_interleave_streamfile.h in Headers */,
839E21E51F2EDAF100EE54D7 /* vorbis_custom_decoder.h in Headers */,
8306B0E320984590000302D4 /* aax_utf.h in Headers */,
8306B0E120984590000302D4 /* ubi_lyn_ogg_streamfile.h in Headers */,
836F705918BDC2190095E648 /* vgmstream.h in Headers */,
83C7281522BC893D00678B4A /* txth_streamfile.h in Headers */,
8306B0DE20984590000302D4 /* awc_xma_streamfile.h in Headers */,
834FE0B5215C798C000A5D3D /* acm_decoder_libacm.h in Headers */,
839E21E61F2EDAF100EE54D7 /* vorbis_custom_data_wwise.h in Headers */,
834FE103215C79ED000A5D3D /* ea_schl_streamfile.h in Headers */,
83C7282722BC8C1500678B4A /* plugins.h in Headers */,
83F0AA6021E2028C004BBC04 /* vsv_streamfile.h in Headers */,
48C2650F1A5D420800A0A3D6 /* vorbisfile.h in Headers */,
836F705718BDC2190095E648 /* util.h in Headers */,
836F6F9A18BDC2190095E648 /* meta.h in Headers */,
8306B0D820984590000302D4 /* ea_eaac_streamfile.h in Headers */,
8306B0E820984590000302D4 /* opus_interleave_streamfile.h in Headers */,
83C7281822BC893D00678B4A /* sfh_streamfile.h in Headers */,
834FE0EF215C79ED000A5D3D /* xvag_streamfile.h in Headers */,
8349A90C1FE6258200E26435 /* sqex_scd_streamfile.h in Headers */,
8349A91B1FE6258200E26435 /* adx_keys.h in Headers */,
@ -1945,6 +2004,7 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
es,
);
@ -2060,12 +2120,14 @@
834FE104215C79ED000A5D3D /* nxa.c in Sources */,
8349A9071FE6258200E26435 /* dec.c in Sources */,
839E21E91F2EDAF100EE54D7 /* vorbis_custom_utils_sk.c in Sources */,
83C7281422BC893D00678B4A /* ffdl.c in Sources */,
832BF80721E050DC006F50F1 /* blocked_vs_str.c in Sources */,
839E21E41F2EDAF100EE54D7 /* vorbis_custom_utils_fsb.c in Sources */,
839E21E11F2EDAF100EE54D7 /* vorbis_custom_decoder.c in Sources */,
839E21E71F2EDAF100EE54D7 /* mpeg_custom_utils.c in Sources */,
839E21E31F2EDAF100EE54D7 /* mpeg_custom_utils_ahx.c in Sources */,
8306B0AF20984552000302D4 /* blocked_rws.c in Sources */,
83C7281A22BC893D00678B4A /* mus_vc.c in Sources */,
839E21EB1F2EDB0600EE54D7 /* sk_aud.c in Sources */,
834FE0F1215C79ED000A5D3D /* a2m.c in Sources */,
8301659A1F256BD000CA0941 /* txth.c in Sources */,
@ -2120,6 +2182,7 @@
834FE109215C79ED000A5D3D /* idsp_ie.c in Sources */,
83299FD01E7660C7003A3242 /* bik.c in Sources */,
836F6F3318BDC2190095E648 /* ngc_dtk_decoder.c in Sources */,
83C7281322BC893D00678B4A /* mta2.c in Sources */,
8306B0EF20984590000302D4 /* ubi_bao.c in Sources */,
836F6FBB18BDC2190095E648 /* ngca.c in Sources */,
8306B0E220984590000302D4 /* smv.c in Sources */,
@ -2144,6 +2207,7 @@
834FE105215C79ED000A5D3D /* xmd.c in Sources */,
834FE0F6215C79ED000A5D3D /* derf.c in Sources */,
836F6F8B18BDC2190095E648 /* genh.c in Sources */,
83C7281922BC893D00678B4A /* fsb5_fev.c in Sources */,
8349A8EA1FE6253900E26435 /* blocked_ea_schl.c in Sources */,
836F705118BDC2190095E648 /* zsd.c in Sources */,
8349A91F1FE6258200E26435 /* naac.c in Sources */,
@ -2168,7 +2232,6 @@
836F6F7818BDC2190095E648 /* Cstr.c in Sources */,
836F6F1E18BDC2190095E648 /* acm_decoder.c in Sources */,
836F6FD818BDC2190095E648 /* ps2_gbts.c in Sources */,
836F6F7A18BDC2190095E648 /* dc_dcsw_dcs.c in Sources */,
831BA61A1EAC61A500CF89B0 /* ps2_vds_vdm.c in Sources */,
836F6FF218BDC2190095E648 /* ps2_rnd.c in Sources */,
83709E0D1ECBC1C3005C03D3 /* mc3_decoder.c in Sources */,
@ -2185,13 +2248,11 @@
836F6F6C18BDC2190095E648 /* ahx.c in Sources */,
83AB8C751E8072A100086084 /* nub_vag.c in Sources */,
836F702D18BDC2190095E648 /* sfl.c in Sources */,
836F6FEC18BDC2190095E648 /* ps2_mtaf.c in Sources */,
83D7318C1A749EEE00CA1366 /* g719_decoder.c in Sources */,
836F701118BDC2190095E648 /* ps3_cps.c in Sources */,
8306B0DA20984590000302D4 /* ea_wve_au00.c in Sources */,
83A21F85201D8981000F04B9 /* atx.c in Sources */,
8306B0E720984590000302D4 /* opus_ppp.c in Sources */,
836F701418BDC2190095E648 /* ps3_msf.c in Sources */,
836F6F6518BDC2190095E648 /* 2dx9.c in Sources */,
830EBE102004655D0023AA10 /* atrac9_decoder.c in Sources */,
836F700818BDC2190095E648 /* ps2_vms.c in Sources */,
@ -2227,6 +2288,7 @@
836F6FCB18BDC2190095E648 /* ps2_ads.c in Sources */,
834FE108215C79ED000A5D3D /* hd3_bd3.c in Sources */,
836F6FD318BDC2190095E648 /* ps2_ccc.c in Sources */,
83C7281C22BC893D00678B4A /* sfh.c in Sources */,
834FE0FC215C79ED000A5D3D /* vai.c in Sources */,
83AA5D171F6E2F600020821C /* mpeg_custom_utils_ealayer3.c in Sources */,
83345A521F8AEB2800B2EAA4 /* xvag.c in Sources */,
@ -2234,6 +2296,7 @@
836F6F3918BDC2190095E648 /* SASSC_decoder.c in Sources */,
8306B0A920984552000302D4 /* blocked_adm.c in Sources */,
836F703A18BDC2190095E648 /* vs.c in Sources */,
83C7282022BC893D00678B4A /* dcs_wav.c in Sources */,
8306B0F220984590000302D4 /* ubi_jade.c in Sources */,
836F6FF918BDC2190095E648 /* ps2_snd.c in Sources */,
836F6F2918BDC2190095E648 /* l5_555_decoder.c in Sources */,
@ -2250,6 +2313,7 @@
8350C0551E071881009E0A93 /* xma.c in Sources */,
836F6F3218BDC2190095E648 /* ngc_dsp_decoder.c in Sources */,
836F704218BDC2190095E648 /* wii_sts.c in Sources */,
83C7281722BC893D00678B4A /* mtaf.c in Sources */,
836F703918BDC2190095E648 /* vgs.c in Sources */,
834FE0F8215C79ED000A5D3D /* adpcm_capcom.c in Sources */,
836F6F2C18BDC2190095E648 /* mp4_aac_decoder.c in Sources */,
@ -2264,8 +2328,8 @@
836F6FDA18BDC2190095E648 /* ps2_hgc1.c in Sources */,
836F702C18BDC2190095E648 /* seg.c in Sources */,
836F700918BDC2190095E648 /* ps2_voi.c in Sources */,
836F6F3E18BDC2190095E648 /* aix_layout.c in Sources */,
836F6FE018BDC2190095E648 /* ps2_joe.c in Sources */,
83C7282A22BC8C1500678B4A /* plugins.c in Sources */,
832BF82721E0514B006F50F1 /* xa.c in Sources */,
8306B0A220984552000302D4 /* blocked_bdsp.c in Sources */,
836F700118BDC2190095E648 /* ps2_tec.c in Sources */,
@ -2290,6 +2354,7 @@
836F6F6D18BDC2190095E648 /* aifc.c in Sources */,
836F702218BDC2190095E648 /* rsd.c in Sources */,
8349A90D1FE6258200E26435 /* ubi_sb.c in Sources */,
83C7281D22BC893D00678B4A /* ikm.c in Sources */,
83345A501F8AEB2800B2EAA4 /* pc_al2.c in Sources */,
834FE0BB215C798C000A5D3D /* celt_fsb_decoder.c in Sources */,
836F702518BDC2190095E648 /* rwx.c in Sources */,
@ -2299,6 +2364,8 @@
834FE0BF215C79A9000A5D3D /* flat.c in Sources */,
836F6F6B18BDC2190095E648 /* agsc.c in Sources */,
836F700E18BDC2190095E648 /* ps2_xa2.c in Sources */,
83C7281022BC893D00678B4A /* nps.c in Sources */,
83C7281E22BC893D00678B4A /* msf.c in Sources */,
836F6FF718BDC2190095E648 /* ps2_sl3.c in Sources */,
8351F32D2212B57000A606E4 /* 208.c in Sources */,
836F6F3118BDC2190095E648 /* ngc_afc_decoder.c in Sources */,
@ -2328,7 +2395,6 @@
836F701518BDC2190095E648 /* ps3_past.c in Sources */,
832BF80621E050DC006F50F1 /* blocked_vs_square.c in Sources */,
836F6F7C18BDC2190095E648 /* dc_kcey.c in Sources */,
836F6FED18BDC2190095E648 /* ps2_npsf.c in Sources */,
83A21F8B201D8982000F04B9 /* sps_n1.c in Sources */,
836F6F9E18BDC2190095E648 /* mus_acm.c in Sources */,
83709E0E1ECBC1C3005C03D3 /* psv_decoder.c in Sources */,
@ -2338,6 +2404,7 @@
836F6FCD18BDC2190095E648 /* ps2_ass.c in Sources */,
8349A90B1FE6258200E26435 /* ps2_pcm.c in Sources */,
836F6F4A18BDC2190095E648 /* interleave.c in Sources */,
83C7281F22BC893D00678B4A /* xwma_konami.c in Sources */,
83EDE5D81A70951A005F5D84 /* mca.c in Sources */,
834FE0F3215C79ED000A5D3D /* bnk_sony.c in Sources */,
8306B0AE20984552000302D4 /* blocked_filp.c in Sources */,
@ -2349,6 +2416,7 @@
836F704618BDC2190095E648 /* x360_tra.c in Sources */,
834FE0F0215C79ED000A5D3D /* apc.c in Sources */,
836F6FFA18BDC2190095E648 /* ps2_spm.c in Sources */,
83C7281B22BC893D00678B4A /* strm_abylight.c in Sources */,
834D3A6E19F47C98001C54F6 /* g1l.c in Sources */,
836F6FCE18BDC2190095E648 /* ps2_ast.c in Sources */,
832BF82A21E0514B006F50F1 /* vs_square.c in Sources */,
@ -2430,6 +2498,7 @@
836F6FB118BDC2190095E648 /* ngc_ffcc_str.c in Sources */,
8306B0B620984552000302D4 /* blocked_hwas.c in Sources */,
836F6FC218BDC2190095E648 /* pc_mxst.c in Sources */,
83C7282922BC8C1500678B4A /* mixing.c in Sources */,
8375737621F950ED00F01AF5 /* gin.c in Sources */,
836F6FC918BDC2190095E648 /* ps2_2pfs.c in Sources */,
836F704818BDC2190095E648 /* xbox_ims.c in Sources */,
@ -2460,11 +2529,12 @@
836F704F18BDC2190095E648 /* xwb.c in Sources */,
8306B0AD20984552000302D4 /* blocked_caf.c in Sources */,
8306B0AA20984552000302D4 /* blocked_sthd.c in Sources */,
8350270D1ED119D200C25929 /* ps3_mta2.c in Sources */,
836F6FE918BDC2190095E648 /* ps2_mihb.c in Sources */,
836F6FA918BDC2190095E648 /* ngc_adpdtk.c in Sources */,
836F6FDC18BDC2190095E648 /* ps2_iab.c in Sources */,
83C7282122BC893D00678B4A /* msf_konami.c in Sources */,
8315958920FEC83F007002F0 /* asf.c in Sources */,
83C7281222BC893D00678B4A /* 9tav.c in Sources */,
836F6F3818BDC2190095E648 /* psx_decoder.c in Sources */,
836F6F2D18BDC2190095E648 /* mpeg_decoder.c in Sources */,
836F6F2618BDC2190095E648 /* g7221_decoder.c in Sources */,
@ -2472,7 +2542,6 @@
836F6FA218BDC2190095E648 /* naomi_adpcm.c in Sources */,
836F6FBF18BDC2190095E648 /* otm.c in Sources */,
8306B0B420984552000302D4 /* blocked_tra.c in Sources */,
836F6FDD18BDC2190095E648 /* ps2_ikm.c in Sources */,
834FE0B8215C798C000A5D3D /* acm_decoder_decode.c in Sources */,
836F6FBD18BDC2190095E648 /* nwa.c in Sources */,
834FE0F7215C79ED000A5D3D /* vis.c in Sources */,
@ -2595,6 +2664,13 @@
"$(inherited)",
BUILD_VGMSTREAM,
"VAR_ARRAYS=1",
VGM_USE_ATRAC9,
VGM_USE_FFMPEG,
VGM_USE_G719,
VGM_USE_G7221,
VGM_USE_MPEG,
VGM_USE_VORBIS,
__MACOSX__,
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@ -2654,6 +2730,13 @@
BUILD_VGMSTREAM,
"VAR_ARRAYS=1",
"$(inherited)",
VGM_USE_ATRAC9,
VGM_USE_FFMPEG,
VGM_USE_G719,
VGM_USE_G7221,
VGM_USE_MPEG,
VGM_USE_VORBIS,
__MACOSX__,
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;

View File

@ -1,7 +1,11 @@
#include "coding.h"
#ifdef VGM_USE_ATRAC9
#ifdef __MACOSX__
#include <libatrac9/libatrac9.h>
#else
#include "libatrac9.h"
#endif
/* opaque struct */
@ -9,7 +13,7 @@ struct atrac9_codec_data {
uint8_t *data_buffer;
size_t data_buffer_size;
sample *sample_buffer;
sample_t *sample_buffer;
size_t samples_filled; /* number of samples in the buffer */
size_t samples_used; /* number of samples extracted from the buffer */
@ -39,7 +43,7 @@ atrac9_codec_data *init_atrac9(atrac9_config *cfg) {
status = Atrac9GetCodecInfo(data->handle, &data->info);
if (status < 0) goto fail;
//;VGM_LOG("ATRAC9: config=%x, sf-size=%x, sub-frames=%i x %i samples\n", cfg->config_data, info.superframeSize, info.framesInSuperframe, info.frameSamples);
//;VGM_LOG("ATRAC9: config=%x, sf-size=%x, sub-frames=%i x %i samples\n", cfg->config_data, data->info.superframeSize, data->info.framesInSuperframe, data->info.frameSamples);
if (cfg->channels && cfg->channels != data->info.channels) {
VGM_LOG("ATRAC9: channels in header %i vs config %i don't match\n", cfg->channels, data->info.channels);
@ -50,7 +54,7 @@ atrac9_codec_data *init_atrac9(atrac9_config *cfg) {
/* must hold at least one superframe and its samples */
data->data_buffer_size = data->info.superframeSize;
data->data_buffer = calloc(sizeof(uint8_t), data->data_buffer_size);
data->sample_buffer = calloc(sizeof(sample), data->info.channels * data->info.frameSamples * data->info.framesInSuperframe);
data->sample_buffer = calloc(sizeof(sample_t), data->info.channels * data->info.frameSamples * data->info.framesInSuperframe);
data->samples_to_discard = cfg->encoder_delay;
@ -63,7 +67,7 @@ fail:
return NULL;
}
void decode_atrac9(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, int channels) {
void decode_atrac9(VGMSTREAM *vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
atrac9_codec_data * data = vgmstream->codec_data;
int samples_done = 0;
@ -220,20 +224,20 @@ void free_atrac9(atrac9_codec_data *data) {
}
size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data *data) {
return bytes / data->info.superframeSize * (data->info.frameSamples * data->info.framesInSuperframe);
}
#if 0 //not needed (for now)
int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_channels, size_t *out_frame_size) {
static int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_channels, size_t *out_frame_size, size_t *out_samples_per_frame) {
static const int sample_rate_table[16] = {
11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
44100, 48000, 64000, 88200, 96000,128000,176400,192000
};
static const int samples_power_table[16] = {
6, 6, 7, 7, 7, 8, 8, 8,
6, 6, 7, 7, 7, 8, 8, 8
};
static const int channel_table[8] = {
1, 2, 2, 6, 8, 4, 0, 0
};
int superframe_size, frames_per_superframe, samples_per_frame, samples_per_superframe;
uint32_t sync = (atrac9_config >> 24) & 0xff; /* 8b */
uint8_t sample_rate_index = (atrac9_config >> 20) & 0x0f; /* 4b */
uint8_t channels_index = (atrac9_config >> 17) & 0x07; /* 3b */
@ -242,6 +246,11 @@ int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_c
size_t superframe_index = (atrac9_config >> 3) & 0x3; /* 2b */
/* uint8_t unused = (atrac9_config >> 0) & 0x7);*/ /* 3b */
superframe_size = ((frame_size+1) << superframe_index);
frames_per_superframe = (1 << superframe_index);
samples_per_frame = 1 << samples_power_table[sample_rate_index];
samples_per_superframe = samples_per_frame * frames_per_superframe;
if (sync != 0xFE)
goto fail;
if (out_sample_rate)
@ -249,11 +258,23 @@ int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_c
if (out_channels)
*out_channels = channel_table[channels_index];
if (out_frame_size)
*out_frame_size = (frame_size+1) * (1 << superframe_index);
*out_frame_size = superframe_size;
if (out_samples_per_frame)
*out_samples_per_frame = samples_per_superframe;
return 1;
fail:
return 0;
}
#endif
size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data *data) {
return bytes / data->info.superframeSize * (data->info.frameSamples * data->info.framesInSuperframe);
}
size_t atrac9_bytes_to_samples_cfg(size_t bytes, uint32_t atrac9_config) {
size_t frame_size, samples_per_frame;
if (!atrac9_parse_config(atrac9_config, NULL, NULL, &frame_size, &samples_per_frame))
return 0;
return bytes / frame_size * samples_per_frame;
}
#endif

View File

@ -15,37 +15,38 @@ void decode_g721(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
void g72x_init_state(struct g72x_state *state_ptr);
/* ima_decoder */
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first);
void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_alp_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ffta2_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first);
void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_alp_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ffta2_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_blitz_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_xbox_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
void decode_xbox_ima_mch(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_h4m_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, uint16_t frame_format);
void decode_xbox_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
void decode_xbox_ima_mch(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_h4m_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, uint16_t frame_format);
size_t ima_bytes_to_samples(size_t bytes, int channels);
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels);
size_t xbox_ima_bytes_to_samples(size_t bytes, int channels);
size_t apple_ima4_bytes_to_samples(size_t bytes, int channels);
/* ngc_dsp_decoder */
void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ngc_dsp_subint(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int interleave);
void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ngc_dsp_subint(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int interleave);
size_t dsp_bytes_to_samples(size_t bytes, int channels);
int32_t dsp_nibbles_to_samples(int32_t nibbles);
void dsp_read_coefs_be(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t offset, off_t spacing);
@ -62,27 +63,28 @@ void decode_ngc_dtk(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
void decode_ngc_afc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* pcm_decoder */
void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_alaw(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
/* psx_decoder */
void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int is_badflags);
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size);
void decode_psx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int is_badflags);
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size);
int ps_find_loop_offsets(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end);
int ps_find_loop_offsets_full(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end);
size_t ps_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int discard_empty);
size_t ps_bytes_to_samples(size_t bytes, int channels);
size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, int channels);
@ -122,17 +124,17 @@ void free_acm(acm_codec_data *data);
void decode_nwa(NWAData *nwa, sample *outbuf, int32_t samples_to_do);
/* msadpcm_decoder */
void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do);
void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_msadpcm_ck(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t first_sample, int32_t samples_to_do);
void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_msadpcm_ck(VGMSTREAM * vgmstream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
long msadpcm_bytes_to_samples(long bytes, int block_size, int channels);
/* yamaha_decoder */
void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
void decode_yamaha(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_yamaha_nxap(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
size_t aica_bytes_to_samples(size_t bytes, int channels);
void decode_yamaha(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
void decode_aska(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_nxap(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
size_t yamaha_bytes_to_samples(size_t bytes, int channels);
size_t aska_bytes_to_samples(size_t bytes, int channels);
/* nds_procyon_decoder */
void decode_nds_procyon(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
@ -147,10 +149,10 @@ void decode_sassc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing
void decode_lsf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* mtaf_decoder */
void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_mtaf(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
/* mta2_decoder */
void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_mta2(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
/* mc3_decoder */
void decode_mc3(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
@ -162,7 +164,7 @@ void decode_fadpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacin
void decode_asf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* dsa_decoder */
void decode_dsa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_dsa(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* xmd_decoder */
void decode_xmd(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, size_t frame_size);
@ -174,8 +176,8 @@ void decode_derf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
void decode_circus_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* oki_decoder */
void decode_pcfx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int mode);
void decode_oki16(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_pcfx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int mode);
void decode_oki16(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
size_t oki_bytes_to_samples(size_t bytes, int channels);
/* ea_mt_decoder*/
@ -191,20 +193,20 @@ void free_ea_mt(ea_mt_codec_data *data, int channels);
hca_codec_data *init_hca(STREAMFILE *streamFile);
void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do);
void reset_hca(hca_codec_data * data);
void loop_hca(hca_codec_data * data);
void loop_hca(hca_codec_data * data, int32_t num_sample);
void free_hca(hca_codec_data * data);
int test_hca_key(hca_codec_data * data, unsigned long long keycode);
#ifdef VGM_USE_VORBIS
/* ogg_vorbis_decoder */
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample_t * outbuf, int32_t samples_to_do, int channels);
void reset_ogg_vorbis(VGMSTREAM *vgmstream);
void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample);
void free_ogg_vorbis(ogg_vorbis_codec_data *data);
/* vorbis_custom_decoder */
vorbis_custom_codec_data *init_vorbis_custom(STREAMFILE *streamfile, off_t start_offset, vorbis_custom_t type, vorbis_custom_config * config);
void decode_vorbis_custom(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels);
void decode_vorbis_custom(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels);
void reset_vorbis_custom(VGMSTREAM *vgmstream);
void seek_vorbis_custom(VGMSTREAM *vgmstream, int32_t num_sample);
void free_vorbis_custom(vorbis_custom_codec_data *data);
@ -214,7 +216,7 @@ void free_vorbis_custom(vorbis_custom_codec_data *data);
/* mpeg_decoder */
mpeg_codec_data *init_mpeg(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels);
mpeg_codec_data *init_mpeg_custom(STREAMFILE *streamFile, off_t start_offset, coding_t *coding_type, int channels, mpeg_custom_t custom_type, mpeg_custom_config *config);
void decode_mpeg(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels);
void decode_mpeg(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels);
void reset_mpeg(VGMSTREAM *vgmstream);
void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample);
void free_mpeg(mpeg_codec_data *data);
@ -259,12 +261,12 @@ void free_at3plus(maiatrac3plus_codec_data *data);
#ifdef VGM_USE_ATRAC9
/* atrac9_decoder */
atrac9_codec_data *init_atrac9(atrac9_config *cfg);
void decode_atrac9(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, int channels);
void decode_atrac9(VGMSTREAM *vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels);
void reset_atrac9(VGMSTREAM *vgmstream);
void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample);
void free_atrac9(atrac9_codec_data *data);
size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data *data);
//int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_channels, size_t *out_frame_size);
size_t atrac9_bytes_to_samples_cfg(size_t bytes, uint32_t atrac9_config);
#endif
#ifdef VGM_USE_CELT
@ -282,12 +284,14 @@ ffmpeg_codec_data *init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, ui
ffmpeg_codec_data *init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size);
ffmpeg_codec_data *init_ffmpeg_header_offset_subsong(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size, int target_subsong);
void decode_ffmpeg(VGMSTREAM *stream, sample * outbuf, int32_t samples_to_do, int channels);
void decode_ffmpeg(VGMSTREAM *stream, sample_t * outbuf, int32_t samples_to_do, int channels);
void reset_ffmpeg(VGMSTREAM *vgmstream);
void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample);
void free_ffmpeg(ffmpeg_codec_data *data);
void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples);
uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data * data);
void ffmpeg_set_channel_remapping(ffmpeg_codec_data * data, int *channels_remap);
/* ffmpeg_decoder_custom_opus.c (helper-things) */
ffmpeg_codec_data * init_ffmpeg_switch_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
@ -295,7 +299,7 @@ ffmpeg_codec_data * init_ffmpeg_ue4_opus(STREAMFILE *streamFile, off_t start_off
ffmpeg_codec_data * init_ffmpeg_ea_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
ffmpeg_codec_data * init_ffmpeg_x_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
size_t switch_opus_get_samples(off_t offset, size_t data_size, STREAMFILE *streamFile);
size_t switch_opus_get_samples(off_t offset, size_t stream_size, STREAMFILE *streamFile);
size_t switch_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile);
size_t ue4_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile);
@ -351,7 +355,9 @@ int riff_get_fact_skip_samples(STREAMFILE * streamFile, off_t start_offset);
size_t atrac3_bytes_to_samples(size_t bytes, int full_block_align);
size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align);
size_t ac3_bytes_to_samples(size_t bytes, int full_block_align, int channels);
size_t aac_get_samples(STREAMFILE *streamFile, off_t start_offset, size_t bytes);
size_t mpeg_get_samples(STREAMFILE *streamFile, off_t start_offset, size_t bytes);
/* An internal struct to pass around and simulate a bitstream. */

View File

@ -1006,17 +1006,61 @@ fail:
/* ******************************************** */
size_t atrac3_bytes_to_samples(size_t bytes, int full_block_align) {
if (full_block_align <= 0) return 0;
/* ATRAC3 expects full block align since as is can mix joint stereo with mono blocks;
* so (full_block_align / channels) DOESN'T give the size of a single channel (uncommon in ATRAC3 though) */
return (bytes / full_block_align) * 1024;
}
size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align) {
if (full_block_align <= 0) return 0;
/* ATRAC3plus expects full block align since as is can mix joint stereo with mono blocks;
* so (full_block_align / channels) DOESN'T give the size of a single channel (common in ATRAC3plus) */
return (bytes / full_block_align) * 2048;
}
size_t ac3_bytes_to_samples(size_t bytes, int full_block_align, int channels) {
if (full_block_align <= 0) return 0;
return (bytes / full_block_align) * 256 * channels;
}
size_t aac_get_samples(STREAMFILE *streamFile, off_t start_offset, size_t bytes) {
const int samples_per_frame = 1024; /* theoretically 960 exists in .MP4 so may need a flag */
int frames = 0;
off_t offset = start_offset;
off_t max_offset = start_offset + bytes;
if (!streamFile)
return 0;
if (max_offset > get_streamfile_size(streamFile))
max_offset = get_streamfile_size(streamFile);
/* AAC sometimes comes with an "ADIF" header right before data but probably not in games,
* while standard raw frame headers are called "ADTS" and are similar to MPEG's:
* (see https://wiki.multimedia.cx/index.php/ADTS) */
/* AAC uses VBR so must read all frames */
while (offset < max_offset) {
uint16_t frame_sync = read_u16be(offset+0x00, streamFile);
uint32_t frame_size = read_u32be(offset+0x02, streamFile);
frame_sync = (frame_sync >> 4) & 0x0FFF; /* 12b */
frame_size = (frame_size >> 5) & 0x1FFF; /* 13b */
if (frame_sync != 0xFFF)
break;
if (frame_size <= 0x08)
break;
frames++;
offset += frame_size;
}
return frames * samples_per_frame;
}
/* ******************************************** */
/* BITSTREAM */

View File

@ -10,7 +10,7 @@ static const int dsa_coefs[16] = {
/* Decodes Ocean DSA ADPCM codec from Last Rites (PC).
* Reverse engineered from daemon1's reverse engineering. */
void decode_dsa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_dsa(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
off_t frame_offset;
int i, frames_in, sample_count = 0;
size_t bytes_per_frame, samples_per_frame;
@ -32,20 +32,20 @@ void decode_dsa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
/* decode nibbles */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
int32_t new_sample;
int32_t sample;
uint8_t nibbles = (uint8_t)read_8bit(frame_offset+0x01 + i/2,stream->streamfile);
new_sample = i&1 ? /* high nibble first */
sample = i&1 ? /* high nibble first */
(nibbles >> 0) & 0xf :
(nibbles >> 4) & 0xf;
new_sample = ((int16_t)(new_sample << 0xC) >> shift); /* 16b sign extend + scale */
new_sample = new_sample + ((hist1 * filter) >> 0x10);
sample = ((int16_t)(sample << 0xC) >> shift); /* 16b sign extend + scale */
sample = sample + ((hist1 * filter) >> 0x10);
outbuf[sample_count] = (int16_t)(new_sample << 2);
outbuf[sample_count] = (sample_t)(sample << 2);
sample_count += channelspacing;
hist1 = new_sample;
hist1 = sample;
}
stream->adpcm_history1_32 = hist1;

View File

@ -28,8 +28,27 @@ static void g_init_ffmpeg() {
}
}
static void remap_audio(sample_t *outbuf, int sample_count, int channels, int channel_mappings[]) {
int ch_from,ch_to,s;
sample_t temp;
for (s = 0; s < sample_count; s++) {
for (ch_from = 0; ch_from < channels; ch_from++) {
if (ch_from > 32)
continue;
ch_to = channel_mappings[ch_from];
if (ch_to < 1 || ch_to > 32 || ch_to > channels-1 || ch_from == ch_to)
continue;
temp = outbuf[s*channels + ch_from];
outbuf[s*channels + ch_from] = outbuf[s*channels + ch_to];
outbuf[s*channels + ch_to] = temp;
}
}
}
/* converts codec's samples (can be in any format, ex. Ogg's float32) to PCM16 */
static void convert_audio_pcm16(sample *outbuf, const uint8_t *inbuf, int fullSampleCount, int bitsPerSample, int floatingPoint) {
static void convert_audio_pcm16(sample_t *outbuf, const uint8_t *inbuf, int fullSampleCount, int bitsPerSample, int floatingPoint) {
int s;
switch (bitsPerSample) {
case 8: {
@ -495,7 +514,7 @@ fail:
}
/* decode samples of any kind of FFmpeg format */
void decode_ffmpeg(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, int channels) {
void decode_ffmpeg(VGMSTREAM *vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels) {
ffmpeg_codec_data *data = vgmstream->codec_data;
int samplesReadNow;
//todo use either channels / data->channels / codecCtx->channels
@ -656,6 +675,8 @@ end:
/* convert native sample format into PCM16 outbuf */
samplesReadNow = bytesRead / (bytesPerSample * channels);
convert_audio_pcm16(outbuf, data->sampleBuffer, samplesReadNow * channels, data->bitsPerSample, data->floatingPoint);
if (data->channel_remap_set)
remap_audio(outbuf, samplesReadNow, data->channels, data->channel_remap);
/* clean buffer when requested more samples than possible */
if (endOfAudio && samplesReadNow < samples_to_do) {
@ -808,4 +829,25 @@ void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples) {
data->skipSamples = skip_samples;
}
/* returns channel layout if set */
uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data * data) {
if (!data || !data->codecCtx) return 0;
return (uint32_t)data->codecCtx->channel_layout; /* uint64 but there ain't so many speaker mappings */
}
/* yet another hack to fix codecs that encode channels in different order and reorder on decoder
* but FFmpeg doesn't do it automatically
* (maybe should be done via mixing, but could clash with other stuff?) */
void ffmpeg_set_channel_remapping(ffmpeg_codec_data * data, int *channel_remap) {
int i;
if (data->channels > 32)
return;
for (i = 0; i < data->channels; i++) {
data->channel_remap[i] = channel_remap[i];
}
data->channel_remap_set = 1;
}
#endif

View File

@ -523,9 +523,9 @@ static size_t get_xopus_packet_size(int packet, STREAMFILE * streamfile) {
#ifdef VGM_USE_FFMPEG
static size_t custom_opus_get_samples(off_t offset, size_t data_size, STREAMFILE *streamFile, opus_type_t type) {
static size_t custom_opus_get_samples(off_t offset, size_t stream_size, STREAMFILE *streamFile, opus_type_t type) {
size_t num_samples = 0;
off_t end_offset = offset + data_size;
off_t end_offset = offset + stream_size;
int packet = 0;
if (end_offset > get_streamfile_size(streamFile)) {
@ -569,8 +569,8 @@ static size_t custom_opus_get_samples(off_t offset, size_t data_size, STREAMFILE
return num_samples;
}
size_t switch_opus_get_samples(off_t offset, size_t data_size, STREAMFILE *streamFile) {
return custom_opus_get_samples(offset, data_size, streamFile, OPUS_SWITCH);
size_t switch_opus_get_samples(off_t offset, size_t stream_size, STREAMFILE *streamFile) {
return custom_opus_get_samples(offset, stream_size, streamFile, OPUS_SWITCH);
}

View File

@ -1,7 +1,12 @@
#include "coding.h"
#ifdef VGM_USE_G719
#ifdef __MACOSX__
#include <g719/g719.h>
#else
#include <g719.h>
#endif
#define G719_MAX_CODES ((1280/8)) /* in int16, so max frame size is (value/8)*2 (0xF0=common, 0x140=decoder max 2560b, rare) */

View File

@ -130,9 +130,19 @@ void reset_hca(hca_codec_data * data) {
data->samples_to_discard = data->info.encoderDelay;
}
void loop_hca(hca_codec_data * data) {
void loop_hca(hca_codec_data * data, int32_t num_sample) {
if (!data) return;
/* manually calc loop values if not set (should only happen with installed/forced looping,
* as actual files usually pad encoder delay so earliest loopStartBlock becomes 1-2,
* probably for decoding cleanup so this may not be as exact) */
if (data->info.loopStartBlock == 0 && data->info.loopStartDelay == 0) {
int target_sample = num_sample + data->info.encoderDelay;
data->info.loopStartBlock = target_sample / data->info.samplesPerBlock;
data->info.loopStartDelay = target_sample - (data->info.loopStartBlock * data->info.samplesPerBlock);
}
data->current_block = data->info.loopStartBlock;
data->samples_filled = 0;
data->samples_consumed = 0;
@ -155,9 +165,10 @@ void free_hca(hca_codec_data * data) {
#define HCA_KEY_SCORE_SCALE 10
/* ignores beginning frames (~10 is not uncommon, Dragalia Lost vocal layers have lots) */
#define HCA_KEY_MAX_SKIP_BLANKS 1200
/* 5~15 should be enough, but almost silent or badly mastered files may need tweaks */
#define HCA_KEY_MIN_TEST_FRAMES 5
#define HCA_KEY_MAX_TEST_FRAMES 10
/* 5~15 should be enough, but almost silent or badly mastered files may need tweaks
* (ex. newer Tales of the Rays files clip a lot and need +6 as some keys give almost-ok results) */
#define HCA_KEY_MIN_TEST_FRAMES 7
#define HCA_KEY_MAX_TEST_FRAMES 12
/* score of 10~30 isn't uncommon in a single frame, too many frames over that is unlikely */
#define HCA_KEY_MAX_FRAME_SCORE 150
#define HCA_KEY_MAX_TOTAL_SCORE (HCA_KEY_MAX_TEST_FRAMES * 50*HCA_KEY_SCORE_SCALE)

View File

@ -236,6 +236,33 @@ static void ffta2_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset
if (*step_index > 88) *step_index=88;
}
/* Yet another IMA expansion, from the exe */
static void blitz_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) {
int sample_nibble, sample_decoded, step, delta;
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; /* ADPCM code */
sample_decoded = *hist1; /* predictor value */
step = ADPCMTable[*step_index]; /* current step */
/* table has 2 different values, not enough to bother adding the full table */
if (step == 22385)
step = 22358;
else if (step == 24623)
step = 24633;
delta = (sample_nibble & 0x07);
if (sample_nibble & 8) delta = -delta;
delta = (step >> 1) + delta * step; /* custom */
sample_decoded += delta;
/* somehow the exe tries to clamp hist, but actually doesn't (bug?),
* not sure if pcm buffer would be clamped outside though */
*hist1 = sample_decoded;//clamp16(sample_decoded);
*step_index += IMA_IndexTable[sample_nibble];
if (*step_index < 0) *step_index=0;
if (*step_index > 88) *step_index=88;
}
/* ************************************ */
/* DVI/IMA */
/* ************************************ */
@ -243,7 +270,7 @@ static void ffta2_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset
/* Standard DVI/IMA ADPCM (as in, ADPCM recommended by the IMA using Intel/DVI's implementation).
* Configurable: stereo or mono/interleave nibbles, and high or low nibble first.
* For vgmstream, low nibble is called "IMA ADPCM" and high nibble is "DVI IMA ADPCM" (same thing though). */
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first) {
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first) {
int i, sample_count = 0;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -271,7 +298,7 @@ void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
stream->adpcm_step_index = step_index;
}
void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -292,7 +319,7 @@ void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
stream->adpcm_step_index = step_index;
}
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -313,7 +340,7 @@ void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
stream->adpcm_step_index = step_index;
}
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -337,7 +364,7 @@ void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample *
}
/* WV6 IMA, DVI IMA with custom nibble expand */
void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -359,7 +386,7 @@ void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
}
/* ALT IMA, DVI IMA with custom nibble expand */
void decode_alp_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_alp_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -381,7 +408,7 @@ void decode_alp_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
}
/* FFTA2 IMA, DVI IMA with custom nibble expand/rounding */
void decode_ffta2_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_ffta2_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -403,6 +430,28 @@ void decode_ffta2_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspa
stream->adpcm_step_index = step_index;
}
/* Blitz IMA, IMA with custom nibble expand */
void decode_blitz_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
//external interleave
//no header
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t byte_offset = stream->offset + i/2;
int nibble_shift = (i&1?4:0); //low nibble first
blitz_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
outbuf[sample_count] = (short)(hist1);
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
}
/* ************************************ */
/* MS-IMA */
/* ************************************ */
@ -410,7 +459,7 @@ void decode_ffta2_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspa
/* IMA with custom frame sizes, header and nibble layout. Outputs an odd number of samples per frame,
* so to simplify calcs this decodes full frames, thus hist doesn't need to be mantained.
* Officially defined in "Microsoft Multimedia Standards Update" doc (RIFFNEW.pdf). */
void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, samples_read = 0, samples_done = 0, max_samples;
int32_t hist1;// = stream->adpcm_history1_32;
int step_index;// = stream->adpcm_step_index;
@ -464,7 +513,7 @@ void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * ou
}
/* Reflection's MS-IMA with custom nibble layout (some info from XA2WAV by Deniz Oezmen) */
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, samples_read = 0, samples_done = 0, max_samples;
int32_t hist1;// = stream->adpcm_history1_32;
int step_index;// = stream->adpcm_step_index;
@ -524,7 +573,7 @@ void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * o
/* MS-IMA with fixed frame size, and outputs an even number of samples per frame (skips last nibble).
* Defined in Xbox's SDK. Usable in mono or stereo modes (both suitable for interleaved multichannel). */
void decode_xbox_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo) {
void decode_xbox_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo) {
int i, frames_in, sample_pos = 0, block_samples, frame_size;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -576,7 +625,7 @@ void decode_xbox_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
}
/* Multichannel XBOX-IMA ADPCM, with all channels mixed in the same block (equivalent to multichannel MS-IMA; seen in .rsd XADP). */
void decode_xbox_ima_mch(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_xbox_ima_mch(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count = 0, num_frame;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -622,7 +671,7 @@ void decode_xbox_ima_mch(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
/* Similar to MS-IMA with even number of samples, header sample is not written (setup only).
* Apparently clamps to -32767 unlike standard's -32768 (probably not noticeable).
* Info here: http://problemkaputt.de/gbatek.htm#dssoundnotes */
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -653,7 +702,7 @@ void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
stream->adpcm_step_index = step_index;
}
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16?
int step_index = stream->adpcm_step_index;
@ -682,7 +731,7 @@ void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
stream->adpcm_step_index = step_index;
}
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -716,7 +765,7 @@ void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * ou
stream->adpcm_step_index = step_index;
}
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -748,7 +797,7 @@ void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
}
/* Apple's IMA4, a.k.a QuickTime IMA. 2 byte header and header sample is not written (setup only). */
void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count, num_frame;
int16_t hist1 = stream->adpcm_history1_16;//todo unneeded 16?
int step_index = stream->adpcm_step_index;
@ -781,7 +830,7 @@ void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelsp
}
/* XBOX-IMA with modified data layout */
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
int i, sample_count = 0;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -830,7 +879,7 @@ void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * o
}
/* mono XBOX-IMA with header endianness and alt nibble expand (per hcs's decompilation) */
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count = 0, num_frame;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -886,7 +935,7 @@ void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample *
*/
/* MS-IMA with possibly the XBOX-IMA model of even number of samples per block (more tests are needed) */
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_32;
@ -923,7 +972,7 @@ void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
/* DVI stereo/mono with some mini header and sample output */
void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count = 0;
int32_t hist1 = stream->adpcm_history1_32;
@ -948,8 +997,8 @@ void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
offset += 0x10 + 0x08;
if (version >= 3)
offset += 0x04;
//if (version >= 6) /* supposedly this exists, maybe in later BAOs */
// offset += 0x08;
if (version >= 6) /* later BAOs */
offset += 0x08;
/* write PCM samples, must be written to match header's num_samples (hist mustn't) */
max_samples_to_do = ((samples_to_do > header_samples) ? header_samples : samples_to_do);
@ -989,7 +1038,7 @@ void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
/* IMA with variable frame formats controlled by the block layout. The original code uses
* tables mapping all standard IMA combinations (to optimize calculations), but decodes the same.
* Based on HCS's and Nisto's reverse engineering in h4m_audio_decode. */
void decode_h4m_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, uint16_t frame_format) {
void decode_h4m_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, uint16_t frame_format) {
int i, samples_done = 0;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -1062,11 +1111,13 @@ void decode_h4m_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
/* ************************************************************* */
size_t ima_bytes_to_samples(size_t bytes, int channels) {
if (channels <= 0) return 0;
/* 2 samples per byte (2 nibbles) in stereo or mono config */
return bytes * 2 / channels;
}
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels) {
if (block_align <= 0 || channels <= 0) return 0;
/* MS-IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */
return (bytes / block_align) * ((block_align - 0x04*channels) * 2 / channels + 1)
+ ((bytes % block_align) ? (((bytes % block_align) - 0x04*channels) * 2 / channels + 1) : 0);
@ -1074,6 +1125,7 @@ size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels) {
size_t xbox_ima_bytes_to_samples(size_t bytes, int channels) {
int block_align = 0x24 * channels;
if (channels <= 0) return 0;
/* XBOX IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */
return (bytes / block_align) * (block_align - 4 * channels) * 2 / channels
+ ((bytes % block_align) ? ((bytes % block_align) - 4 * channels) * 2 / channels : 0); /* unlikely (encoder aligns) */
@ -1081,6 +1133,7 @@ size_t xbox_ima_bytes_to_samples(size_t bytes, int channels) {
size_t apple_ima4_bytes_to_samples(size_t bytes, int channels) {
int block_align = 0x22 * channels;
if (channels <= 0) return 0;
return (bytes / block_align) * (block_align - 0x02*channels) * 2 / channels
+ ((bytes % block_align) ? ((bytes % block_align) - 0x02*channels) * 2 / channels : 0);
}

View File

@ -78,12 +78,14 @@ int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, m
//todo: test more: this improves the output, but seems formats aren't usually prepared
// (and/or the num_samples includes all possible samples in file, so by discarding some it'll reach EOF)
// FSBs (with FMOD DLLs) don't seem to need it, even when files contain garbage at the beginning
#if 0
/* set encoder delay (samples to skip at the beginning of a stream) if needed, which varies with encoder used */
switch(data->type) {
case MPEG_AHX: data->skip_samples = 480; break; /* observed default */
case MPEG_P3D: data->skip_samples = info.frame_samples; break; /* matches Radical ADPCM (PC) output */
/* FSBs (with FMOD DLLs) don't seem to need it. Particularly a few games (all from Wayforward?)
* contain audible garbage at the beginning, but it's actually there in-game too */
case MPEG_FSB: data->skip_samples = 0;
default: break;
}
data->samples_to_discard = data->skip_samples;
@ -300,5 +302,64 @@ fail:
return 0;
}
size_t mpeg_get_samples(STREAMFILE *streamFile, off_t start_offset, size_t bytes) {
off_t offset = start_offset;
off_t max_offset = start_offset + bytes;
int samples = 0;
mpeg_frame_info info;
size_t prev_size = 0;
int cbr_count = 0;
int is_vbr = 0;
if (!streamFile)
return 0;
if (max_offset > get_streamfile_size(streamFile))
max_offset = get_streamfile_size(streamFile);
/* MPEG may use VBR so must read all frames */
while (offset < max_offset) {
/* skip ID3v2 */
if ((read_32bitBE(offset+0x00, streamFile) & 0xFFFFFF00) == 0x49443300) { /* "ID3\0" */
size_t frame_size = 0;
uint8_t flags = read_8bit(offset+0x05, streamFile);
/* this is how it's officially read :/ */
frame_size += read_8bit(offset+0x06, streamFile) << 21;
frame_size += read_8bit(offset+0x07, streamFile) << 14;
frame_size += read_8bit(offset+0x08, streamFile) << 7;
frame_size += read_8bit(offset+0x09, streamFile) << 0;
frame_size += 0x0a;
if (flags & 0x10) /* footer? */
frame_size += 0x0a;
offset += frame_size;
continue;
}
/* this may fail with unknown ID3 tags */
if (!mpeg_get_frame_info(streamFile, offset, &info))
break;
if (prev_size && prev_size != info.frame_size) {
is_vbr = 1;
}
else if (!is_vbr) {
cbr_count++;
}
if (cbr_count >= 10) {
/* must be CBR, don't bother counting */
samples = (bytes / info.frame_size) * info.frame_samples;
break;
}
offset += info.frame_size;
prev_size = info.frame_size;
samples += info.frame_samples; /* header frames may be 0? */
}
return samples;
}
#endif

View File

@ -506,7 +506,6 @@ static int ealayer3_rebuild_mpeg_frame(vgm_bitstream* is_0, ealayer3_frame_info*
is_0->b_off = eaf_0->data_offset_b;
for (i = 0; i < eaf_0->channels; i++) { /* granule0 */
for (j = 0; j < eaf_0->main_data_size[i]; j++) {
uint32_t c = 0;
r_bits(is_0, 1, &c);
w_bits(os, 1, c);
}

View File

@ -3,15 +3,19 @@
#include "../vgmstream.h"
#ifdef VGM_USE_MPEG
#ifdef __MACOSX__
#include <mpg123/mpg123.h>
#else
#include <mpg123.h>
#endif
#include "mpeg_decoder.h"
#define MPEG_DATA_BUFFER_SIZE 0x1000 /* at least one MPEG frame (max ~0x5A1 plus some more in case of free bitrate) */
static mpg123_handle * init_mpg123_handle();
static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
static void decode_mpeg_custom(VGMSTREAM * vgmstream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, sample_t * outbuf, int32_t samples_to_do, int channels);
static void decode_mpeg_custom(VGMSTREAM * vgmstream, mpeg_codec_data * data, sample_t * outbuf, int32_t samples_to_do, int channels);
static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, int num_stream);
@ -218,7 +222,7 @@ fail:
/* DECODERS */
/************/
void decode_mpeg(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels) {
void decode_mpeg(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels) {
mpeg_codec_data * data = (mpeg_codec_data *) vgmstream->codec_data;
if (!data->custom) {
@ -232,7 +236,7 @@ void decode_mpeg(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do,
* Decode anything mpg123 can.
* Feeds raw data and extracts decoded samples as needed.
*/
static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) {
static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, sample_t * outbuf, int32_t samples_to_do, int channels) {
int samples_done = 0;
mpg123_handle *m = data->m;
@ -290,7 +294,7 @@ static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * dat
* Copies to outbuf when there are samples in all streams and calls decode_mpeg_custom_stream to decode.
. Depletes the stream's sample buffers before decoding more, so it doesn't run out of buffer space.
*/
static void decode_mpeg_custom(VGMSTREAM * vgmstream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) {
static void decode_mpeg_custom(VGMSTREAM * vgmstream, mpeg_codec_data * data, sample_t * outbuf, int32_t samples_to_do, int channels) {
int i, samples_done = 0;
while (samples_done < samples_to_do) {
@ -327,7 +331,7 @@ static void decode_mpeg_custom(VGMSTREAM * vgmstream, mpeg_codec_data * data, sa
ch = 0;
for (stream = 0; stream < data->streams_size; stream++) {
mpeg_custom_stream *ms = data->streams[stream];
sample* inbuf = (sample*)ms->output_buffer;
sample_t *inbuf = (sample_t *)ms->output_buffer;
int stream_channels = ms->channels_per_frame;
int stream_ch, s;
@ -509,42 +513,37 @@ void free_mpeg(mpeg_codec_data *data) {
/* seeks stream to 0 */
void reset_mpeg(VGMSTREAM *vgmstream) {
off_t input_offset;
mpeg_codec_data *data = vgmstream->codec_data;
if (!data) return;
flush_mpeg(data);
#if 0
/* flush_mpeg properly resets mpg123 with mpg123_open_feed, and
* offsets are reset in the VGMSTREAM externally, but for posterity: */
if (!data->custom) {
off_t input_offset = 0;
mpg123_feedseek(data->m,0,SEEK_SET,&input_offset);
/* input_offset is ignored as we can assume it will be 0 for a seek to sample 0 */
}
else {
off_t input_offset = 0;
int i;
/* re-start from 0 */
for (i = 0; i < data->streams_size; i++) {
mpg123_feedseek(data->streams[i]->m,0,SEEK_SET,&input_offset);
data->streams[i]->bytes_in_buffer = 0;
data->streams[i]->buffer_full = 0;
data->streams[i]->buffer_used = 0;
data->streams[i]->samples_filled = 0;
data->streams[i]->samples_used = 0;
data->streams[i]->current_size_count = 0;
data->streams[i]->current_size_target = 0;
data->streams[i]->decode_to_discard = 0;
}
data->samples_to_discard = data->skip_samples; /* initial delay */
}
#endif
}
/* seeks to a point */
void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
off_t input_offset;
mpeg_codec_data *data = vgmstream->codec_data;
if (!data) return;
if (!data->custom) {
off_t input_offset = 0;
mpg123_feedseek(data->m, num_sample,SEEK_SET,&input_offset);
/* adjust loop with mpg123's offset (useful?) */
@ -553,31 +552,20 @@ void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
}
else {
int i;
/* re-start from 0 */
flush_mpeg(data);
/* restart from 0 and manually discard samples, since we don't really know the correct offset */
for (i = 0; i < data->streams_size; i++) {
mpg123_feedseek(data->streams[i]->m,0,SEEK_SET,&input_offset);
data->streams[i]->bytes_in_buffer = 0;
data->streams[i]->buffer_full = 0;
data->streams[i]->buffer_used = 0;
data->streams[i]->samples_filled = 0;
data->streams[i]->samples_used = 0;
data->streams[i]->current_size_count = 0;
data->streams[i]->current_size_target = 0;
data->streams[i]->decode_to_discard = 0;
//mpg123_feedseek(data->streams[i]->m,0,SEEK_SET,&input_offset); /* already reset */
/* force first offset as discard-looping needs to start from the beginning */
if (vgmstream->loop_ch)
vgmstream->loop_ch[i].offset = vgmstream->loop_ch[i].channel_start_offset;
}
/* manually discard samples, since we don't really know the correct offset */
data->samples_to_discard = num_sample;
data->samples_to_discard += data->skip_samples;
data->samples_to_discard += num_sample;
}
data->bytes_in_buffer = 0;
data->buffer_full = 0;
data->buffer_used = 0;
}
/* resets mpg123 decoder and its internals without seeking, useful when a new MPEG substream starts */

View File

@ -19,7 +19,7 @@ static const int msadpcm_coefs[7][2] = {
{ 392, -232 }
};
void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do) {
void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t first_sample, int32_t samples_to_do) {
VGMSTREAMCHANNEL *ch1,*ch2;
STREAMFILE *streamfile;
int i, frames_in;
@ -97,7 +97,7 @@ void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first
}
}
void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[channel];
int i, frames_in;
size_t bytes_per_frame, samples_per_frame;
@ -160,7 +160,7 @@ void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample * outbuf, int channelspac
/* Cricket Audio's MSADPCM, same thing with reversed hist and nibble order
* (their tools may convert to float/others but internally it's all PCM16, from debugging). */
void decode_msadpcm_ck(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_msadpcm_ck(VGMSTREAM * vgmstream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[channel];
int i, frames_in;
size_t bytes_per_frame, samples_per_frame;
@ -222,6 +222,7 @@ void decode_msadpcm_ck(VGMSTREAM * vgmstream, sample * outbuf, int channelspacin
}
long msadpcm_bytes_to_samples(long bytes, int block_size, int channels) {
if (block_size <= 0 || channels <= 0) return 0;
return (bytes / block_size) * (block_size - (7-1)*channels) * 2 / channels
+ ((bytes % block_size) ? ((bytes % block_size) - (7-1)*channels) * 2 / channels : 0);
}

View File

@ -1,7 +1,7 @@
#include "coding.h"
#include "../util.h"
/* MTA2 (EA XAS variant?) decoder based on:
/* MTA2 decoder based on:
* - MGS Developer Wiki: https://www.mgsdevwiki.com/wiki/index.php/MTA2_(Codec) [codec by daemon1]
* - Solid4 tools: https://github.com/GHzGangster/Drebin
*
@ -11,23 +11,21 @@
* * up to 16 possible tracks, but max seen is 3 (ex. track0=sneaking, track1=action, track2=ambience)
* - each ch frame is divided into 4 headers + 4 vertical groups with nibbles (0x4*4 + 0x20*4)
* ex. group1 is 0x04(4) + 0x14(4) + 0x24(4) + 0x34(4) ... (vertically maybe for paralelism?)
* - in case of "macroblock" layout, there are also headers before N tracks (like other MGS games)
*
* Due to this vertical layout and multiple hist/indexes, it decodes everything in a block between calls
* but discards unwanted data, instead of trying to skip to the target nibble. Meaning no need to save hist, and
* expects samples_to_do to be block_samples at most (could be simplified, I guess).
*
* Because of how the macroblock/track and stream's offset per channel work, they are supported by
* autodetecting and skipping when needed (ideally should keep a special layout/count, but this is simpler).
*/
static const int c1[8] = { /* mod table 1 */
/* coefs table (extended XA filters) */
static const int mta2_coefs1[8] = {
0, 240, 460, 392, 488, 460, 460, 240
};
static const int c2[8] = { /* mod table 2 */
static const int mta2_coefs2[8] = {
0, 0, -208, -220, -240, -240, -220, -104
};
static const int c3[32] = { /* shift table */
/* shift table */
static const int mta2_shifts[32] = {
256, 335, 438, 573, 749, 979, 1281, 1675,
2190, 2864, 3746, 4898, 6406, 8377, 10955, 14327,
18736, 24503, 32043, 41905, 54802, 71668, 93724, 122568,
@ -35,80 +33,31 @@ static const int c3[32] = { /* shift table */
};
/* expands nibble */
static short calculate_output(int nibble, short smp1, short smp2, int mod, int sh) {
static short mta2_expand_nibble(int nibble, short hist1, short hist2, int coef_index, int shift_index) {
int output;
if (nibble > 7) /* sign extend */
nibble = nibble - 16;
output = (smp1 * c1[mod] + smp2 * c2[mod] + (nibble * c3[sh]) + 128) >> 8;
output = (hist1 * mta2_coefs1[coef_index] + hist2 * mta2_coefs2[coef_index] + (nibble * mta2_shifts[shift_index]) + 128) >> 8;
output = clamp16(output);
return (short)output;
}
/* autodetect and skip "macroblocks" */
static void mta2_block_update(VGMSTREAMCHANNEL * stream) {
int block_type, block_size, block_tracks, repeat = 1;
/* may need to skip N empty blocks */
do {
block_type = read_32bitBE(stream->offset + 0x00, stream->streamfile);
block_size = read_32bitBE(stream->offset + 0x04, stream->streamfile); /* including this header */
/* 0x08: always null */
block_tracks = read_32bitBE(stream->offset + 0x0c, stream->streamfile); /* total tracks of variable size (can be 0) */
/* 0x10001: music, 0x20001: sfx?, 0xf0: loop control (goes at the end) */
if (block_type != 0x00010001 && block_type != 0x00020001 && block_type != 0x000000F0)
return; /* not a block */
/* frame=010001+00/etc can be mistaken as block_type, do extra checks */
{
int i, track_channels = 0;
uint16_t channel_layout = (block_size >> 16);
uint16_t track_size = (block_size & 0xFFFF);
/* has chanel layout == may be a track */
if (channel_layout > 0 && channel_layout <= 0xFF) {
for (i = 0; i < 8; i++) {
if ((channel_layout >> i) & 0x01)
track_channels++;
}
if (track_channels*0x90 == track_size)
return;
}
}
if (block_size <= 0 || block_tracks < 0) { /* nonsense block (maybe at EOF) */
VGM_LOG("MTA2: bad block @ 0x%x\n", (uint32_t)stream->offset);
stream->offset += 0x10;
repeat = 0;
}
else if (block_tracks == 0) { /* empty block (common), keep repeating */
stream->offset += block_size;
}
else { /* normal block, position into next track header */
stream->offset += 0x10;
repeat = 0;
}
} while (repeat);
}
/* decodes a block for a channel, skipping macroblocks/tracks if needed */
void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
/* decodes a block for a channel */
void decode_mta2(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int samples_done = 0, sample_count = 0, channel_block_samples, channel_first_sample, frame_size = 0;
int i, group, row, col;
int track_channels = 0, track_channel;
/* block/track skip */
/* track skip */
do {
int num_track = 0, channel_layout;
/* autodetect and skip macroblock header */
mta2_block_update(stream);
/* parse track header (0x10) and skip tracks that our current channel doesn't belong to */
num_track = read_8bit(stream->offset+0x00,stream->streamfile); /* 0=first */
/* 0x01(3): num_frame (0=first), 0x04(1): 0? */
/* 0x01(3): num_frame (0=first) */
/* 0x04(1): 0? */
channel_layout = read_8bit(stream->offset+0x05,stream->streamfile); /* bitmask, see mta2.c */
frame_size = read_16bitBE(stream->offset+0x06,stream->streamfile); /* not including this header */
/* 0x08(8): null */
@ -151,22 +100,22 @@ void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
/* parse channel frame (header 0x04*4 + data 0x20*4) */
for (group = 0; group < 4; group++) {
short smp2, smp1, mod, sh, output;
short hist2, hist1, coefs, shift, output;
int group_header = read_32bitBE(stream->offset + 0x10 + track_channel*0x90 + group*0x4, stream->streamfile);
smp2 = (short) ((group_header >> 16) & 0xfff0); /* upper 16b discarding 4b */
smp1 = (short) ((group_header >> 4) & 0xfff0); /* lower 16b discarding 4b */
mod = (group_header >> 5) & 0x7; /* mid 3b */
sh = group_header & 0x1f; /* lower 5b */
hist2 = (short) ((group_header >> 16) & 0xfff0); /* upper 16b discarding 4b */
hist1 = (short) ((group_header >> 4) & 0xfff0); /* lower 16b discarding 4b */
coefs = (group_header >> 5) & 0x7; /* mid 3b */
shift = group_header & 0x1f; /* lower 5b */
/* write header samples (skips the last 2 group nibbles), like Drebin's decoder
* last 2 nibbles and next 2 header hist should match though */
if (sample_count >= channel_first_sample && samples_done < samples_to_do) {
outbuf[samples_done * channelspacing] = smp2;
outbuf[samples_done * channelspacing] = hist2;
samples_done++;
}
sample_count++;
if (sample_count >= channel_first_sample && samples_done < samples_to_do) {
outbuf[samples_done * channelspacing] = smp1;
outbuf[samples_done * channelspacing] = hist1;
samples_done++;
}
sample_count++;
@ -175,7 +124,7 @@ void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
for (col = 0; col < 4*2; col++) {
uint8_t nibbles = read_8bit(stream->offset + 0x10 + 0x10 + track_channel*0x90 + group*0x4 + row*0x10 + col/2, stream->streamfile);
int nibble_shift = (!(col&1) ? 4 : 0); /* upper first */
output = calculate_output((nibbles >> nibble_shift) & 0xf, smp1, smp2, mod, sh);
output = mta2_expand_nibble((nibbles >> nibble_shift) & 0xf, hist1, hist2, coefs, shift);
/* ignore last 2 nibbles (uses first 2 header samples) */
if (row < 7 || col < 3*2) {
@ -186,8 +135,8 @@ void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
sample_count++;
}
smp2 = smp1;
smp1 = output;
hist2 = hist1;
hist1 = output;
}
}
}

View File

@ -1,15 +1,11 @@
#include "coding.h"
#include "../util.h"
#define MTAF_BLOCK_SUPPORT
/* A hybrid of IMA and Yamaha ADPCM found in Metal Gear Solid 3
* Thanks to X_Tra (http://metalgear.in/) for pointing me to the step size table.
*
* Layout: N tracks of 0x10 header + 0x80*2 (always 2ch; multichannels uses 4ch = 2ch track0 + 2ch track1 xN)
* "macroblocks" support is not really needed as the extractors should remove them but they are
* autodetected and skipped if found (ideally should keep a special layout/count, but this is simpler).
* Layout: N tracks of 0x10 header + 0x80*2 (always 2ch; multichannels uses 4ch = 2ch track0 + 2ch track1 xN).
*/
static const int index_table[16] = {
@ -84,48 +80,8 @@ static const int16_t step_size[32][16] = {
-424, -1273, -2121, -2970, -3819, -4668, -5516, -6365, },
};
#ifdef MTAF_BLOCK_SUPPORT
/* autodetect and skip "macroblocks" */
static void mtaf_block_update(VGMSTREAMCHANNEL * stream) {
int block_type, block_size, block_empty, block_tracks, repeat = 1;
do {
block_type = read_32bitLE(stream->offset+0x00, stream->streamfile);
block_size = read_32bitLE(stream->offset+0x04, stream->streamfile); /* including this header */
block_empty = read_32bitLE(stream->offset+0x08, stream->streamfile); /* always 0 */
block_tracks = read_32bitLE(stream->offset+0x0c, stream->streamfile); /* total tracks of 0x110 (can be 0)*/
/* 0x110001: music (type 0x11=adpcm), 0xf0: loop control (goes at the end) */
if ((block_type != 0x00110001 && block_type != 0x000000F0) || block_empty != 0)
return; /* not a block */
/* track=001100+01 could be mistaken as block_type, do extra checks */
{
int track = read_8bit(stream->offset+0x10, stream->streamfile);
if (track != 0 && track != 1)
return; /* if this is a block, next header should be from track 0/1 */
if (block_tracks > 0 && (block_size-0x10) != block_tracks*0x110)
return; /* wrong expected size */
}
if (block_size <= 0 || block_tracks < 0) { /* nonsense block (maybe at EOF) */
VGM_LOG("MTAF: bad block @ %x\n", (uint32_t)stream->offset);
stream->offset += 0x10;
repeat = 0;
}
else if (block_tracks == 0) { /* empty block (common), keep repeating */
stream->offset += block_size;
}
else { /* normal block, position into next track header */
stream->offset += 0x10;
repeat = 0;
}
} while(repeat);
}
#endif
void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_mtaf(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int32_t sample_count;
int i;
int c = channel%2; /* global channel to track channel */
@ -133,11 +89,6 @@ void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
int32_t step_idx = stream->adpcm_step_index;
#ifdef MTAF_BLOCK_SUPPORT
/* autodetect and skip macroblock header */
mtaf_block_update(stream);
#endif
/* read header when we hit a new track every 0x100 samples */
first_sample = first_sample % 0x100;

View File

@ -1,7 +1,7 @@
#include "coding.h"
#include "../util.h"
void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i=first_sample;
int32_t sample_count;
@ -37,7 +37,7 @@ void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
}
/* read from memory rather than a file */
static void decode_ngc_dsp_subint_internal(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, uint8_t * mem) {
static void decode_ngc_dsp_subint_internal(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, uint8_t * mem) {
int i=first_sample;
int32_t sample_count;
@ -71,7 +71,7 @@ static void decode_ngc_dsp_subint_internal(VGMSTREAMCHANNEL * stream, sample * o
}
/* decode DSP with byte-interleaved frames (ex. 0x08: 1122112211221122) */
void decode_ngc_dsp_subint(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int interleave) {
void decode_ngc_dsp_subint(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int interleave) {
uint8_t sample_data[0x08];
int i;
@ -100,21 +100,12 @@ int32_t dsp_nibbles_to_samples(int32_t nibbles) {
int32_t whole_frames = nibbles/16;
int32_t remainder = nibbles%16;
/*
fprintf(stderr,"%d (%#x) nibbles => %x bytes and %d samples\n",nibbles,nibbles,whole_frames*8,remainder);
*/
#if 0
if (remainder > 0 && remainder < 14)
return whole_frames*14 + remainder;
else if (remainder >= 14)
fprintf(stderr,"***** last frame %d leftover nibbles makes no sense\n",remainder);
#endif
if (remainder>0) return whole_frames*14+remainder-2;
else return whole_frames*14;
}
size_t dsp_bytes_to_samples(size_t bytes, int channels) {
if (channels <= 0) return 0;
return bytes / channels / 8 * 14;
}

View File

@ -1,55 +1,121 @@
#include <math.h>
#include "coding.h"
#include "../util.h"
#ifdef VGM_USE_VORBIS
#include <vorbis/vorbisfile.h>
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) {
static void pcm_convert_float_to_16(int channels, sample_t * outbuf, int samples_to_do, float ** pcm, int disable_ordering);
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample_t * outbuf, int32_t samples_to_do, int channels) {
int samples_done = 0;
OggVorbis_File *ogg_vorbis_file = &data->ogg_vorbis_file;
long rc;
float **pcm_channels; /* pointer to Xiph's double array buffer */
do {
long rc = ov_read(ogg_vorbis_file, (char *)(outbuf + samples_done*channels),
(samples_to_do - samples_done)*sizeof(sample)*channels, 0,
sizeof(sample), 1, &data->bitstream);
while (samples_done < samples_to_do) {
rc = ov_read_float(
&data->ogg_vorbis_file, /* context */
&pcm_channels, /* buffer pointer */
(samples_to_do - samples_done), /* samples to produce */
&data->bitstream); /* bitstream*/
if (rc <= 0) goto fail; /* rc is samples done */
if (rc > 0) samples_done += rc/sizeof(sample)/channels;
else return;
} while (samples_done < samples_to_do);
pcm_convert_float_to_16(channels, outbuf, rc, pcm_channels, data->disable_reordering);
swap_samples_le(outbuf, samples_to_do*channels);
outbuf += rc * channels;
samples_done += rc;
#if 0 // alt decoding
/* we use ov_read_float as to reuse the xiph's buffer for easier remapping,
* but seems ov_read is slightly faster due to optimized (asm) float-to-int. */
rc = ov_read(
&data->ogg_vorbis_file, /* context */
(char *)(outbuf), /* buffer */
(samples_to_do - samples_done) * sizeof(sample_t) * channels, /* length in bytes */
0, /* pcm endianness */
sizeof(sample), /* pcm size */
1, /* pcm signedness */
&data->bitstream); /* bitstream */
if (rc <= 0) goto fail; /* rc is bytes done (for all channels) */
swap_samples_le(outbuf, rc / sizeof(sample_t)); /* endianness is a bit weird with ov_read though */
outbuf += rc / sizeof(sample_t);
samples_done += rc / sizeof(sample_t) / channels;
#endif
}
return;
fail:
VGM_LOG("OGG: error %lx during decode\n", rc);
memset(outbuf, 0, (samples_to_do - samples_done) * channels * sizeof(sample));
}
/* vorbis encodes channels in non-standard order, so we remap during conversion to fix this oddity.
* (feels a bit weird as one would think you could leave as-is and set the player's output
* order, but that isn't possible and remapping is what FFmpeg and every other plugin do). */
static const int xiph_channel_map[8][8] = {
{ 0 }, /* 1ch: FC > same */
{ 0, 1 }, /* 2ch: FL FR > same */
{ 0, 2, 1 }, /* 3ch: FL FC FR > FL FR FC */
{ 0, 1, 2, 3 }, /* 4ch: FL FR BL BR > same */
{ 0, 2, 1, 3, 4 }, /* 5ch: FL FC FR BL BR > FL FR FC BL BR */
{ 0, 2, 1, 5, 3, 4 }, /* 6ch: FL FC FR BL BR LFE > FL FR FC LFE BL BR */
{ 0, 2, 1, 6, 5, 3, 4 }, /* 7ch: FL FC FR SL SR BC LFE > FL FR FC LFE BC SL SR */
{ 0, 2, 1, 7, 5, 6, 3, 4 }, /* 8ch: FL FC FR SL SR BL BR LFE > FL FR FC LFE BL BR SL SR */
};
void reset_ogg_vorbis(VGMSTREAM *vgmstream) {
OggVorbis_File *ogg_vorbis_file;
ogg_vorbis_codec_data *data = vgmstream->codec_data;
if (!data) return;
/* converts from internal Vorbis format to standard PCM and remaps (mostly from Xiph's decoder_example.c) */
static void pcm_convert_float_to_16(int channels, sample_t * outbuf, int samples_to_do, float ** pcm, int disable_ordering) {
int ch, s, ch_map;
sample_t *ptr;
float *channel;
ogg_vorbis_file = &(data->ogg_vorbis_file);
/* convert float PCM (multichannel float array, with pcm[0]=ch0, pcm[1]=ch1, pcm[2]=ch0, etc)
* to 16 bit signed PCM ints (host order) and interleave + fix clipping */
for (ch = 0; ch < channels; ch++) {
ch_map = disable_ordering ?
ch :
(channels > 8) ? ch : xiph_channel_map[channels - 1][ch]; /* put Vorbis' ch to other outbuf's ch */
ptr = outbuf + ch;
channel = pcm[ch_map];
for (s = 0; s < samples_to_do; s++) {
int val = (int)floor(channel[s] * 32767.0f + 0.5f); /* use floorf? doesn't seem any faster */
if (val > 32767) val = 32767;
else if (val < -32768) val = -32768;
ov_pcm_seek(ogg_vorbis_file, 0);
}
void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) {
OggVorbis_File *ogg_vorbis_file;
ogg_vorbis_codec_data *data = (ogg_vorbis_codec_data *)(vgmstream->codec_data);
if (!data) return;
ogg_vorbis_file = &(data->ogg_vorbis_file);
ov_pcm_seek_lap(ogg_vorbis_file, num_sample);
}
void free_ogg_vorbis(ogg_vorbis_codec_data *data) {
if (data) {
OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
ov_clear(ogg_vorbis_file);
close_streamfile(data->ov_streamfile.streamfile);
free(data);
*ptr = val;
ptr += channels;
}
}
}
/* ********************************************** */
void reset_ogg_vorbis(VGMSTREAM *vgmstream) {
ogg_vorbis_codec_data *data = vgmstream->codec_data;
if (!data) return;
ov_pcm_seek(&data->ogg_vorbis_file, 0);
}
void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) {
ogg_vorbis_codec_data *data = vgmstream->codec_data;
if (!data) return;
ov_pcm_seek_lap(&data->ogg_vorbis_file, num_sample);
}
void free_ogg_vorbis(ogg_vorbis_codec_data *data) {
if (!data) return;
ov_clear(&data->ogg_vorbis_file);
close_streamfile(data->ov_streamfile.streamfile);
free(data);
}
#endif

View File

@ -87,7 +87,7 @@ static void oki16_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, in
* so it's needs GENH/TXTH. Sample rate can only be base_value divided by 1/2/3/4, where
* base_value is approximately ~31468.5 (follows hardware clocks), mono or interleaved for stereo.
*/
void decode_pcfx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int mode) {
void decode_pcfx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int mode) {
int i, sample_count = 0;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -108,7 +108,7 @@ void decode_pcfx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
/* OKI variation with 16-bit output (vs standard's 12-bit), found in FrontWing's PS2 games (Sweet Legacy, Hooligan).
* Reverse engineered from the ELF with help from the folks at hcs. */
void decode_oki16(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_oki16(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count = 0;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -140,6 +140,7 @@ void decode_oki16(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing
size_t oki_bytes_to_samples(size_t bytes, int channels) {
if (channels <= 0) return 0;
/* 2 samples per byte (2 nibbles) in stereo or mono config */
return bytes * 2 / channels;
}

View File

@ -2,7 +2,7 @@
#include "../util.h"
#include <math.h>
void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i;
int32_t sample_count;
@ -11,7 +11,7 @@ void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
}
}
void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i;
int32_t sample_count;
@ -20,7 +20,7 @@ void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
}
}
void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) {
void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) {
int i, sample_count;
int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE;
@ -29,7 +29,7 @@ void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspa
}
}
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i;
int32_t sample_count;
@ -38,7 +38,7 @@ void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
}
}
void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i;
int32_t sample_count;
@ -47,7 +47,7 @@ void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
}
}
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i;
int32_t sample_count;
@ -57,7 +57,7 @@ void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channe
}
}
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i;
int32_t sample_count;
@ -67,7 +67,7 @@ void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int ch
}
}
void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i;
int32_t sample_count;
@ -78,7 +78,7 @@ void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
}
}
void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, nibble_shift, is_high_first, is_stereo;
int32_t sample_count;
int16_t v;
@ -101,7 +101,7 @@ void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outb
}
}
void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, nibble_shift, is_high_first, is_stereo;
int32_t sample_count;
int16_t v;
@ -125,7 +125,7 @@ void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, samp
}
static int expand_ulaw(uint8_t ulawbyte) {
int sign, segment, quantization, new_sample;
int sign, segment, quantization, sample;
const int bias = 0x84;
ulawbyte = ~ulawbyte; /* stored in complement */
@ -133,9 +133,9 @@ static int expand_ulaw(uint8_t ulawbyte) {
segment = (ulawbyte & 0x70) >> 4; /* exponent */
quantization = ulawbyte & 0x0F; /* mantissa */
new_sample = (quantization << 3) + bias; /* add bias */
new_sample <<= segment;
new_sample = (sign) ? (bias - new_sample) : (new_sample - bias); /* remove bias */
sample = (quantization << 3) + bias; /* add bias */
sample <<= segment;
sample = (sign) ? (bias - sample) : (sample - bias); /* remove bias */
#if 0 // the above follows Sun's implementation, but this works too
{
@ -145,11 +145,11 @@ static int expand_ulaw(uint8_t ulawbyte) {
}
#endif
return new_sample;
return sample;
}
/* decodes u-law (ITU G.711 non-linear PCM), from g711.c */
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
@ -159,7 +159,7 @@ void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
}
void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
@ -169,33 +169,33 @@ void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
}
static int expand_alaw(uint8_t alawbyte) {
int sign, segment, quantization, new_sample;
int sign, segment, quantization, sample;
alawbyte ^= 0x55;
sign = (alawbyte & 0x80);
segment = (alawbyte & 0x70) >> 4; /* exponent */
quantization = alawbyte & 0x0F; /* mantissa */
new_sample = (quantization << 4);
sample = (quantization << 4);
switch (segment) {
case 0:
new_sample += 8;
sample += 8;
break;
case 1:
new_sample += 0x108;
sample += 0x108;
break;
default:
new_sample += 0x108;
new_sample <<= segment - 1;
sample += 0x108;
sample <<= segment - 1;
break;
}
new_sample = (sign) ? new_sample : -new_sample;
sample = (sign) ? sample : -sample;
return new_sample;
return sample;
}
/* decodes a-law (ITU G.711 non-linear PCM), from g711.c */
void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_alaw(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
@ -204,7 +204,7 @@ void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
}
}
void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) {
void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) {
int i, sample_count;
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
@ -221,5 +221,6 @@ void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
}
size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample) {
return (bytes * 8) / channels / bits_per_sample;
if (channels <= 0 || bits_per_sample <= 0) return 0;
return ((int64_t)bytes * 8) / channels / bits_per_sample;
}

View File

@ -43,7 +43,7 @@ static const int ps_adpcm_coefs_i[5][2] = {
*/
/* standard PS-ADPCM (float math version) */
void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int is_badflags) {
void decode_psx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int is_badflags) {
off_t frame_offset;
int i, frames_in, sample_count = 0;
size_t bytes_per_frame, samples_per_frame;
@ -75,24 +75,24 @@ void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
/* decode nibbles */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
int32_t new_sample = 0;
int32_t sample = 0;
if (flag < 0x07) { /* with flag 0x07 decoded sample must be 0 */
uint8_t nibbles = (uint8_t)read_8bit(frame_offset+0x02+i/2,stream->streamfile);
new_sample = i&1 ? /* low nibble first */
sample = i&1 ? /* low nibble first */
(nibbles >> 4) & 0x0f :
(nibbles >> 0) & 0x0f;
new_sample = (int16_t)((new_sample << 12) & 0xf000) >> shift_factor; /* 16b sign extend + scale */
new_sample = (int)(new_sample + ps_adpcm_coefs_f[coef_index][0]*hist1 + ps_adpcm_coefs_f[coef_index][1]*hist2);
new_sample = clamp16(new_sample);
sample = (int16_t)((sample << 12) & 0xf000) >> shift_factor; /* 16b sign extend + scale */
sample = (int)(sample + ps_adpcm_coefs_f[coef_index][0]*hist1 + ps_adpcm_coefs_f[coef_index][1]*hist2);
sample = clamp16(sample);
}
outbuf[sample_count] = new_sample;
outbuf[sample_count] = sample;
sample_count += channelspacing;
hist2 = hist1;
hist1 = new_sample;
hist1 = sample;
}
stream->adpcm_history1_32 = hist1;
@ -104,7 +104,7 @@ void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
* Found in some PC/PS3 games (FF XI in sizes 3/5/9/41, Afrika in size 4, Blur/James Bond in size 33, etc).
*
* Uses int math to decode, which seems more likely (based on FF XI PC's code in Moogle Toolbox). */
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size) {
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size) {
off_t frame_offset;
int i, frames_in, sample_count = 0;
size_t bytes_per_frame, samples_per_frame;
@ -131,21 +131,21 @@ void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int cha
/* decode nibbles */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
int32_t new_sample = 0;
int32_t sample = 0;
uint8_t nibbles = (uint8_t)read_8bit(frame_offset+0x01+i/2,stream->streamfile);
new_sample = i&1 ? /* low nibble first */
sample = i&1 ? /* low nibble first */
(nibbles >> 4) & 0x0f :
(nibbles >> 0) & 0x0f;
new_sample = (int16_t)((new_sample << 12) & 0xf000) >> shift_factor; /* 16b sign extend + scale */
new_sample = new_sample + ((ps_adpcm_coefs_i[coef_index][0]*hist1 + ps_adpcm_coefs_i[coef_index][1]*hist2) >> 6);
new_sample = clamp16(new_sample);
sample = (int16_t)((sample << 12) & 0xf000) >> shift_factor; /* 16b sign extend + scale */
sample = sample + ((ps_adpcm_coefs_i[coef_index][0]*hist1 + ps_adpcm_coefs_i[coef_index][1]*hist2) >> 6);
sample = clamp16(sample);
outbuf[sample_count] = new_sample;
outbuf[sample_count] = sample;
sample_count += channelspacing;
hist2 = hist1;
hist1 = new_sample;
hist1 = sample;
}
stream->adpcm_history1_32 = hist1;
@ -176,6 +176,9 @@ static int ps_find_loop_offsets_internal(STREAMFILE *streamFile, off_t start_off
int detect_full_loops = config & 1;
if (data_size == 0 || channels == 0 || (channels > 0 && interleave == 0))
return 0;
while (offset < max_offset) {
uint8_t flag = (uint8_t)read_8bit(offset+0x01,streamFile) & 0x0F; /* lower nibble only (for HEVAG) */
@ -268,7 +271,70 @@ int ps_find_loop_offsets_full(STREAMFILE *streamFile, off_t start_offset, size_t
return ps_find_loop_offsets_internal(streamFile, start_offset, data_size, channels, interleave, out_loop_start, out_loop_end, 1);
}
size_t ps_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int discard_empty) {
off_t min_offset, offset;
size_t frame_size = 0x10;
size_t padding_size = 0;
size_t interleave_consumed = 0;
if (data_size == 0 || channels == 0 || (channels > 0 && interleave == 0))
return 0;
offset = start_offset + data_size;
/* in rare cases (ex. Gitaroo Man) channels have inconsistent empty padding, use first as guide */
offset = offset - interleave * (channels - 1);
/* some files have padding spanning multiple interleave blocks */
min_offset = start_offset; //offset - interleave;
while (offset > min_offset) {
uint32_t f1,f2,f3,f4;
uint8_t flag;
int is_empty = 0;
offset -= frame_size;
f1 = read_32bitBE(offset+0x00,streamFile);
f2 = read_32bitBE(offset+0x04,streamFile);
f3 = read_32bitBE(offset+0x08,streamFile);
f4 = read_32bitBE(offset+0x0c,streamFile);
flag = (f1 >> 16) & 0xFF;
if (f1 == 0 && f2 == 0 && f3 == 0 && f4 == 0)
is_empty = 1;
if (!is_empty && discard_empty) {
if (flag == 0x07 || flag == 0x77)
is_empty = 1; /* 'discard frame' flag */
else if ((f1 & 0xFF00FFFF) == 0 && f2 == 0 && f3 == 0 && f4 == 0)
is_empty = 1; /* silent with flags (typical for looping files) */
else if ((f1 & 0xFF00FFFF) == 0x0C000000 && f2 == 0 && f3 == 0 && f4 == 0)
is_empty = 1; /* silent (maybe shouldn't ignore flag 0x03?) */
else if ((f1 & 0x0000FFFF) == 0x00007777 && f2 == 0x77777777 && f3 ==0x77777777 && f4 == 0x77777777)
is_empty = 1; /* silent-ish */
}
if (!is_empty)
break;
padding_size += frame_size * channels;
/* skip other channels */
interleave_consumed += 0x10;
if (interleave_consumed == interleave) {
interleave_consumed = 0;
offset -= interleave*(channels - 1);
}
}
return padding_size;
}
size_t ps_bytes_to_samples(size_t bytes, int channels) {
if (channels <= 0) return 0;
return bytes / channels / 0x10 * 28;
}

View File

@ -7,7 +7,7 @@
#define VORBIS_DEFAULT_BUFFER_SIZE 0x8000 /* should be at least the size of the setup header, ~0x2000 */
static void pcm_convert_float_to_16(vorbis_custom_codec_data * data, sample * outbuf, int samples_to_do, float ** pcm);
static void pcm_convert_float_to_16(int channels, sample_t * outbuf, int samples_to_do, float ** pcm);
/**
* Inits a vorbis stream of some custom variety.
@ -75,7 +75,7 @@ fail:
}
/* Decodes Vorbis packets into a libvorbis sample buffer, and copies them to outbuf */
void decode_vorbis_custom(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels) {
void decode_vorbis_custom(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
vorbis_custom_codec_data * data = vgmstream->codec_data;
size_t stream_size = get_streamfile_size(stream->streamfile);
@ -112,7 +112,7 @@ void decode_vorbis_custom(VGMSTREAM * vgmstream, sample * outbuf, int32_t sample
/* get max samples and convert from Vorbis float pcm to 16bit pcm */
if (samples_to_get > samples_to_do - samples_done)
samples_to_get = samples_to_do - samples_done;
pcm_convert_float_to_16(data, outbuf + samples_done * channels, samples_to_get, pcm);
pcm_convert_float_to_16(data->vi.channels, outbuf + samples_done * channels, samples_to_get, pcm);
samples_done += samples_to_get;
}
@ -167,21 +167,24 @@ decode_fail:
}
/* converts from internal Vorbis format to standard PCM (mostly from Xiph's decoder_example.c) */
static void pcm_convert_float_to_16(vorbis_custom_codec_data * data, sample * outbuf, int samples_to_do, float ** pcm) {
int i,j;
static void pcm_convert_float_to_16(int channels, sample_t * outbuf, int samples_to_do, float ** pcm) {
int ch, s;
sample_t *ptr;
float *channel;
/* convert float PCM (multichannel float array, with pcm[0]=ch0, pcm[1]=ch1, pcm[2]=ch0, etc)
* to 16 bit signed PCM ints (host order) and interleave + fix clipping */
for (i = 0; i < data->vi.channels; i++) {
sample *ptr = outbuf + i;
float *mono = pcm[i];
for (j = 0; j < samples_to_do; j++) {
int val = (int)floor(mono[j] * 32767.f + .5f);
for (ch = 0; ch < channels; ch++) {
/* channels should be in standard order unlike Ogg Vorbis (at least in FSB) */
ptr = outbuf + ch;
channel = pcm[ch];
for (s = 0; s < samples_to_do; s++) {
int val = (int)floor(channel[s] * 32767.0f + 0.5f);
if (val > 32767) val = 32767;
if (val < -32768) val = -32768;
else if (val < -32768) val = -32768;
*ptr = val;
ptr += data->vi.channels;
ptr += channels;
}
}
}

View File

@ -8,6 +8,11 @@ static const unsigned int scale_step[16] = {
230, 230, 230, 230, 307, 409, 512, 614
};
/* actually implemented with if-else/switchs but that's too goofy */
static const int scale_step_aska[8] = {
57, 57, 57, 57, 77, 102, 128, 153,
};
/* expand an unsigned four bit delta to a wider signed range */
static const int scale_delta[16] = {
1, 3, 5, 7, 9, 11, 13, 15,
@ -15,8 +20,9 @@ static const int scale_delta[16] = {
};
/* raw Yamaha ADPCM a.k.a AICA as it's mainly used in Naomi/Dreamcast (also in RIFF and older arcade sound chips). */
void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo) {
/* raw Yamaha ADPCM a.k.a AICA as it's prominently used in Naomi/Dreamcast's Yamaha AICA sound chip,
* also found in Windows RIFF and older Yamaha's arcade sound chips. */
void decode_yamaha(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_16;
@ -52,9 +58,8 @@ void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
stream->adpcm_step_index = step_size;
}
/* Yamaha ADPCM, in headered frames like MS-IMA. Possibly originated from Yamaha's SMAF tools
* (Windows ACM encoder/decoder was given in their site). Some info from Rockbox's yamaha_adpcm.c */
void decode_yamaha(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
/* tri-Ace Aska ADPCM, same-ish with modified step table (reversed from Android SO's .so) */
void decode_aska(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count, num_frame;
int32_t hist1 = stream->adpcm_history1_32;
int step_size = stream->adpcm_step_index;
@ -84,15 +89,15 @@ void decode_yamaha(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacin
(!(channel&1) ? 0:4) :
(!(i&1) ? 0:4); /* even = low, odd = high */
/* Yamaha/AICA expand, but same result as IMA's (((delta * 2 + 1) * step) >> 3) */
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
sample_delta = (step_size * scale_delta[sample_nibble]) / 8;
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift) & 0xf;
sample_delta = ((((sample_nibble & 0x7) * 2) | 1) * step_size) >> 3; /* like 'mul' IMA with 'or' */
if (sample_nibble & 8) sample_delta = -sample_delta;
sample_decoded = hist1 + sample_delta;
outbuf[sample_count] = clamp16(sample_decoded);
outbuf[sample_count] = sample_decoded; /* not clamped */
hist1 = outbuf[sample_count];
step_size = (step_size * scale_step[sample_nibble]) >> 8;
step_size = (step_size * scale_step_aska[sample_nibble & 0x07]) >> 6;
if (step_size < 0x7f) step_size = 0x7f;
if (step_size > 0x6000) step_size = 0x6000;
}
@ -102,7 +107,7 @@ void decode_yamaha(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacin
}
/* Yamaha ADPCM with unknown expand variation (noisy), step size is double of normal Yamaha? */
void decode_yamaha_nxap(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_nxap(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count, num_frame;
int32_t hist1 = stream->adpcm_history1_32;
int step_size = stream->adpcm_step_index;
@ -145,14 +150,15 @@ void decode_yamaha_nxap(VGMSTREAMCHANNEL * stream, sample * outbuf, int channels
stream->adpcm_step_index = step_size;
}
size_t aica_bytes_to_samples(size_t bytes, int channels) {
size_t yamaha_bytes_to_samples(size_t bytes, int channels) {
if (channels <= 0) return 0;
/* 2 samples per byte (2 nibbles) in stereo or mono config */
return bytes * 2 / channels;
}
size_t yamaha_bytes_to_samples(size_t bytes, int channels) {
size_t aska_bytes_to_samples(size_t bytes, int channels) {
int block_align = 0x40;
if (channels <= 0) return 0;
return (bytes / block_align) * (block_align - 0x04*channels) * 2 / channels
+ ((bytes % block_align) ? ((bytes % block_align) - 0x04*channels) * 2 / channels : 0);
}

View File

@ -18,6 +18,7 @@ static const char* extension_list[] = {
"2dx9",
"2pfs",
"800",
"9tav",
//"aac", //common
"aa3", //FFmpeg/not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
@ -42,6 +43,7 @@ static const char* extension_list[] = {
"ahv",
"ai",
//"aif", //common
"aif-Loop",
"aifc", //common?
"aifcl", //fake extension for .aif???
//"aiff", //common
@ -71,6 +73,7 @@ static const char* extension_list[] = {
"b1s",
"baf",
"baka",
"bank",
"bar",
"bcstm",
"bcwav",
@ -90,6 +93,7 @@ static const char* extension_list[] = {
"bmdx",
"bms",
"bnk",
"bnm",
"bns",
"bnsf",
"bo2",
@ -123,6 +127,7 @@ static const char* extension_list[] = {
"de2",
"dec",
"dmsg",
"ds2", //txth/reserved [Star Wars Bounty Hunter (GC)]
"dsf",
"dsp",
"dspw",
@ -183,6 +188,7 @@ static const char* extension_list[] = {
"idx",
"ikm",
"ild",
"ilv", //txth/reserved [Star Wars Episode III (PS2)]
"imc",
"int",
"isd",
@ -208,6 +214,9 @@ static const char* extension_list[] = {
"l",
"laac", //fake extension for .aac (tri-Ace)
"laif", //fake extension for .aif (various)
"laiff", //fake extension for .aiff
"laifc", //fake extension for .aifc
"lac3", //fake extension for .ac3, FFmpeg/not parsed
"lasf", //fake extension for .asf (various)
"leg",
@ -366,7 +375,6 @@ static const char* extension_list[] = {
"sbin",
"sc",
"scd",
"sck",
"sd9",
"sdf",
"sdt",
@ -421,11 +429,13 @@ static const char* extension_list[] = {
"sx",
"sxd",
"sxd2",
"sxd3",
"tec",
"tgq",
"thp",
"tk5",
"tmx",
"tra",
"tun",
"txth",
@ -456,7 +466,9 @@ static const char* extension_list[] = {
"vig",
"vis",
"vms",
"vmu", //txth/reserved [Red Faction (PS2)]
"voi",
"vp6",
"vpk",
"vs",
"vsf",
@ -498,6 +510,7 @@ static const char* extension_list[] = {
"xa30",
"xag",
"xau",
"xen",
"xma",
"xma2",
"xmu",
@ -608,6 +621,7 @@ static const coding_info coding_info_list[] = {
{coding_WV6_IMA, "Gorilla Systems WV6 4-bit IMA ADPCM"},
{coding_ALP_IMA, "High Voltage ALP 4-bit IMA ADPCM"},
{coding_FFTA2_IMA, "Final Fantasy Tactics A2 4-bit IMA ADPCM"},
{coding_BLITZ_IMA, "Blitz Games 4-bit IMA ADPCM"},
{coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"},
{coding_XBOX_IMA, "XBOX 4-bit IMA ADPCM"},
@ -630,10 +644,10 @@ static const coding_info coding_info_list[] = {
{coding_MSADPCM_int, "Microsoft 4-bit ADPCM (mono/interleave)"},
{coding_MSADPCM_ck, "Microsoft 4-bit ADPCM (Cricket Audio)"},
{coding_WS, "Westwood Studios VBR ADPCM"},
{coding_AICA, "Yamaha 4-bit ADPCM"},
{coding_AICA_int, "Yamaha 4-bit ADPCM (mono/interleave)"},
{coding_YAMAHA, "Yamaha 4-bit ADPCM (framed)"},
{coding_YAMAHA_NXAP, "Yamaha NXAP 4-bit ADPCM"},
{coding_YAMAHA, "Yamaha 4-bit ADPCM"},
{coding_YAMAHA_int, "Yamaha 4-bit ADPCM (mono/interleave)"},
{coding_ASKA, "tri-Ace Aska 4-bit ADPCM"},
{coding_NXAP, "Nex NXAP 4-bit ADPCM"},
{coding_NDS_PROCYON, "Procyon Studio Digital Sound Elements NDS 4-bit APDCM"},
{coding_L5_555, "Level-5 0x555 4-bit ADPCM"},
{coding_LSF, "lsf 4-bit ADPCM"},
@ -698,7 +712,6 @@ static const layout_info layout_info_list[] = {
{layout_segmented, "segmented"},
{layout_layered, "layered"},
{layout_aix, "AIX"},
{layout_blocked_mxch, "blocked (MxCh)"},
{layout_blocked_ast, "blocked (AST)"},
@ -762,7 +775,7 @@ static const meta_info meta_info_list[] = {
{meta_DSP_CSTR, "Namco Cstr header"},
{meta_GCSW, "GCSW header"},
{meta_PS2_SShd, "Sony ADS header"},
{meta_PS2_NPSF, "Namco Production Sound File (NPSF) header"},
{meta_NPS, "Namco NPSF header"},
{meta_RWSD, "Nintendo RWSD header (single stream)"},
{meta_RWAR, "Nintendo RWAR header (single RWAV stream)"},
{meta_RWAV, "Nintendo RWAV header"},
@ -838,7 +851,7 @@ static const meta_info meta_info_list[] = {
{meta_MUSX_V201, "MUSX / Version 201 Header"},
{meta_LEG, "Legaia 2 - Duel Saga LEG Header"},
{meta_FILP, "Bio Hazard - Gun Survivor FILp Header"},
{meta_IKM, "Zwei!! IKM Header"},
{meta_IKM, "MiCROViSiON IKM header"},
{meta_SFS, "Baroque SFS Header"},
{meta_SAT_DVI, "Konami KCEN DVI. header"},
{meta_DC_KCEY, "Konami KCEY KCEYCOMP header"},
@ -901,8 +914,8 @@ static const meta_info meta_info_list[] = {
{meta_RSD6WMA, "Radical RSD6/WMA header"},
{meta_DC_ASD, "ASD Header"},
{meta_NAOMI_SPSD, "Naomi SPSD header"},
{meta_FFXI_BGW, "BGW BGMStream header"},
{meta_FFXI_SPW, "SPW SeWave header"},
{meta_FFXI_BGW, "Square Enix .BGW header"},
{meta_FFXI_SPW, "Square Enix .SPW header"},
{meta_PS2_ASS, "SystemSoft .ASS header"},
{meta_NUB_IDSP, "Namco NUB IDSP header"},
{meta_IDSP_NL, "Next Level IDSP header"},
@ -921,7 +934,7 @@ static const meta_info meta_info_list[] = {
{meta_NGC_SSM, "SSM DSP Header"},
{meta_PS2_JOE, "Asobo Studio .JOE header"},
{meta_VGS, "Guitar Hero VGS Header"},
{meta_DC_DCSW_DCS, "Evil Twin DCS file with helper"},
{meta_DCS_WAV, "In Utero DCS+WAV header"},
{meta_SMP, "Infernal Engine .smp header"},
{meta_MUL, "Crystal Dynamics .MUL header"},
{meta_THP, "THP Movie File Format Header"},
@ -995,7 +1008,7 @@ static const meta_info meta_info_list[] = {
{meta_PS2_B1S, "B1S header"},
{meta_PS2_WAD, "WAD header"},
{meta_DSP_XIII, "XIII dsp header"},
{meta_DSP_CABELAS, "Cabelas games dsp header"},
{meta_DSP_CABELAS, "Cabelas games .DSP header"},
{meta_PS2_ADM, "Dragon Quest V .ADM raw header"},
{meta_PS2_LPCM, "LPCM header"},
{meta_PS2_VMS, "VMS Header"},
@ -1009,7 +1022,7 @@ static const meta_info meta_info_list[] = {
{meta_SQEX_SCD, "Square-Enix SCD header"},
{meta_NGC_NST_DSP, "Animaniacs NST header"},
{meta_BAF, "Bizarre Creations .baf header"},
{meta_PS3_MSF, "Sony MSF header"},
{meta_MSF, "Sony MSF header"},
{meta_NUB_VAG, "Namco NUB VAG header"},
{meta_PS3_PAST, "SNDP header"},
{meta_SGXD, "Sony SGXD header"},
@ -1030,7 +1043,7 @@ static const meta_info meta_info_list[] = {
{meta_OTNS_ADP, "Omikron: The Nomad Soul ADP header"},
{meta_EB_SFX, "Excitebots .sfx header"},
{meta_EB_SF0, "assumed Excitebots .sf0 by extension"},
{meta_PS2_MTAF, "Konami MTAF header"},
{meta_MTAF, "Konami MTAF header"},
{meta_PS2_VAG1, "Konami VAG1 header"},
{meta_PS2_VAG2, "Konami VAG2 header"},
{meta_TUN, "Lego Racers ALP header"},
@ -1071,7 +1084,7 @@ static const meta_info meta_info_list[] = {
{meta_TA_AAC_X360, "tri-Ace AAC (X360) header"},
{meta_TA_AAC_PS3, "tri-Ace AAC (PS3) header"},
{meta_TA_AAC_MOBILE, "tri-Ace AAC (Mobile) header"},
{meta_PS3_MTA2, "Konami MTA2 header"},
{meta_MTA2, "Konami MTA2 header"},
{meta_NGC_ULW, "Criterion ULW raw header"},
{meta_PC_XA30, "Reflections XA30 PC header"},
{meta_WII_04SW, "Reflections 04SW header"},
@ -1170,6 +1183,12 @@ static const meta_info meta_info_list[] = {
{meta_GIN, "Electronic Arts Gnsu header"},
{meta_DSF, "Ocean DSF header"},
{meta_208, "Ocean .208 header"},
{meta_DSP_DS2, "LucasArts .DS2 header"},
{meta_MUS_VC, "Vicious Cycle .MUS header"},
{meta_STRM_ABYLIGHT, "Abylight STRM header"},
{meta_MSF_KONAMI, "Konami MSF header"},
{meta_XWMA_KONAMI, "Konami XWMA header"},
{meta_9TAV, "Konami 9TAV header"},
};

View File

@ -1,92 +0,0 @@
#include "layout.h"
#include "../vgmstream.h"
#include "../coding/coding.h"
void render_vgmstream_aix(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written=0;
aix_codec_data *data = vgmstream->codec_data;
while (samples_written<sample_count) {
int samples_to_do;
int samples_this_block = data->sample_counts[data->current_segment];
int current_stream;
int channels_sofar = 0;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
data->current_segment = 1;
for (current_stream = 0; current_stream < data->stream_count; current_stream++)
{
int i;
reset_vgmstream(data->adxs[data->current_segment*data->stream_count+current_stream]);
/* carry over the history from the loop point */
for (i=0;i<data->adxs[data->stream_count+current_stream]->channels;i++)
{
data->adxs[1*data->stream_count+current_stream]->ch[i].adpcm_history1_32 =
data->adxs[0+current_stream]->ch[i].adpcm_history1_32;
data->adxs[1*data->stream_count+current_stream]->ch[i].adpcm_history2_32 =
data->adxs[0+current_stream]->ch[i].adpcm_history2_32;
}
}
vgmstream->samples_into_block = 0;
continue;
}
samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream);
/*printf("samples_to_do=%d,samples_this_block=%d,samples_written=%d,sample_count=%d\n",samples_to_do,samples_this_block,samples_written,sample_count);*/
if (samples_written+samples_to_do > sample_count)
samples_to_do=sample_count-samples_written;
if (samples_to_do == 0)
{
int i;
data->current_segment++;
/*printf("next %d, %d samples\n",data->current_file,data->files[data->current_file]->total_values/data->files[data->current_file]->info.channels);*/
for (current_stream = 0; current_stream < data->stream_count; current_stream++)
{
reset_vgmstream(data->adxs[data->current_segment*data->stream_count+current_stream]);
/* carry over the history from the previous segment */
for (i=0;i<data->adxs[data->current_segment*data->stream_count+current_stream]->channels;i++)
{
data->adxs[data->current_segment*data->stream_count+current_stream]->ch[i].adpcm_history1_32 =
data->adxs[(data->current_segment-1)*data->stream_count+current_stream]->ch[i].adpcm_history1_32;
data->adxs[data->current_segment*data->stream_count+current_stream]->ch[i].adpcm_history2_32 =
data->adxs[(data->current_segment-1)*data->stream_count+current_stream]->ch[i].adpcm_history2_32;
}
}
vgmstream->samples_into_block = 0;
continue;
}
/*printf("decode %d samples file %d\n",samples_to_do,data->current_file);*/
if (samples_to_do > AIX_BUFFER_SIZE/2)
{
samples_to_do = AIX_BUFFER_SIZE/2;
}
for (current_stream = 0; current_stream < data->stream_count; current_stream++)
{
int i,j;
VGMSTREAM *adx = data->adxs[data->current_segment*data->stream_count+current_stream];
render_vgmstream(data->buffer,samples_to_do,adx);
for (i = 0; i < samples_to_do; i++)
{
for (j = 0; j < adx->channels; j++)
{
buffer[(i+samples_written)*vgmstream->channels+channels_sofar+j] = data->buffer[i*adx->channels+j];
}
}
channels_sofar += adx->channels;
}
samples_written += samples_to_do;
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block+=samples_to_do;
}
}

View File

@ -5,7 +5,7 @@
/* Decodes samples for blocked streams.
* Data is divided into headered blocks with a bunch of data. The layout calls external helper functions
* when a block is decoded, and those must parse the new block and move offsets accordingly. */
void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
void render_vgmstream_blocked(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written = 0;
int frame_size, samples_per_frame, samples_this_block;
@ -41,14 +41,14 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
if (samples_this_block < 0) {
/* probably block bug or EOF, next calcs would give wrong values/segfaults/infinite loop */
VGM_LOG("layout_blocked: wrong block samples at 0x%x\n", (uint32_t)vgmstream->current_block_offset);
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample));
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t));
break;
}
if (vgmstream->current_block_offset < 0 || vgmstream->current_block_offset == 0xFFFFFFFF) {
/* probably block bug or EOF, block functions won't be able to read anything useful/infinite loop */
VGM_LOG("layout_blocked: wrong block offset found\n");
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample));
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t));
break;
}

View File

@ -10,6 +10,10 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
size_t block_size, block_samples;
int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE;
uint32_t flag_lang = (vgmstream->codec_config >> 16) & 0xFFFF;
int flag_be = (vgmstream->codec_config & 0x02);
int flag_adpcm = (vgmstream->codec_config & 0x01);
/* EOF reads: signal we have nothing and let the layout fail */
if (block_offset >= get_streamfile_size(streamFile)) {
@ -23,35 +27,21 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
{
uint32_t block_id = read_32bitBE(block_offset+0x00,streamFile);
if (vgmstream->codec_config & 0x02) /* size is always LE, except in early SS/MAC */
if (flag_be) /* size is always LE, except in early SS/MAC */
block_size = read_32bitBE(block_offset + 0x04,streamFile);
else
block_size = read_32bitLE(block_offset + 0x04,streamFile);
switch(block_id) {
case 0x5343446C: /* "SCDl" */
case 0x5344454E: /* "SDEN" */
case 0x53444652: /* "SDFR" */
case 0x53444745: /* "SDGE" */
case 0x53444445: /* "SDDE" */
case 0x53444954: /* "SDIT" */
case 0x53445350: /* "SDSP" */
case 0x53444553: /* "SDES" */
case 0x53444D58: /* "SDMX" */
case 0x53445255: /* "SDRU" */
case 0x53444A41: /* "SDJA" */
case 0x53444A50: /* "SDJP" */
case 0x5344504C: /* "SDPL" */
/* audio chunk */
if (vgmstream->coding_type == coding_PSX)
block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels);
else
block_samples = read_32bit(block_offset+0x08,streamFile);
break;
default:
/* ignore other chunks (audio "SCHl/SCCl/...", video "pIQT/MADk/...", etc) */
block_samples = 0; /* layout ignores this */
break;
if (block_id == 0x5343446C || block_id == (0x53440000 | flag_lang)) {
/* "SCDl" or "SDxx" audio chunk */
if (vgmstream->coding_type == coding_PSX)
block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels);
else
block_samples = read_32bit(block_offset+0x08,streamFile);
}
else {
/* ignore other chunks (audio "SCHl/SCCl/...", non-target lang, video "pIQT/MADk/...", etc) */
block_samples = 0; /* layout ignores this */
}
/* "SCHl" start block (movie "SHxx" shouldn't use multi files) */
@ -185,7 +175,7 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
}
/* read ADPCM history before each channel if needed (not actually read in sx.exe) */
if (vgmstream->codec_config & 0x01) {
if (flag_adpcm) {
for (i = 0; i < vgmstream->channels; i++) {
//vgmstream->ch[i].adpcm_history1_32 = read_16bit(vgmstream->ch[i].offset+0x00,streamFile);
//vgmstream->ch[i].adpcm_history3_32 = read_16bit(vgmstream->ch[i].offset+0x02,streamFile);

View File

@ -6,7 +6,6 @@ void block_update_wsi(off_t block_offset, VGMSTREAM * vgmstream) {
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
int i;
off_t channel_block_size;
//int is_first_offset =
/* assume that all channels have the same size for this block */
@ -22,8 +21,6 @@ void block_update_wsi(off_t block_offset, VGMSTREAM * vgmstream) {
/* first block has DSP header, remove */
if (block_offset == vgmstream->ch[0].channel_start_offset) {
int i;
vgmstream->current_block_size -= 0x60;
for (i = 0; i < vgmstream->channels; i++) {
vgmstream->ch[i].offset += 0x60;

View File

@ -4,7 +4,7 @@
/* Decodes samples for flat streams.
* Data forms a single stream, and the decoder may internally skip chunks and move offsets as needed. */
void render_vgmstream_flat(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
void render_vgmstream_flat(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written = 0;
int samples_per_frame, samples_this_block;
@ -23,10 +23,11 @@ void render_vgmstream_flat(sample * buffer, int32_t sample_count, VGMSTREAM * vg
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written;
if (samples_to_do == 0) {
VGM_LOG("layout_flat: wrong samples_to_do found\n");
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample));
VGM_LOG("layout_flat: wrong samples_to_do 0 found\n"); /* could happen when calling render at EOF? */
//VGM_LOG("layout_flat: tb=%i sib=%i, spf=%i\n", samples_this_block, vgmstream->samples_into_block, samples_per_frame);
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t));
break;
}

View File

@ -6,7 +6,7 @@
* Data has interleaved chunks per channel, and once one is decoded the layout moves offsets,
* skipping other chunks (essentially a simplified variety of blocked layout).
* Incompatible with decoders that move offsets. */
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written = 0;
int frame_size, samples_per_frame, samples_this_block;
int has_interleave_last = vgmstream->interleave_last_block_size && vgmstream->channels > 1;
@ -49,7 +49,7 @@ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREA
if (samples_to_do == 0) { /* happens when interleave is not set */
VGM_LOG("layout_interleave: wrong samples_to_do found\n");
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample));
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t));
break;
}

View File

@ -1,50 +1,58 @@
#include "layout.h"
#include "../vgmstream.h"
#include "../mixing.h"
/* NOTE: if loop settings change the layered vgmstreams must be notified (preferably using vgmstream_force_loop) */
#define LAYER_BUF_SIZE 512
#define LAYER_MAX_CHANNELS 6 /* at least 2, but let's be generous */
#define VGMSTREAM_MAX_LAYERS 255
#define VGMSTREAM_LAYER_SAMPLE_BUFFER 8192
/* Decodes samples for layered streams.
* Similar to interleave layout, but decodec samples are mixed from complete vgmstreams, each
* with custom codecs and different number of channels, creating a single super-vgmstream.
* Usually combined with custom streamfiles to handle data interleaved in weird ways. */
void render_vgmstream_layered(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
void render_vgmstream_layered(sample_t * outbuf, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written = 0;
layered_layout_data *data = vgmstream->layout_data;
sample interleave_buf[LAYER_BUF_SIZE*LAYER_MAX_CHANNELS];
while (samples_written < sample_count) {
int samples_to_do = LAYER_BUF_SIZE;
int samples_to_do = VGMSTREAM_LAYER_SAMPLE_BUFFER;
int layer, ch = 0;
if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written;
for (layer = 0; layer < data->layer_count; layer++) {
int s, layer_ch;
int layer_channels = data->layers[layer]->channels;
int s, layer_ch, layer_channels;
/* each layer will handle its own looping internally */
/* each layer will handle its own looping/mixing internally */
render_vgmstream(interleave_buf, samples_to_do, data->layers[layer]);
/* layers may have its own number of channels */
mixing_info(data->layers[layer], NULL, &layer_channels);
render_vgmstream(
data->buffer,
samples_to_do,
data->layers[layer]);
/* mix layer samples to main samples */
for (layer_ch = 0; layer_ch < layer_channels; layer_ch++) {
for (s = 0; s < samples_to_do; s++) {
size_t layer_sample = s*layer_channels + layer_ch;
size_t buffer_sample = (samples_written+s)*vgmstream->channels + ch;
size_t buffer_sample = (samples_written+s)*data->output_channels + ch;
buffer[buffer_sample] = interleave_buf[layer_sample];
outbuf[buffer_sample] = data->buffer[layer_sample];
}
ch++;
}
}
samples_written += samples_to_do;
vgmstream->current_sample = data->layers[0]->current_sample; /* just in case it's used for info */
/* needed for info (ex. for mixing) */
vgmstream->current_sample = data->layers[0]->current_sample;
vgmstream->loop_count = data->layers[0]->loop_count;
//vgmstream->samples_into_block = 0; /* handled in each layer */
}
}
@ -53,7 +61,7 @@ void render_vgmstream_layered(sample * buffer, int32_t sample_count, VGMSTREAM *
layered_layout_data* init_layout_layered(int layer_count) {
layered_layout_data *data = NULL;
if (layer_count <= 0 || layer_count > 255)
if (layer_count <= 0 || layer_count > VGMSTREAM_MAX_LAYERS)
goto fail;
data = calloc(1, sizeof(layered_layout_data));
@ -71,38 +79,62 @@ fail:
}
int setup_layout_layered(layered_layout_data* data) {
int i;
int i, max_input_channels = 0, max_output_channels = 0;
sample_t *outbuf_re = NULL;
/* setup each VGMSTREAM (roughly equivalent to vgmstream.c's init_vgmstream_internal stuff) */
for (i = 0; i < data->layer_count; i++) {
if (!data->layers[i])
goto fail;
int layer_input_channels, layer_output_channels;
if (data->layers[i]->num_samples <= 0)
if (data->layers[i] == NULL) {
VGM_LOG("layered: no vgmstream in %i\n", i);
goto fail;
}
if (data->layers[i]->channels > LAYER_MAX_CHANNELS)
if (data->layers[i]->num_samples <= 0) {
VGM_LOG("layered: no samples in %i\n", i);
goto fail;
}
/* different layers may have different input/output channels */
mixing_info(data->layers[i], &layer_input_channels, &layer_output_channels);
max_output_channels += layer_output_channels;
if (max_input_channels < layer_input_channels)
max_input_channels = layer_input_channels;
if (i > 0) {
/* a bit weird, but no matter */
if (data->layers[i]->sample_rate != data->layers[i-1]->sample_rate) {
VGM_LOG("layered layout: layer %i has different sample rate\n", i);
VGM_LOG("layered: layer %i has different sample rate\n", i);
}
/* also weird */
if (data->layers[i]->coding_type != data->layers[i-1]->coding_type) {
VGM_LOG("layered layout: layer %i has different coding type\n", i);
VGM_LOG("layered: layer %i has different coding type\n", i);
}
}
//todo could check if layers'd loop match vs main, etc
/* loops and other values could be mismatched but hopefully not */
/* save start things so we can restart for seeking/looping */
memcpy(data->layers[i]->start_ch,data->layers[i]->ch,sizeof(VGMSTREAMCHANNEL)*data->layers[i]->channels);
memcpy(data->layers[i]->start_vgmstream,data->layers[i],sizeof(VGMSTREAM));
setup_vgmstream(data->layers[i]); /* final setup in case the VGMSTREAM was created manually */
mixing_setup(data->layers[i], VGMSTREAM_LAYER_SAMPLE_BUFFER); /* init mixing */
}
if (max_output_channels > VGMSTREAM_MAX_CHANNELS || max_input_channels > VGMSTREAM_MAX_CHANNELS)
goto fail;
/* create internal buffer big enough for mixing */
outbuf_re = realloc(data->buffer, VGMSTREAM_LAYER_SAMPLE_BUFFER*max_input_channels*sizeof(sample_t));
if (!outbuf_re) goto fail;
data->buffer = outbuf_re;
data->input_channels = max_input_channels;
data->output_channels = max_output_channels;
return 1;
fail:
return 0; /* caller is expected to free */
@ -133,3 +165,39 @@ void reset_layout_layered(layered_layout_data *data) {
reset_vgmstream(data->layers[i]);
}
}
/* helper for easier creation of layers */
VGMSTREAM *allocate_layered_vgmstream(layered_layout_data* data) {
VGMSTREAM *vgmstream = NULL;
int i, channels, loop_flag;
/* get data */
channels = data->output_channels;
loop_flag = 1;
for (i = 0; i < data->layer_count; i++) {
if (loop_flag && !data->layers[i]->loop_flag)
loop_flag = 0;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = data->layers[0]->meta_type;
vgmstream->sample_rate = data->layers[0]->sample_rate;
vgmstream->num_samples = data->layers[0]->num_samples;
vgmstream->loop_start_sample = data->layers[0]->loop_start_sample;
vgmstream->loop_end_sample = data->layers[0]->loop_end_sample;
vgmstream->coding_type = data->layers[0]->coding_type;
vgmstream->layout_type = layout_layered;
vgmstream->layout_data = data;
return vgmstream;
fail:
if (vgmstream) vgmstream->layout_data = NULL;
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -5,7 +5,7 @@
#include "../vgmstream.h"
/* blocked layouts */
void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void render_vgmstream_blocked(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void block_update(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_ast(off_t block_ofset, VGMSTREAM * vgmstream);
@ -48,22 +48,22 @@ void block_update_xa_aiff(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_vs_square(off_t block_offset, VGMSTREAM * vgmstream);
/* other layouts */
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void render_vgmstream_flat(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void render_vgmstream_flat(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void render_vgmstream_aix(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void render_vgmstream_segmented(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
segmented_layout_data* init_layout_segmented(int segment_count);
int setup_layout_segmented(segmented_layout_data* data);
void free_layout_segmented(segmented_layout_data *data);
void reset_layout_segmented(segmented_layout_data *data);
VGMSTREAM *allocate_segmented_vgmstream(segmented_layout_data* data, int loop_flag, int loop_start_segment, int loop_end_segment);
void render_vgmstream_layered(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void render_vgmstream_layered(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
layered_layout_data* init_layout_layered(int layer_count);
int setup_layout_layered(layered_layout_data* data);
void free_layout_layered(layered_layout_data *data);
void reset_layout_layered(layered_layout_data *data);
VGMSTREAM *allocate_layered_vgmstream(layered_layout_data* data);
#endif

View File

@ -1,50 +1,74 @@
#include "layout.h"
#include "../vgmstream.h"
#include "../mixing.h"
#define VGMSTREAM_MAX_SEGMENTS 255
#define VGMSTREAM_SEGMENT_SAMPLE_BUFFER 8192
/* Decodes samples for segmented streams.
* Chains together sequential vgmstreams, for data divided into separate sections or files
* (like one part for intro and other for loop segments, which may even use different codecs). */
void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written = 0;
void render_vgmstream_segmented(sample_t * outbuf, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written = 0, loop_samples_skip = 0;
segmented_layout_data *data = vgmstream->layout_data;
int use_internal_buffer = 0;
/* normally uses outbuf directly (faster) but could need internal buffer if downmixing */
if (vgmstream->channels != data->input_channels) {
use_internal_buffer = 1;
}
while (samples_written < sample_count) {
int samples_to_do;
int samples_this_block = data->segments[data->current_segment]->num_samples;
int samples_this_segment = data->segments[data->current_segment]->num_samples;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
/* handle looping, finding loop segment */
int loop_segment = 0, samples = 0, loop_samples_skip = 0;
while (samples < vgmstream->num_samples) {
int segment, loop_segment, total_samples;
/* handle looping by finding loop segment and loop_start inside that segment */
loop_segment = 0;
total_samples = 0;
while (total_samples < vgmstream->num_samples) {
int32_t segment_samples = data->segments[loop_segment]->num_samples;
if (vgmstream->loop_start_sample >= samples && vgmstream->loop_start_sample < samples + segment_samples) {
loop_samples_skip = vgmstream->loop_start_sample - samples;
if (vgmstream->loop_sample >= total_samples && vgmstream->loop_sample < total_samples + segment_samples) {
loop_samples_skip = vgmstream->loop_sample - total_samples;
break; /* loop_start falls within loop_segment's samples */
}
samples += segment_samples;
total_samples += segment_samples;
loop_segment++;
}
if (loop_segment == data->segment_count) {
VGM_LOG("segmented_layout: can't find loop segment\n");
loop_segment = 0;
}
if (loop_samples_skip > 0) {
VGM_LOG("segmented_layout: loop starts after %i samples\n", loop_samples_skip);
//todo skip/fix, but probably won't happen
}
data->current_segment = loop_segment;
reset_vgmstream(data->segments[data->current_segment]);
/* loops can span multiple segments */
for (segment = loop_segment; segment < data->segment_count; segment++) {
reset_vgmstream(data->segments[segment]);
}
vgmstream->samples_into_block = 0;
continue;
}
samples_to_do = vgmstream_samples_to_do(samples_this_block, sample_count, vgmstream);
samples_to_do = vgmstream_samples_to_do(samples_this_segment, sample_count, vgmstream);
if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written;
if (samples_to_do > VGMSTREAM_SEGMENT_SAMPLE_BUFFER /*&& use_internal_buffer*/) /* always for fade/etc mixes */
samples_to_do = VGMSTREAM_SEGMENT_SAMPLE_BUFFER;
/* segment looping: discard until actual start */
if (loop_samples_skip > 0) {
if (samples_to_do > loop_samples_skip)
samples_to_do = loop_samples_skip;
}
/* detect segment change and restart */
if (samples_to_do == 0) {
@ -54,8 +78,25 @@ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM
continue;
}
render_vgmstream(&buffer[samples_written*data->segments[data->current_segment]->channels],
samples_to_do,data->segments[data->current_segment]);
render_vgmstream(
use_internal_buffer ?
data->buffer :
&outbuf[samples_written * data->output_channels],
samples_to_do,
data->segments[data->current_segment]);
if (loop_samples_skip > 0) {
loop_samples_skip -= samples_to_do;
vgmstream->samples_into_block += samples_to_do;
continue;
}
if (use_internal_buffer) {
int s;
for (s = 0; s < samples_to_do * data->output_channels; s++) {
outbuf[samples_written * data->output_channels + s] = data->buffer[s];
}
}
samples_written += samples_to_do;
vgmstream->current_sample += samples_to_do;
@ -67,7 +108,7 @@ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM
segmented_layout_data* init_layout_segmented(int segment_count) {
segmented_layout_data *data = NULL;
if (segment_count <= 0 || segment_count > 255)
if (segment_count <= 0 || segment_count > VGMSTREAM_MAX_SEGMENTS)
goto fail;
data = calloc(1, sizeof(segmented_layout_data));
@ -86,41 +127,75 @@ fail:
}
int setup_layout_segmented(segmented_layout_data* data) {
int i;
int i, max_input_channels = 0, max_output_channels = 0;
sample_t *outbuf_re = NULL;
/* setup each VGMSTREAM (roughly equivalent to vgmstream.c's init_vgmstream_internal stuff) */
for (i = 0; i < data->segment_count; i++) {
if (!data->segments[i])
goto fail;
int segment_input_channels, segment_output_channels;
if (data->segments[i]->num_samples <= 0)
if (data->segments[i] == NULL) {
VGM_LOG("segmented: no vgmstream in segment %i\n", i);
goto fail;
}
/* shouldn't happen */
if (data->segments[i]->num_samples <= 0) {
VGM_LOG("segmented: no samples in segment %i\n", i);
goto fail;
}
/* disable so that looping is controlled by render_vgmstream_segmented */
if (data->segments[i]->loop_flag != 0) {
VGM_LOG("segmented layout: segment %i is looped\n", i);
VGM_LOG("segmented: segment %i is looped\n", i);
data->segments[i]->loop_flag = 0;
}
/* different segments may have different input channels, though output should be
* the same for all (ex. 2ch + 1ch segments, but 2ch segment is downmixed to 1ch) */
mixing_info(data->segments[i], &segment_input_channels, &segment_output_channels);
if (max_input_channels < segment_input_channels)
max_input_channels = segment_input_channels;
if (max_output_channels < segment_output_channels)
max_output_channels = segment_output_channels;
if (i > 0) {
if (data->segments[i]->channels != data->segments[i-1]->channels)
int prev_output_channels;
mixing_info(data->segments[i-1], NULL, &prev_output_channels);
if (segment_output_channels != prev_output_channels) {
VGM_LOG("segmented: segment %i has wrong channels %i vs prev channels %i\n", i, segment_output_channels, prev_output_channels);
goto fail;
}
/* a bit weird, but no matter */
if (data->segments[i]->sample_rate != data->segments[i-1]->sample_rate) {
VGM_LOG("segmented layout: segment %i has different sample rate\n", i);
VGM_LOG("segmented: segment %i has different sample rate\n", i);
}
/* perfectly acceptable */
//if (data->segments[i]->coding_type != data->segments[i-1]->coding_type)
// goto fail; /* perfectly acceptable */
// goto fail;
}
/* save start things so we can restart for seeking/looping */
memcpy(data->segments[i]->start_ch,data->segments[i]->ch,sizeof(VGMSTREAMCHANNEL)*data->segments[i]->channels);
memcpy(data->segments[i]->start_vgmstream,data->segments[i],sizeof(VGMSTREAM));
setup_vgmstream(data->segments[i]); /* final setup in case the VGMSTREAM was created manually */
mixing_setup(data->segments[i], VGMSTREAM_SEGMENT_SAMPLE_BUFFER); /* init mixing */
}
if (max_output_channels > VGMSTREAM_MAX_CHANNELS || max_input_channels > VGMSTREAM_MAX_CHANNELS)
goto fail;
/* create internal buffer big enough for mixing */
outbuf_re = realloc(data->buffer, VGMSTREAM_SEGMENT_SAMPLE_BUFFER*max_input_channels*sizeof(sample_t));
if (!outbuf_re) goto fail;
data->buffer = outbuf_re;
data->input_channels = max_input_channels;
data->output_channels = max_output_channels;
return 1;
fail:
@ -153,3 +228,53 @@ void reset_layout_segmented(segmented_layout_data *data) {
reset_vgmstream(data->segments[i]);
}
}
/* helper for easier creation of segments */
VGMSTREAM *allocate_segmented_vgmstream(segmented_layout_data* data, int loop_flag, int loop_start_segment, int loop_end_segment) {
VGMSTREAM *vgmstream = NULL;
int channel_layout;
int i, num_samples, loop_start, loop_end;
/* save data */
channel_layout = data->segments[0]->channel_layout;
num_samples = 0;
loop_start = 0;
loop_end = 0;
for (i = 0; i < data->segment_count; i++) {
if (loop_flag && i == loop_start_segment)
loop_start = num_samples;
num_samples += data->segments[i]->num_samples;
if (loop_flag && i == loop_end_segment)
loop_end = num_samples;
/* inherit first segment's layout but only if all segments' layout match */
if (channel_layout != 0 && channel_layout != data->segments[i]->channel_layout)
channel_layout = 0;
}
/* respect loop_flag even when no loop_end found as it's possible file loops are set outside */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(data->output_channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = data->segments[0]->meta_type;
vgmstream->sample_rate = data->segments[0]->sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->coding_type = data->segments[0]->coding_type;
vgmstream->channel_layout = channel_layout;
vgmstream->layout_type = layout_segmented;
vgmstream->layout_data = data;
return vgmstream;
fail:
if (vgmstream) vgmstream->layout_data = NULL;
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -0,0 +1,118 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
#include "9tav_streamfile.h"
/* 9TAV - from Metal Gear Solid 2/3 HD (Vita) */
VGMSTREAM * init_vgmstream_9tav(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate, track_count;
int32_t num_samples, loop_start, loop_end;
size_t track_size;
uint32_t config_data;
int i, is_padded;
layered_layout_data * data = NULL;
STREAMFILE* temp_streamFile = NULL;
/* checks */
/* .9tav: header id */
if (!check_extensions(streamFile, "9tav"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x39544156) /* "9TAV" */
goto fail;
/* 0x04: always 0x09 */
channel_count = read_16bitLE(0x08,streamFile);
track_count = read_16bitLE(0x0a,streamFile); /* MGS3 uses multitracks */
sample_rate = read_32bitLE(0x0c,streamFile);
track_size = read_32bitLE(0x10,streamFile); /* without padding */
//data_size = read_32bitLE(0x14,streamFile); /* without padding */
num_samples = read_32bitLE(0x18,streamFile);
config_data = read_32bitBE(0x1c,streamFile);
if (read_32bitBE(0x20,streamFile) == 0x4D544146) { /* "MTAF" */
/* MGS3 has a MTAF header (data size and stuff don't match, probably for track info) */
loop_start = read_32bitLE(0x78, streamFile);
loop_end = read_32bitLE(0x7c, streamFile);
loop_flag = read_32bitLE(0x90, streamFile) & 1;
is_padded = 1; /* data also has padding and other oddities */
start_offset = 0x00;
}
else {
/* MGS2 doesn't */
loop_start = 0;
loop_end = 0;
loop_flag = 0;
is_padded = 0;
start_offset = 0x20;
}
/* init layout */
data = init_layout_layered(track_count);
if (!data) goto fail;
/* open each layer subfile */
for (i = 0; i < data->layer_count; i++) {
data->layers[i] = allocate_vgmstream(channel_count, loop_flag);
if (!data->layers[i]) goto fail;
data->layers[i]->meta_type = meta_9TAV;
data->layers[i]->sample_rate = sample_rate;
data->layers[i]->num_samples = num_samples;
data->layers[i]->loop_start_sample = loop_start;
data->layers[i]->loop_end_sample = loop_end;
#ifdef VGM_USE_ATRAC9
{
atrac9_config cfg = {0};
cfg.channels = channel_count;
cfg.config_data = config_data;
cfg.encoder_delay = atrac9_bytes_to_samples_cfg(track_size, cfg.config_data) - num_samples; /* seems ok */
if (cfg.encoder_delay > 4096) /* doesn't seem too normal */
cfg.encoder_delay = 0;
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
if (is_padded) {
temp_streamFile = setup_9tav_streamfile(streamFile, 0xFE4, track_size, i, track_count);
if (!temp_streamFile) goto fail;
}
if (!vgmstream_open_stream(data->layers[i],temp_streamFile == NULL ? streamFile : temp_streamFile,start_offset))
goto fail;
close_streamfile(temp_streamFile);
temp_streamFile = NULL;
}
/* setup layered VGMSTREAMs */
if (!setup_layout_layered(data))
goto fail;
/* build the layered VGMSTREAM */
vgmstream = allocate_layered_vgmstream(data);
if (!vgmstream) goto fail;
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
if (!vgmstream)
free_layout_layered(data);
return NULL;
}

View File

@ -0,0 +1,182 @@
#ifndef _9TAV_STREAMFILE_H_
#define _9TAV_STREAMFILE_H_
#include "../streamfile.h"
typedef struct {
/* config */
off_t stream_offset;
size_t stream_size;
size_t track_size;
int track_number;
int track_count;
int skip_count;
int read_count;
size_t frame_size;
size_t interleave_count;
size_t interleave_last_count;
/* state */
off_t logical_offset; /* fake offset */
off_t physical_offset; /* actual offset */
size_t block_size; /* current size */
size_t skip_size; /* size from block start to reach data */
size_t data_size; /* usable size in a block */
size_t logical_size;
} ntav_io_data;
static size_t ntav_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, ntav_io_data* data) {
size_t total_read = 0;
/* re-start when previous offset (can't map logical<>physical offsets) */
if (data->logical_offset < 0 || offset < data->logical_offset) {
data->physical_offset = data->stream_offset;
data->logical_offset = 0x00;
data->data_size = 0;
data->skip_size = 0;
data->read_count = 0;
data->skip_count = data->interleave_count * data->track_number;
//VGM_LOG("0 o=%lx, sc=%i\n", data->physical_offset, data->skip_count);
}
/* read blocks */
while (length > 0) {
//VGM_LOG("1 of=%lx, so=%lx, sz=%x, of2=%lx, log=%lx\n", data->physical_offset, data->stream_offset, data->stream_size, offset, data->logical_offset);
/* ignore EOF */
if (offset < 0 || data->physical_offset >= data->stream_offset + data->stream_size) {
//VGM_LOG("9 o=%lx, so=%lx, sz=%x, of2=%lx, log=%lx\n", data->physical_offset, data->stream_offset, data->stream_size, offset, data->logical_offset);
//VGM_LOG("eof\n");
break;
}
/* process new block */
if (data->data_size == 0) {
/* not very exact compared to real blocks but ok enough */
if (read_32bitLE(data->physical_offset, streamfile) == 0x00) {
data->block_size = 0x10;
//VGM_LOG("1 o=%lx, lo=%lx skip\n", data->physical_offset, data->logical_offset);
}
else {
data->block_size = data->frame_size;
//VGM_LOG("2 o=%lx, lo=%lx, skip=%i, read=%i\n", data->physical_offset, data->logical_offset, data->skip_count, data->read_count);
/* each track interleaves NTAV_INTERLEAVE frames, but can contain padding in between,
* so must read one by one up to max */
if (data->skip_count == 0 && data->read_count == 0) {
data->read_count = data->interleave_count;
}
if (data->skip_count) {
data->skip_count--;
}
if (data->read_count) {
data->data_size = data->block_size;
data->read_count--;
if (data->read_count == 0) {
if (data->logical_offset + data->interleave_count * data->frame_size > data->track_size)
data->skip_count = data->interleave_last_count * (data->track_count - 1);
else
data->skip_count = data->interleave_count * (data->track_count - 1);
}
}
}
}
/* move to next block */
if (data->data_size == 0 || offset >= data->logical_offset + data->data_size) {
data->physical_offset += data->block_size;
data->logical_offset += data->data_size;
data->data_size = 0;
continue;
}
/* read data */
{
size_t bytes_consumed, bytes_done, to_read;
bytes_consumed = offset - data->logical_offset;
to_read = data->data_size - bytes_consumed;
if (to_read > length)
to_read = length;
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
total_read += bytes_done;
dest += bytes_done;
offset += bytes_done;
length -= bytes_done;
if (bytes_done != to_read || bytes_done == 0) {
break; /* error/EOF */
}
}
}
return total_read;
}
static size_t ntav_io_size(STREAMFILE *streamfile, ntav_io_data* data) {
uint8_t buf[1];
if (data->logical_size)
return data->logical_size;
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
ntav_io_read(streamfile, buf, 0x7FFFFFFF, 1, data);
data->logical_size = data->logical_offset;
return data->logical_size;
}
/* Handles deinterleaving of 9TAV blocked streams. Unlike other games using .sdt,
* KCEJ blocks have a data_size field and rest is padding. Even after that all blocks start
* with 0 (skipped) and there are padding blocks that start with LE 0xDEADBEEF.
* This streamfile handles 9tav extracted like regular sdt and remove padding manually. */
static STREAMFILE* setup_9tav_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t track_size, int track_number, int track_count) {
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
ntav_io_data io_data = {0};
size_t io_data_size = sizeof(ntav_io_data);
size_t last_size;
io_data.stream_offset = stream_offset;
io_data.stream_size = get_streamfile_size(streamFile) - stream_offset;
io_data.track_size = track_size;
io_data.track_number = track_number;
io_data.track_count = track_count;
io_data.frame_size = 0x40;
io_data.interleave_count = 256;
last_size = track_size % (io_data.interleave_count * io_data.frame_size);
if (last_size)
io_data.interleave_last_count = last_size / io_data.frame_size;
io_data.logical_offset = -1; /* force state reset */
/* setup subfile */
new_streamFile = open_wrap_streamfile(streamFile);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_io_streamfile(new_streamFile, &io_data,io_data_size, ntav_io_read,ntav_io_size);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_buffer_streamfile(new_streamFile,0);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
return temp_streamFile;
fail:
close_streamfile(temp_streamFile);
return NULL;
}
#endif /* _9TAV_STREAMFILE_H_ */

View File

@ -188,6 +188,9 @@ static const adxkey_info adxkey8_list[] = {
/* Lucky Star - Ryouou Gakuen Outousai (PS2) */
{0x481D,0x44F9,0x4E35, "LSTARPS2",0},
/* Bakumatsu Renka: Shinsengumi (PS2) */
{0x5381,0x5701,0x665B, "SHINN",0},
};
static const adxkey_info adxkey9_list[] = {

View File

@ -10,8 +10,8 @@ VGMSTREAM * init_vgmstream_aif_asobo(STREAMFILE *streamFile) {
/* checks */
/* aif: standard, aiffl: for plugins? */
if ( !check_extensions(streamFile,"aif,aiffl") )
/* aif: standard, .laif/aiffl: for plugins */
if ( !check_extensions(streamFile,"aif,laif,aiffl") )
goto fail;
if ((uint16_t)read_16bitLE(0x00,streamFile) != 0x69) /* Xbox codec */
goto fail;

View File

@ -67,20 +67,21 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
/* checks */
/* .aif: common (AIFF or AIFC), .aiff: common AIFF, .aifc: common AIFC
* .laif/laifc/laiff: for plugins
* .aifcl/aiffl: for plugins?
* .cbd2: M2 games
* .bgm: Super Street Fighter II Turbo (3DO)
* .acm: Crusader - No Remorse (SAT)
* .adp: Sonic Jam (SAT)
* .ai: Dragon Force (SAT)
* .aifcl/aiffl: for plugins? */
if (check_extensions(streamFile, "aif")) {
* .ai: Dragon Force (SAT) */
if (check_extensions(streamFile, "aif,laif")) {
is_aifc_ext = 1;
is_aiff_ext = 1;
}
else if (check_extensions(streamFile, "aifc,aifcl,afc,cbd2,bgm")) {
else if (check_extensions(streamFile, "aifc,laifc,aifcl,afc,cbd2,bgm")) {
is_aifc_ext = 1;
}
else if (check_extensions(streamFile, "aiff,acm,adp,ai,aiffl")) {
else if (check_extensions(streamFile, "aiff,laiff,acm,adp,ai,aiffl")) {
is_aiff_ext = 1;
}
else {

View File

@ -1,200 +1,195 @@
#include "meta.h"
#include "../layout/layout.h"
#include "aix_streamfile.h"
/* AIX - interleaved AAX, N segments with M layers (1/2ch) inside [SoulCalibur IV (PS3), Dragon Ball Z: Burst Limit (PS3)] */
VGMSTREAM * init_vgmstream_aix(STREAMFILE *streamFile) {
#define MAX_SEGMENTS 50 /* usually segment0=intro, segment1=loop/main, sometimes ~5, rarely ~40 */
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);
/* 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 * vgmstream = NULL;
STREAMFILE * streamFileAIX = NULL;
int loop_flag = 0, channel_count, sample_rate;
int32_t sample_count, loop_start_sample = 0, loop_end_sample = 0;
off_t *segment_offset = NULL;
int32_t *segment_samples = NULL;
aix_codec_data *data = NULL;
off_t data_offset;
off_t layer_list_offset;
off_t layer_list_end;
const off_t segment_list_offset = 0x20;
const size_t segment_list_entry_size = 0x10;
const size_t layer_list_entry_size = 0x08;
off_t segment_offsets[MAX_SEGMENTS] = {0};
size_t segment_sizes[MAX_SEGMENTS] = {0};
int32_t segment_samples[MAX_SEGMENTS] = {0};
int segment_rates[MAX_SEGMENTS] = {0};
off_t data_offset, subtable_offset;
int segment_count, layer_count;
int i, j;
int i;
/* checks */
if (!check_extensions(streamFile, "aix"))
if (!check_extensions(sf, "aix"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x41495846 || /* "AIXF" */
read_32bitBE(0x08,streamFile) != 0x01000014 || /* version? */
read_32bitBE(0x0c,streamFile) != 0x00000800)
if (read_u32be(0x00,sf) != 0x41495846 || /* "AIXF" */
read_u32be(0x08,sf) != 0x01000014 || /* version? */
read_u32be(0x0c,sf) != 0x00000800)
goto fail;
/* AIX combine layers for multichannel and segments for looping, all very hacky.
* For some reason AIX with 1 layer and 1 segment exist (equivalent to a single ADX). */
/* base segment header */
data_offset = read_32bitBE(0x04,streamFile)+0x08;
segment_count = (uint16_t)read_16bitBE(0x18,streamFile);
if (segment_count < 1) goto fail;
layer_list_offset = segment_list_offset + segment_count*segment_list_entry_size + 0x10;
if (layer_list_offset >= data_offset) goto fail;
segment_samples = calloc(segment_count,sizeof(int32_t));
if (!segment_samples) goto fail;
segment_offset = calloc(segment_count,sizeof(off_t));
if (!segment_offset) goto fail;
data_offset = read_s32be(0x04,sf) + 0x08;
/* parse segments table */
{
sample_rate = read_32bitBE(layer_list_offset+0x08,streamFile); /* first layer's sample rate */
const off_t segment_list_offset = 0x20;
const size_t segment_list_entry_size = 0x10;
segment_count = read_u16be(0x18,sf);
if (segment_count < 1 || segment_count > MAX_SEGMENTS) goto fail;
subtable_offset = segment_list_offset + segment_count*segment_list_entry_size;
if (subtable_offset >= data_offset) goto fail;
for (i = 0; i < segment_count; i++) {
segment_offset[i] = read_32bitBE(segment_list_offset + segment_list_entry_size*i + 0x00,streamFile);
/* 0x04: segment size */
segment_samples[i] = read_32bitBE(segment_list_offset + segment_list_entry_size*i + 0x08,streamFile);
segment_offsets[i] = read_s32be(segment_list_offset + segment_list_entry_size*i + 0x00,sf);
segment_sizes[i] = read_u32be(segment_list_offset + segment_list_entry_size*i + 0x04,sf);
segment_samples[i] = read_s32be(segment_list_offset + segment_list_entry_size*i + 0x08,sf);
segment_rates[i] = read_s32be(segment_list_offset + segment_list_entry_size*i + 0x0c,sf);
/* segments > 0 can have 0 sample rate, seems to indicate same as first
* [Ryu ga Gotoku: Kenzan! (PS3) tenkei_sng1.aix] */
if (i > 0 && segment_rates[i] == 0)
segment_rates[i] = segment_rates[0];
/* all segments must have equal sample rate */
if (read_32bitBE(segment_list_offset + segment_list_entry_size*i + 0x0c,streamFile) != sample_rate) {
/* segments > 0 can have 0 sample rate (Ryu ga gotoku: Kenzan! tenkei_sng1.aix),
seems to indicate same sample rate as first */
if (!(i > 0 && read_32bitBE(segment_list_offset + segment_list_entry_size*i + 0x0c,streamFile) == 0))
goto fail;
}
if (segment_rates[i] != segment_rates[0])
goto fail;
}
if (segment_offset[0] != data_offset)
if (segment_offsets[0] != data_offset)
goto fail;
}
/* base layer header */
layer_count = (uint8_t)read_8bit(layer_list_offset,streamFile);
if (layer_count < 1) goto fail;
layer_list_end = layer_list_offset + 0x08 + layer_count*layer_list_entry_size;
if (layer_list_end >= data_offset) goto fail;
/* between the segment and layer table some kind of 0x10 subtable? */
if (read_u8(subtable_offset,sf) != 0x01)
goto fail;
/* parse layers table */
channel_count = 0;
for (i = 0; i < layer_count; i++) {
/* all streams must have same samplerate as segments */
if (read_32bitBE(layer_list_offset + 0x08 + i*layer_list_entry_size + 0x00,streamFile) != sample_rate)
goto fail;
channel_count += read_8bit(layer_list_offset + 0x08 + i*layer_list_entry_size + 0x04,streamFile);
}
{
const size_t layer_list_entry_size = 0x08;
off_t layer_list_offset, layer_list_end;
/* check for existence of segments */
for (i = 0; i < segment_count; i++) {
off_t aixp_offset = segment_offset[i];
for (j = 0; j < layer_count; j++) {
if (read_32bitBE(aixp_offset,streamFile) != 0x41495850) /* "AIXP" */
layer_list_offset = subtable_offset + 0x10;
if (layer_list_offset >= data_offset) goto fail;
layer_count = read_u8(layer_list_offset,sf);
if (layer_count < 1) goto fail;
layer_list_end = layer_list_offset + 0x08 + layer_count*layer_list_entry_size;
if (layer_list_end >= data_offset) goto fail;
for (i = 0; i < layer_count; i++) {
/* all layers must have same sample rate as segments */
if (read_s32be(layer_list_offset + 0x08 + i*layer_list_entry_size + 0x00,sf) != segment_rates[0])
goto fail;
if (read_8bit(aixp_offset+0x08,streamFile) != j)
goto fail;
aixp_offset += read_32bitBE(aixp_offset+0x04,streamFile) + 0x08;
/* 0x04: layer channels */
}
}
/* open base streamfile, that will be shared by all open_aix_with_STREAMFILE */
{
char filename[PATH_LIMIT];
streamFile->get_name(streamFile,filename,sizeof(filename));
streamFileAIX = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); //todo simplify
if (!streamFileAIX) goto fail;
}
/* init layout */
{
data = malloc(sizeof(aix_codec_data));
if (!data) goto fail;
data->segment_count = segment_count;
data->stream_count = layer_count;
data->adxs = calloc(segment_count * layer_count, sizeof(VGMSTREAM*));
if (!data->adxs) goto fail;
data->sample_counts = calloc(segment_count,sizeof(int32_t));
if (!data->sample_counts) goto fail;
memcpy(data->sample_counts,segment_samples,segment_count*sizeof(int32_t));
}
/* open each segment / layer subfile */
for (i = 0; i < segment_count; i++) {
for (j = 0; j < layer_count; j++) {
//;VGM_LOG("AIX: opening segment %d/%d stream %d/%d %x\n",i,segment_count,j,stream_count,segment_offset[i]);
VGMSTREAM *temp_vgmstream;
STREAMFILE * temp_streamFile = open_aix_with_STREAMFILE(streamFileAIX,segment_offset[i],j);
if (!temp_streamFile) goto fail;
temp_vgmstream = data->adxs[i*layer_count+j] = init_vgmstream_adx(temp_streamFile);
close_streamfile(temp_streamFile);
if (!temp_vgmstream) goto fail;
/* setup layers */
if (temp_vgmstream->num_samples != data->sample_counts[i] || temp_vgmstream->loop_flag != 0)
goto fail;
memcpy(temp_vgmstream->start_ch,temp_vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*temp_vgmstream->channels);
memcpy(temp_vgmstream->start_vgmstream,temp_vgmstream,sizeof(VGMSTREAM));
}
}
/* get looping and samples */
sample_count = 0;
loop_flag = (segment_count > 1);
for (i = 0; i < segment_count; i++) {
sample_count += data->sample_counts[i];
if (i == 0)
loop_start_sample = sample_count;
if (i == 1)
loop_end_sample = sample_count;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
/* build combo layers + segments VGMSTREAM */
vgmstream = build_segmented_vgmstream(sf, segment_offsets, segment_sizes, segment_samples, segment_count, layer_count);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = sample_count;
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->meta_type = meta_AIX;
vgmstream->coding_type = data->adxs[0]->coding_type;
vgmstream->layout_type = layout_aix;
vgmstream->ch[0].streamfile = streamFileAIX;
data->current_segment = 0;
vgmstream->codec_data = data;
free(segment_offset);
free(segment_samples);
return vgmstream;
fail:
close_streamfile(streamFileAIX);
close_vgmstream(vgmstream);
free(segment_samples);
free(segment_offset);
/* free aix layout */
if (data) {
if (data->adxs) {
int i;
for (i = 0; i < data->segment_count*data->stream_count; i++) {
close_vgmstream(data->adxs[i]);
}
free(data->adxs);
}
if (data->sample_counts) {
free(data->sample_counts);
}
free(data);
}
return NULL;
}
static VGMSTREAM *build_layered_vgmstream(STREAMFILE *streamFile, off_t segment_offset, size_t segment_size, int layer_count) {
VGMSTREAM *vgmstream = NULL;
layered_layout_data* data = NULL;
int i;
STREAMFILE* temp_streamFile = NULL;
/* build layers */
data = init_layout_layered(layer_count);
if (!data) goto fail;
for (i = 0; i < layer_count; i++) {
/* build the layer STREAMFILE */
temp_streamFile = setup_aix_streamfile(streamFile, segment_offset, segment_size, i, "adx");
if (!temp_streamFile) goto fail;
/* build the sub-VGMSTREAM */
data->layers[i] = init_vgmstream_adx(temp_streamFile);
if (!data->layers[i]) goto fail;
data->layers[i]->stream_size = get_streamfile_size(temp_streamFile);
close_streamfile(temp_streamFile);
temp_streamFile = NULL;
}
if (!setup_layout_layered(data))
goto fail;
/* build the layered VGMSTREAM */
vgmstream = allocate_layered_vgmstream(data);
if (!vgmstream) goto fail;
return vgmstream;
fail:
if (!vgmstream) free_layout_layered(data);
close_vgmstream(vgmstream);
close_streamfile(temp_streamFile);
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) {
VGMSTREAM *vgmstream = NULL;
segmented_layout_data *data = NULL;
int i, loop_flag, loop_start_segment, loop_end_segment;
/* build segments */
data = init_layout_segmented(segment_count);
if (!data) goto fail;
for (i = 0; i < segment_count; i++) {
/* build the layered sub-VGMSTREAM */
data->segments[i] = build_layered_vgmstream(streamFile, segment_offsets[i], segment_sizes[i], layer_count);
if (!data->segments[i]) goto fail;
data->segments[i]->num_samples = segment_samples[i]; /* just in case */
data->segments[i]->stream_size = segment_sizes[i];
}
if (!setup_layout_segmented(data))
goto fail;
/* known loop cases:
* - 1 segment: main/no loop [Hatsune Miku: Project Diva (PSP)]
* - 2 segments: intro + loop [SoulCalibur IV (PS3)]
* - 3 segments: intro + loop + end [Dragon Ball Z: Burst Limit (PS3), Metroid: Other M (Wii)]
* - 4/5 segments: intros + loop + ends [Danball Senki (PSP)]
* - 39 segments: no loops but multiple segments for dynamic parts? [Tetris Collection (PS2)] */
loop_flag = (segment_count > 0 && segment_count <= 5);
loop_start_segment = (segment_count > 3) ? 2 : 1;
loop_end_segment = (segment_count > 3) ? (segment_count - 2) : 1;
/* build the segmented VGMSTREAM */
vgmstream = allocate_segmented_vgmstream(data, loop_flag, loop_start_segment, loop_end_segment);
if (!vgmstream) goto fail;
return vgmstream;
fail:
if (!vgmstream) free_layout_segmented(data);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -2,163 +2,150 @@
#define _AIX_STREAMFILE_H_
#include "../streamfile.h"
/* a streamfile representing a subfile inside another, in blocked AIX format */
typedef struct _AIXSTREAMFILE {
STREAMFILE sf;
STREAMFILE *real_file;
off_t start_physical_offset;
off_t current_physical_offset;
off_t current_logical_offset;
off_t current_block_size;
int stream_id;
} AIXSTREAMFILE;
typedef struct {
/* config */
off_t stream_offset;
size_t stream_size;
int layer_number;
/* state */
off_t logical_offset; /* fake offset */
off_t physical_offset; /* actual offset */
size_t block_size; /* current size */
size_t skip_size; /* size from block start to reach data */
size_t data_size; /* usable size in a block */
size_t logical_size;
} aix_io_data;
/*static*/ STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file, off_t start_offset, int stream_id);
static size_t aix_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, aix_io_data* data) {
size_t total_read = 0;
static size_t read_aix(AIXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length) {
size_t sz = 0;
/* re-start when previous offset (can't map logical<>physical offsets) */
if (data->logical_offset < 0 || offset < data->logical_offset) {
data->physical_offset = data->stream_offset;
data->logical_offset = 0x00;
data->data_size = 0;
}
/*printf("trying to read %x bytes from %x (str%d)\n",length,offset,streamfile->stream_id);*/
/* read blocks */
while (length > 0) {
int read_something = 0;
/* read the beginning of the requested block, if we can */
if (offset >= streamfile->current_logical_offset) {
off_t to_read;
off_t length_available;
/* ignore EOF */
if (offset < 0 || data->physical_offset >= data->stream_offset + data->stream_size) {
break;
}
length_available = (streamfile->current_logical_offset + streamfile->current_block_size) - offset;
/* process new block */
if (data->data_size == 0) {
uint32_t block_id = read_u32be(data->physical_offset+0x00, streamfile);
data->block_size = read_u32be(data->physical_offset+0x04, streamfile) + 0x08;
if (length < length_available) {
to_read = length;
}
else {
to_read = length_available;
/* check valid block "AIXP" id, knowing that AIX segments end with "AIXE" block too */
if (block_id != 0x41495850 || data->block_size == 0 || data->block_size == 0xFFFFFFFF) {
break;
}
if (to_read > 0) {
size_t bytes_read;
/* read target layer, otherwise skip to next block and try again */
if (read_s8(data->physical_offset+0x08, streamfile) == data->layer_number) {
/* 0x09(1): layer count */
data->data_size = read_s16be(data->physical_offset+0x0a, streamfile);
/* 0x0c: -1 */
data->skip_size = 0x10;
}
bytes_read = read_streamfile(dest,
streamfile->current_physical_offset+0x10 + (offset-streamfile->current_logical_offset),
to_read,streamfile->real_file);
sz += bytes_read;
if (bytes_read != to_read) {
return sz; /* an error which we will not attempt to handle here */
}
read_something = 1;
dest += bytes_read;
offset += bytes_read;
length -= bytes_read;
/* strange AIX in Tetris Collection (PS2) with padding before ADX start (no known flag) */
if (data->logical_offset == 0x00 &&
read_u32be(data->physical_offset + 0x10, streamfile) == 0 &&
read_u16be(data->physical_offset + data->block_size - 0x28, streamfile) == 0x8000) {
data->data_size = 0x28;
data->skip_size = data->block_size - 0x28;
}
}
if (!read_something) {
/* couldn't read anything, must seek */
int found_block = 0;
/* move to next block */
if (data->data_size == 0 || offset >= data->logical_offset + data->data_size) {
data->physical_offset += data->block_size;
data->logical_offset += data->data_size;
data->data_size = 0;
continue;
}
/* as we have no memory we must start seeking from the beginning */
if (offset < streamfile->current_logical_offset) {
streamfile->current_logical_offset = 0;
streamfile->current_block_size = 0;
streamfile->current_physical_offset = streamfile->start_physical_offset;
/* read data */
{
size_t bytes_consumed, bytes_done, to_read;
bytes_consumed = offset - data->logical_offset;
to_read = data->data_size - bytes_consumed;
if (to_read > length)
to_read = length;
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
total_read += bytes_done;
dest += bytes_done;
offset += bytes_done;
length -= bytes_done;
if (bytes_done != to_read || bytes_done == 0) {
break; /* error/EOF */
}
}
}
/* seek ye forwards */
while (!found_block) {
/*printf("seek looks at %x\n",streamfile->current_physical_offset);*/
switch (read_32bitBE(streamfile->current_physical_offset, streamfile->real_file)) {
case 0x41495850: /* AIXP */
if (read_8bit(streamfile->current_physical_offset+8, streamfile->real_file) == streamfile->stream_id) {
streamfile->current_block_size = (uint16_t)read_16bitBE(streamfile->current_physical_offset+0x0a, streamfile->real_file);
if (offset >= streamfile->current_logical_offset+ streamfile->current_block_size) {
streamfile->current_logical_offset += streamfile->current_block_size;
}
else {
found_block = 1;
}
}
if (!found_block) {
streamfile->current_physical_offset += read_32bitBE(streamfile->current_physical_offset+0x04, streamfile->real_file) + 8;
}
break;
case 0x41495846: /* AIXF */
/* shouldn't ever see this */
case 0x41495845: /* AIXE */
/* shouldn't have reached the end o' the line... */
default:
return sz;
break;
} /* end block/chunk type select */
} /* end while !found_block */
} /* end if !read_something */
} /* end while length > 0 */
return sz;
return total_read;
}
static void close_aix(AIXSTREAMFILE *streamfile) {
free(streamfile);
return;
static size_t aix_io_size(STREAMFILE *streamfile, aix_io_data* data) {
uint8_t buf[1];
if (data->logical_size)
return data->logical_size;
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
aix_io_read(streamfile, buf, 0x7FFFFFFF, 1, data);
data->logical_size = data->logical_offset;
return data->logical_size;
}
static size_t get_size_aix(AIXSTREAMFILE *streamfile) {
return 0;
}
/* Handles deinterleaving of AIX blocked layer streams */
static STREAMFILE* setup_aix_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t stream_size, int layer_number, const char* extension) {
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
aix_io_data io_data = {0};
size_t io_data_size = sizeof(aix_io_data);
static size_t get_offset_aix(AIXSTREAMFILE *streamfile) {
return streamfile->current_logical_offset;
}
io_data.stream_offset = stream_offset;
io_data.stream_size = stream_size;
io_data.layer_number = layer_number;
io_data.logical_offset = -1; /* force reset */
static void get_name_aix(AIXSTREAMFILE *streamfile,char *buffer,size_t length) {
strncpy(buffer,"ARBITRARY.ADX",length);
buffer[length-1]='\0';
}
/* setup subfile */
new_streamFile = open_wrap_streamfile(streamFile);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
static STREAMFILE *open_aix_impl(AIXSTREAMFILE *streamfile,const char * const filename,size_t buffersize) {
AIXSTREAMFILE *newfile;
if (strcmp(filename,"ARBITRARY.ADX"))
return NULL;
new_streamFile = open_io_streamfile(new_streamFile, &io_data,io_data_size, aix_io_read,aix_io_size);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
newfile = malloc(sizeof(AIXSTREAMFILE));
if (!newfile)
return NULL;
memcpy(newfile,streamfile,sizeof(AIXSTREAMFILE));
return &newfile->sf;
}
new_streamFile = open_buffer_streamfile(new_streamFile,0);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
/*static*/ STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file, off_t start_offset, int stream_id) {
AIXSTREAMFILE *streamfile = malloc(sizeof(AIXSTREAMFILE));
if (extension) {
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,extension);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
}
if (!streamfile)
return NULL;
return temp_streamFile;
/* success, set our pointers */
streamfile->sf.read = (void*)read_aix;
streamfile->sf.get_size = (void*)get_size_aix;
streamfile->sf.get_offset = (void*)get_offset_aix;
streamfile->sf.get_name = (void*)get_name_aix;
streamfile->sf.open = (void*)open_aix_impl;
streamfile->sf.close = (void*)close_aix;
streamfile->real_file = file;
streamfile->current_physical_offset = start_offset;
streamfile->start_physical_offset = start_offset;
streamfile->current_logical_offset = 0;
streamfile->current_block_size = 0;
streamfile->stream_id = stream_id;
return &streamfile->sf;
fail:
close_streamfile(temp_streamFile);
return NULL;
}
#endif /* _AIX_STREAMFILE_H_ */

View File

@ -192,7 +192,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, material_offset, extradata_offset;
size_t material_size, extradata_size, stream_size;
int loop_flag = 0, channel_count, encryption_flag, codec, sample_rate, /*num_samples,*/ loop_start, loop_end;
int loop_flag = 0, channel_count, encryption_flag, codec, sample_rate, num_samples, loop_start, loop_end;
int total_subsongs, target_subsong = streamFile->stream_index;
/* check extensions */
@ -237,7 +237,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
material_size = read_16bitLE(material_offset+0x04,streamFile);
sample_rate = (uint16_t)read_16bitLE(material_offset+0x06,streamFile);
stream_size = read_32bitLE(material_offset+0x08,streamFile);
//num_samples = read_32bitLE(material_offset+0x0c,streamFile);
num_samples = read_32bitLE(material_offset+0x0c,streamFile);
loop_start = read_32bitLE(material_offset+0x10,streamFile);
loop_end = read_32bitLE(material_offset+0x14,streamFile);
@ -263,6 +263,17 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_AKB;
switch (codec) {
case 0x01: /* PCM16LE [Mobius: Final Fantasy (Android)] */
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
break;
case 0x02: { /* MSADPCM [The Irregular at Magic High School Lost Zero (Android)] */
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
@ -323,7 +334,6 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
}
#endif
case 0x01: /* PCM16LE */
default:
goto fail;
}

View File

@ -299,7 +299,8 @@ static int parse_awc_header(STREAMFILE* streamFile, awc_header* awc) {
if ((awc->num_samples && !(awc->num_samples >= num_samples - 10 && awc->num_samples <= num_samples + 10)) ||
(awc->sample_rate && awc->sample_rate != sample_rate) ||
(awc->codec && awc->codec != codec)) {
VGM_LOG("AWC: found header diffs between channels\n");
VGM_LOG("AWC: found header diffs in channel %i, ns=%i vs %i, sr=%i vs %i, c=%i vs %i\n",
ch, awc->num_samples, num_samples, awc->sample_rate, sample_rate, awc->codec, codec);
goto fail;
}

View File

@ -7,7 +7,7 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, header_offset, name_offset;
size_t stream_size;
int loop_flag, channel_count, sample_rate, version, codec;
int loop_flag, channel_count, sample_rate, version, codec, tracks;
int total_subsongs, target_subsong = streamFile->stream_index;
int32_t (*read_32bit)(off_t,STREAMFILE*);
@ -27,7 +27,7 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) {
/* 0x04: bank size */
version = read_32bit(0x08,streamFile);
if (version != 0x03 && version != 0x04)
if (version != 0x03 && version != 0x04 && version != 0x05)
goto fail;
total_subsongs = read_32bit(0x0c,streamFile);
if (target_subsong == 0) target_subsong = 1;
@ -35,7 +35,7 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) {
/* - in v3 */
/* 0x10: 0? */
/* 0x11: bank name */
/* - in v4 */
/* - in v4/5 */
/* 0x10: 1? */
/* 0x11: padding flag? */
/* 0x12: bank name */
@ -49,6 +49,11 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) {
if (i+1 == target_subsong)
break;
offset += read_32bit(offset+0x04, streamFile); /* WAVE size, variable per codec */
/* skip companion "CUE " (found in 007: Blood Stone, contains segment cues) */
if (read_32bitBE(offset+0x00, streamFile) == 0x43554520) {
offset += read_32bit(offset+0x04, streamFile); /* CUE size */
}
}
header_offset = offset;
}
@ -60,38 +65,69 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) {
name_offset = header_offset + 0x0c;
start_offset = read_32bit(header_offset+0x2c, streamFile);
stream_size = read_32bit(header_offset+0x30, streamFile);
tracks = 0;
switch(codec) {
case 0x03:
switch(version) {
case 0x03: /* Geometry Wars (PC) */
sample_rate = read_32bit(header_offset + 0x38, streamFile);
channel_count = read_32bit(header_offset + 0x40, streamFile);
sample_rate = read_32bit(header_offset+0x38, streamFile);
channel_count = read_32bit(header_offset+0x40, streamFile);
/* no actual flag, just loop +15sec songs */
loop_flag = (pcm_bytes_to_samples(stream_size, channel_count, 16) > 15*sample_rate);
break;
case 0x04: /* Project Gotham Racing 4 (X360) */
sample_rate = read_32bit(header_offset + 0x3c, streamFile);
channel_count = read_32bit(header_offset + 0x44, streamFile);
loop_flag = read_8bit(header_offset+0x4b, streamFile);
sample_rate = read_32bit(header_offset+0x3c, streamFile);
channel_count = read_32bit(header_offset+0x44, streamFile);
loop_flag = read_8bit(header_offset+0x4b, streamFile);
break;
default:
goto fail;
}
break;
case 0x07: /* Blur (PS3) */
sample_rate = read_32bit(header_offset+0x40, streamFile);
loop_flag = read_8bit(header_offset+0x48, streamFile);
channel_count = read_8bit(header_offset+0x4b, streamFile);
case 0x07:
switch(version) {
case 0x04: /* Blur (PS3) */
case 0x05: /* James Bond 007: Blood Stone (X360) */
sample_rate = read_32bit(header_offset+0x40, streamFile);
loop_flag = read_8bit(header_offset+0x48, streamFile);
tracks = read_8bit(header_offset+0x49, streamFile);
channel_count = read_8bit(header_offset+0x4b, streamFile);
if (tracks) {
channel_count = channel_count * tracks;
}
break;
default:
goto fail;
}
break;
case 0x08: /* Project Gotham Racing (X360) */
sample_rate = read_32bit(header_offset+0x3c, streamFile);
channel_count = read_32bit(header_offset+0x44, streamFile);
loop_flag = read_8bit(header_offset+0x54, streamFile) != 0;
case 0x08:
switch(version) {
case 0x04: /* Project Gotham Racing (X360) */
sample_rate = read_32bit(header_offset+0x3c, streamFile);
channel_count = read_32bit(header_offset+0x44, streamFile);
loop_flag = read_8bit(header_offset+0x54, streamFile) != 0;
break;
case 0x05: /* James Bond 007: Blood Stone (X360) */
sample_rate = read_32bit(header_offset+0x40, streamFile);
channel_count = read_32bit(header_offset+0x48, streamFile);
loop_flag = read_8bit(header_offset+0x58, streamFile) != 0;
break;
default:
goto fail;
}
break;
default:
VGM_LOG("BAF: unknown version %x\n", version);
goto fail;
}
/* others: pan/vol? fixed values? (0x19, 0x10) */
@ -129,6 +165,7 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) {
vgmstream->loop_end_sample = vgmstream->num_samples;
break;
#ifdef VGM_USE_FFMPEG
case 0x08: {
uint8_t buf[0x100];
int bytes;
@ -162,6 +199,7 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) {
xma_fix_raw_samples_ch(vgmstream, streamFile, start_offset, stream_size, channel_count, 1,1);
break;
}
#endif
default:
VGM_LOG("BAF: unknown codec %x\n", codec);

View File

@ -114,6 +114,7 @@ fail:
/* SPW (SEWave) - from PlayOnline viewer for Final Fantasy XI (PC) */
VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
uint32_t codec, file_size, block_size, sample_rate, block_align;
int32_t loop_start;
off_t start_offset;
@ -139,8 +140,8 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
/*0x2c: unk (0x00?) */
/*0x2d: unk (0x00/01?) */
channel_count = read_8bit(0x2a,streamFile);
block_align = read_8bit(0x2b,streamFile);
/*0x2c: unk (0x01 when PCM, 0x10 when VAG?) */
/*0x2b: unk (0x01 when PCM, 0x10 when VAG?) */
block_align = read_8bit(0x2c,streamFile);
if (file_size != get_streamfile_size(streamFile))
goto fail;
@ -181,6 +182,38 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
break;
#ifdef VGM_USE_FFMPEG
case 3: { /* ATRAC3 (encrypted) */
uint8_t buf[0x100];
int bytes, joint_stereo, skip_samples;
size_t data_size = file_size - start_offset;
vgmstream->num_samples = block_size; /* atrac3_bytes_to_samples gives the same value */
if (loop_flag) {
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
block_align = 0xC0 * vgmstream->channels; /* 0x00 in header */
joint_stereo = 0;
skip_samples = 0;
bytes = ffmpeg_make_riff_atrac3(buf, 0x100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_align, joint_stereo, skip_samples);
if (bytes <= 0) goto fail;
temp_streamFile = setup_bgw_atrac3_streamfile(streamFile, start_offset,data_size, 0xC0,channel_count);
if (!temp_streamFile) goto fail;
vgmstream->codec_data = init_ffmpeg_header_offset(temp_streamFile, buf,bytes, 0,data_size);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
close_streamfile(temp_streamFile);
break;
}
#endif
default:
goto fail;
}
@ -193,6 +226,7 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -176,8 +176,15 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
case 0xC2: sample_rate = 44100; break;
case 0xBC: sample_rate = 36000; break; //?
case 0xBA: sample_rate = 32000; break; //?
case 0xB9: sample_rate = 30000; break; //?
case 0xB8: sample_rate = 28000; break; //?
case 0xB6: sample_rate = 22050; break;
case 0xB0: sample_rate = 15000; break; //?
case 0xAF: sample_rate = 14000; break; //?
case 0xAE: sample_rate = 13000; break; //?
case 0xAC: sample_rate = 12000; break; //?
case 0xAA: sample_rate = 11025; break;
case 0xA9: sample_rate = 10000; break; //?
default:
VGM_LOG("BNK: unknown pitch %x\n", pitch);
goto fail;

View File

@ -1,119 +0,0 @@
#include "meta.h"
#include "../util.h"
/* WAV+DCS (DCSW+DCS)
2008-12-06 - manakoAT : Evil Twin - Cypriens Chronicles...
2008-12-07 - manakoAT : Added a function to read the Header file and for
retrieving the channels/frequency, Frequency starts
always at a "data" chunk - 0x0C bytes, Channels
always - 0x0E bytes...
2010-01-13 - manakoAT : Changed the 'Helper' extension from .wav to .dcws, to prevent conflicts */
VGMSTREAM * init_vgmstream_dc_dcsw_dcs(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * streamFileDCSW = NULL;
char filename[PATH_LIMIT];
char filenameDCSW[PATH_LIMIT];
int i;
int channel_count;
int loop_flag;
int frequency;
int dataBuffer = 0;
int Founddata = 0;
size_t file_size;
off_t current_chunk;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("dcs",filename_extension(filename))) goto fail;
/* Getting the Header file name... */
strcpy(filenameDCSW,filename);
strcpy(filenameDCSW+strlen(filenameDCSW)-3,"dcsw");
/* Look if the Header file is present, else cancel vgmstream */
streamFileDCSW = streamFile->open(streamFile,filenameDCSW,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!streamFileDCSW) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFileDCSW) != 0x52494646 || /* "RIFF" */
read_32bitBE(0x08,streamFileDCSW) != 0x57415645 || /* "WAVE" */
read_32bitBE(0x0C,streamFileDCSW) != 0x34582E76 || /* 0x34582E76 */
read_32bitBE(0x3C,streamFileDCSW) != 0x406E616D) /* "@nam" */
goto fail;
/* scan file until we find a "data" string */
file_size = get_streamfile_size(streamFileDCSW);
{
current_chunk = 0;
/* Start at 0 and loop until we reached the
file size, or until we found a "data string */
while (!Founddata && current_chunk < file_size) {
dataBuffer = (read_32bitBE(current_chunk,streamFileDCSW));
if (dataBuffer == 0x64617461) { /* "data" */
/* if "data" string found, retrieve the needed infos */
Founddata = 1;
/* We will cancel the search here if we have a match */
break;
}
/* else we will increase the search offset by 1 */
current_chunk = current_chunk + 1;
}
}
if (Founddata == 0) {
goto fail;
} else if (Founddata == 1) {
channel_count = (uint16_t)read_16bitLE(current_chunk-0x0E,streamFileDCSW);
frequency = read_32bitLE(current_chunk-0x0C,streamFileDCSW);
}
loop_flag = 0;
/* Seems we're dealing with a vaild file+header,
now we can finally build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->channels = channel_count;
vgmstream->sample_rate = frequency;
vgmstream->num_samples=(get_streamfile_size(streamFile))*2/channel_count;
if(loop_flag) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = (get_streamfile_size(streamFile))*2/channel_count;
}
if (channel_count == 1) {
vgmstream->layout_type = layout_none;
} else if (channel_count > 1) {
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x4000;
}
vgmstream->coding_type = coding_AICA_int;
vgmstream->meta_type = meta_DC_DCSW_DCS;
/* open the file for reading by each channel */
{
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[i].streamfile) goto fail;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=i*vgmstream->interleave_block_size;
vgmstream->ch[i].adpcm_step_index = 0x7f; /* AICA */
}
}
close_streamfile(streamFileDCSW); streamFileDCSW=NULL;
return vgmstream;
/* clean up anything we may have opened */
fail:
if (streamFileDCSW) close_streamfile(streamFileDCSW);
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -39,7 +39,7 @@ VGMSTREAM * init_vgmstream_dc_str(STREAMFILE *streamFile) {
/* fill in the vital statistics */
switch (samples) {
case 4:
vgmstream->coding_type = coding_AICA_int;
vgmstream->coding_type = coding_YAMAHA_int;
vgmstream->num_samples = read_32bitLE(0x14,streamFile);
if (loop_flag) {
vgmstream->loop_start_sample = 0;

View File

@ -0,0 +1,58 @@
#include "meta.h"
#include "../coding/coding.h"
/* DCS+WAV - from In Utero games [Evil Twin: Cyprien's Chronicles (DC)] */
VGMSTREAM * init_vgmstream_dcs_wav(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * streamHeader = NULL;
int loop_flag, channel_count, sample_rate;
off_t start_offset, fmt_offset;
/* checks */
if (!check_extensions(streamFile,"dcs"))
goto fail;
streamHeader = open_streamfile_by_ext(streamFile, "wav");
if (!streamHeader) goto fail;
/* a slightly funny RIFF */
if (read_u32be(0x00,streamHeader) != 0x52494646 || /* "RIFF" */
read_u32be(0x08,streamHeader) != 0x57415645 || /* "WAVE" */
read_u32be(0x0C,streamHeader) != 0x34582E76 || /* "4X.v" */
read_u32be(0x3C,streamHeader) != 0x406E616D) /* "@nam" */
goto fail;
fmt_offset = 0x44 + read_32bitLE(0x40,streamHeader); /* skip @nam */
if (fmt_offset % 2) fmt_offset += 1;
if (read_u32be(fmt_offset,streamHeader) != 0x666D7420) goto fail; /* "fmt " */
fmt_offset += 0x04+0x04;
if (read_u16le(fmt_offset+0x00,streamHeader) != 0x0005) goto fail; /* unofficial format */
channel_count = read_u16le(fmt_offset+0x02,streamHeader);
sample_rate = read_u32le(fmt_offset+0x04,streamHeader);
loop_flag = 0;
start_offset = 0x00;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_DCS_WAV;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = yamaha_bytes_to_samples(get_streamfile_size(streamFile), channel_count);
vgmstream->coding_type = coding_YAMAHA_int;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x4000;
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
close_streamfile(streamHeader);
return vgmstream;
fail:
close_streamfile(streamHeader);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -36,7 +36,7 @@
static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type);
static size_t get_snr_size(STREAMFILE *streamFile, off_t offset);
static VGMSTREAM *parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint16_t target_index, off_t ast_offset);
VGMSTREAM * init_vgmstream_gin_header(STREAMFILE *streamFile, off_t offset);
/* .SNR+SNS - from EA latest games (~2008-2013), v0 header */
@ -314,7 +314,7 @@ VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE *streamFile) {
uint32_t i, num_sounds, type_desc;
uint16_t num_metas, meta_type;
off_t table_offset, types_offset, entry_offset, metas_offset, data_offset, snr_offset, sns_offset;
STREAMFILE *sbsFile = NULL, *streamData = NULL;
STREAMFILE *sbsFile = NULL;
VGMSTREAM *vgmstream = NULL;
int target_stream = streamFile->stream_index;
@ -359,13 +359,30 @@ VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE *streamFile) {
}
}
if (snr_offset == 0xFFFFFFFF)
if (snr_offset == 0xFFFFFFFF && sns_offset == 0xFFFFFFFF)
goto fail;
if (sns_offset == 0xFFFFFFFF) {
if (snr_offset == 0xFFFFFFFF) {
/* SPS file */
sbsFile = open_streamfile_by_ext(streamFile, "sbs");
if (!sbsFile)
goto fail;
if (read_32bitBE(0x00, sbsFile) != 0x53424B53) /* "SBKS" */
goto fail;
snr_offset = sns_offset;
sns_offset = snr_offset + (read_32bitBE(snr_offset, sbsFile) & 0x00FFFFFF);
snr_offset += 0x04;
vgmstream = init_vgmstream_eaaudiocore_header(sbsFile, sbsFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
if (!vgmstream)
goto fail;
} else if (sns_offset == 0xFFFFFFFF) {
/* RAM asset */
streamData = streamFile;
sns_offset = snr_offset + get_snr_size(streamFile, snr_offset);
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
if (!vgmstream)
goto fail;
} else {
/* streamed asset */
sbsFile = open_streamfile_by_ext(streamFile, "sbs");
@ -375,13 +392,11 @@ VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE *streamFile) {
if (read_32bitBE(0x00, sbsFile) != 0x53424B53) /* "SBKS" */
goto fail;
streamData = sbsFile;
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, sbsFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
if (!vgmstream)
goto fail;
}
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamData, snr_offset, sns_offset, meta_EA_SNR_SNS);
if (!vgmstream)
goto fail;
vgmstream->num_streams = num_sounds;
close_streamfile(sbsFile);
return vgmstream;
@ -569,6 +584,54 @@ fail:
return NULL;
}
/* EA TMX - used for engine sounds in NFS games (2007-present) */
VGMSTREAM * init_vgmstream_ea_tmx(STREAMFILE *streamFile) {
uint32_t num_sounds, sound_type;
off_t table_offset, data_offset, entry_offset, sound_offset, sns_offset;
VGMSTREAM *vgmstream = NULL;
int target_stream = streamFile->stream_index;
if (!check_extensions(streamFile, "tmx"))
goto fail;
/* always little endian */
if (read_32bitLE(0x0c, streamFile) != 0x30303031) /* "0001" */
goto fail;
num_sounds = read_32bitLE(0x20, streamFile);
table_offset = read_32bitLE(0x58, streamFile);
data_offset = read_32bitLE(0x5c, streamFile);
if (target_stream == 0) target_stream = 1;
if (target_stream < 0 || num_sounds == 0 || target_stream > num_sounds)
goto fail;
entry_offset = table_offset + (target_stream - 1) * 0x24;
sound_type = read_32bitLE(entry_offset + 0x00, streamFile);
sound_offset = read_32bitLE(entry_offset + 0x08, streamFile) + data_offset;
switch (sound_type) {
case 0x47494E20: /* "GIN " */
/* FIXME: need to get GIN size somehow */
vgmstream = init_vgmstream_gin_header(streamFile, sound_offset);
if (!vgmstream) goto fail;
break;
case 0x534E5220: /* "SNR " */
sns_offset = sound_offset + get_snr_size(streamFile, sound_offset);
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, sound_offset, sns_offset, meta_EA_SNR_SNS);
if (!vgmstream) goto fail;
break;
default:
goto fail;
}
vgmstream->num_streams = num_sounds;
return vgmstream;
fail:
return NULL;
}
/* EA Harmony Sample Bank - used in 8th gen EA Sports games */
VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE *streamFile) {
uint32_t num_dsets, set_sounds, chunk_id;
@ -847,7 +910,8 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
eaac.codec == EAAC_CODEC_EALAYER3_V1 ||
eaac.codec == EAAC_CODEC_EALAYER3_V2_PCM ||
eaac.codec == EAAC_CODEC_EALAYER3_V2_SPIKE ||
eaac.codec == EAAC_CODEC_EAXMA)) {
eaac.codec == EAAC_CODEC_EAXMA ||
eaac.codec == EAAC_CODEC_XAS)) {
VGM_LOG("EA EAAC: unknown actual looping for codec %x\n", eaac.codec);
goto fail;
}
@ -857,8 +921,11 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
switch(eaac.channel_config) {
case 0x00: eaac.channels = 1; break;
case 0x01: eaac.channels = 2; break;
case 0x02: eaac.channels = 3; break; /* rare [Battlefield 4 (X360)-EAXMA] */
case 0x03: eaac.channels = 4; break;
case 0x04: eaac.channels = 5; break; /* rare [Battlefield 4 (X360)-EAXMA] */
case 0x05: eaac.channels = 6; break;
case 0x06: eaac.channels = 7; break; /* rare [Battlefield 4 (X360)-EAXMA] */
case 0x07: eaac.channels = 8; break;
case 0x0a: eaac.channels = 11; break; /* rare [Army of Two: The Devil's Cartel (PS3)-EALayer3v2P] */
default:
@ -910,8 +977,19 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
#endif
case EAAC_CODEC_XAS: /* "Xas1": EA-XAS [Dead Space (PC/PS3)] */
vgmstream->coding_type = coding_EA_XAS_V1;
vgmstream->layout_type = layout_blocked_ea_sns;
/* special (if hacky) loop handling, see comments */
if (eaac.loop_start > 0) {
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamData, &eaac);
if (!data) goto fail;
vgmstream->layout_data = data;
vgmstream->coding_type = data->segments[0]->coding_type;
vgmstream->layout_type = layout_segmented;
} else {
vgmstream->coding_type = coding_EA_XAS_V1;
vgmstream->layout_type = layout_blocked_ea_sns;
}
break;
#ifdef VGM_USE_MPEG
@ -1054,6 +1132,9 @@ static size_t calculate_eaac_size(VGMSTREAM *vgmstream, STREAMFILE *streamFile,
uint32_t total_samples;
size_t stream_size, file_size;
if (streamFile == NULL)
return 0;
switch (eaac->codec) {
case EAAC_CODEC_EAXMA:
case EAAC_CODEC_EALAYER3_V1:
@ -1093,11 +1174,12 @@ static size_t calculate_eaac_size(VGMSTREAM *vgmstream, STREAMFILE *streamFile,
*
* We use the segmented layout, since the eaac_streamfile doesn't handle padding,
* and the segments seem fully separate (so even skipping would probably decode wrong). */
// todo consider better ways to handle this once more looped files for other codecs are found
// todo reorganize code for more standard init
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *streamData, eaac_header *eaac) {
segmented_layout_data *data = NULL;
STREAMFILE* temp_streamFile[2] = {0};
STREAMFILE* temp_streamFile = NULL;
off_t offsets[2] = { eaac->stream_offset, eaac->loop_offset };
off_t start_offset;
int num_samples[2] = { eaac->loop_start, eaac->num_samples - eaac->loop_start};
int segment_count = 2; /* intro/loop */
int i;
@ -1122,6 +1204,8 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *st
temp_eaac.num_samples = num_samples[i];
temp_eaac.stream_offset = offsets[i];
start_offset = 0x00; /* must point to the custom streamfile's beginning */
/* layers inside segments, how trippy */
data->segments[i]->layout_data = build_layered_eaaudiocore_eaxma(streamData, &temp_eaac);
if (!data->segments[i]->layout_data) goto fail;
@ -1131,6 +1215,15 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *st
}
#endif
case EAAC_CODEC_XAS:
{
start_offset = offsets[i];
data->segments[i]->coding_type = coding_EA_XAS_V1;
data->segments[i]->layout_type = layout_blocked_ea_sns;
break;
}
#ifdef VGM_USE_MPEG
case EAAC_CODEC_EALAYER3_V1:
case EAAC_CODEC_EALAYER3_V2_PCM:
@ -1138,10 +1231,12 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *st
mpeg_custom_config cfg = {0};
mpeg_custom_t type = (eaac->codec == 0x05 ? MPEG_EAL31b : (eaac->codec == 0x06) ? MPEG_EAL32P : MPEG_EAL32S);
temp_streamFile[i] = setup_eaac_streamfile(streamData, eaac->version,eaac->codec,eaac->streamed,0,0, offsets[i]);
if (!temp_streamFile[i]) goto fail;
start_offset = 0x00; /* must point to the custom streamfile's beginning */
data->segments[i]->codec_data = init_mpeg_custom(temp_streamFile[i], 0x00, &data->segments[i]->coding_type, eaac->channels, type, &cfg);
temp_streamFile = setup_eaac_streamfile(streamData, eaac->version,eaac->codec,eaac->streamed,0,0, offsets[i]);
if (!temp_streamFile) goto fail;
data->segments[i]->codec_data = init_mpeg_custom(temp_streamFile, 0x00, &data->segments[i]->coding_type, eaac->channels, type, &cfg);
if (!data->segments[i]->codec_data) goto fail;
data->segments[i]->layout_type = layout_none;
break;
@ -1151,10 +1246,14 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *st
goto fail;
}
if (!vgmstream_open_stream(data->segments[i],temp_streamFile[i],0x00))
if (!vgmstream_open_stream(data->segments[i],temp_streamFile == NULL ? streamData : temp_streamFile, start_offset))
goto fail;
data->segments[i]->stream_size = calculate_eaac_size(data->segments[i], temp_streamFile[i], eaac, 0x00);
close_streamfile(temp_streamFile);
temp_streamFile = NULL;
//todo temp_streamFile doesn't contain EAXMA's streamfile
data->segments[i]->stream_size = calculate_eaac_size(data->segments[i], temp_streamFile, eaac, start_offset);
}
if (!setup_layout_segmented(data))
@ -1162,8 +1261,7 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *st
return data;
fail:
for (i = 0; i < segment_count; i++)
close_streamfile(temp_streamFile[i]);
close_streamfile(temp_streamFile);
free_layout_segmented(data);
return NULL;
}
@ -1212,6 +1310,7 @@ static layered_layout_data* build_layered_eaaudiocore_eaxma(STREAMFILE *streamDa
data->layers[i]->coding_type = coding_FFmpeg;
data->layers[i]->layout_type = layout_none;
data->layers[i]->stream_size = get_streamfile_size(temp_streamFile);
xma_fix_raw_samples(data->layers[i], temp_streamFile, 0x00,stream_size, 0, 0,0); /* samples are ok? */
}

View File

@ -74,6 +74,7 @@
#define EA_BLOCKID_LOC_JA 0x00004A41 /* Japanese, older */
#define EA_BLOCKID_LOC_JP 0x00004A50 /* Japanese, newer */
#define EA_BLOCKID_LOC_PL 0x0000504C /* Polish */
#define EA_BLOCKID_LOC_BR 0x00004252 /* Brazilian Portuguese */
#define EA_BNK_HEADER_LE 0x424E4B6C /* "BNKl" */
#define EA_BNK_HEADER_BE 0x424E4B62 /* "BNKb" */
@ -135,18 +136,19 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
/* check header */
if (read_32bitBE(0x00,streamFile) != EA_BLOCKID_HEADER && /* "SCHl" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_EN) && /* "SHEN" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_FR) && /* "SHFR" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_GE) && /* "SHGE" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_DE) && /* "SHDE" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_IT) && /* "SHIT" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_SP) && /* "SHSP" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_ES) && /* "SHES" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_MX) && /* "SHMX" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_RU) && /* "SHRU" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_JA) && /* "SHJA" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_JP) && /* "SHJP" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_PL)) /* "SHPL" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_EN) && /* "SHEN" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_FR) && /* "SHFR" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_GE) && /* "SHGE" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_DE) && /* "SHDE" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_IT) && /* "SHIT" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_SP) && /* "SHSP" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_ES) && /* "SHES" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_MX) && /* "SHMX" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_RU) && /* "SHRU" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_JA) && /* "SHJA" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_JP) && /* "SHJP" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_PL) && /* "SHPL" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_BR)) /* "SHBR" */
goto fail;
/* Stream is divided into blocks/chunks: SCHl=audio header, SCCl=count of SCDl, SCDl=data xN, SCLl=loop end, SCEl=end.
@ -158,6 +160,89 @@ fail:
return NULL;
}
/* EA SCHl inside non-demuxed videos, used in current gen games too */
VGMSTREAM * init_vgmstream_ea_schl_video(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t offset = 0, start_offset = 0;
int blocks_done = 0;
int total_subsongs, target_subsong = streamFile->stream_index;
int32_t(*read_32bit)(off_t, STREAMFILE*);
/* check extension */
/* .vp6: ~late */
if (!check_extensions(streamFile,"vp6"))
goto fail;
/* check initial movie block id */
if (read_32bitBE(0x00,streamFile) != 0x4D566864) /* "MVhd" */
goto fail;
/* use block size to check endianness */
if (guess_endianness32bit(0x04, streamFile)) {
read_32bit = read_32bitBE;
} else {
read_32bit = read_32bitLE;
}
/* find starting valid header for the parser */
while (offset < get_streamfile_size(streamFile)) {
uint32_t block_id = read_32bitBE(offset+0x00,streamFile);
uint32_t block_size = read_32bit (offset+0x04,streamFile);
/* find "SCHl" or "SHxx" blocks */
if ((block_id == EA_BLOCKID_HEADER) || ((block_id & 0xFFFF0000) == EA_BLOCKID_LOC_HEADER)) {
start_offset = offset;
break;
}
if (block_size == 0xFFFFFFFF)
goto fail;
if (blocks_done > 10)
goto fail; /* unlikely to contain music */
blocks_done++;
offset += block_size;
}
if (start_offset == 0)
goto fail;
/* find target subsong (one per each SHxx multilang block) */
total_subsongs = 1;
if (target_subsong == 0) target_subsong = 1;
offset = start_offset;
while (offset < get_streamfile_size(streamFile)) {
uint32_t block_id = read_32bitBE(offset+0x00,streamFile);
uint32_t block_size = read_32bit (offset+0x04,streamFile);
/* no more subsongs (assumes all SHxx headers go together) */
if (((block_id & 0xFFFF0000) != EA_BLOCKID_LOC_HEADER)) {
break;
}
if (target_subsong == total_subsongs) {
start_offset = offset;
/* keep counting subsongs */
}
total_subsongs++;
offset += block_size;
}
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
vgmstream = parse_schl_block(streamFile, start_offset, 1);
if (!vgmstream) goto fail;
vgmstream->num_streams = total_subsongs;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* EA BNK with variable header - from EA games SFXs; also created by sx.exe */
VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE *streamFile) {
off_t offset;
@ -292,7 +377,7 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
if (!bnk_offset)
goto fail;
bnk_target_stream = read_32bit(target_entry_offset + 0x04, streamFile) + 1;
bnk_target_stream = read_32bit(target_entry_offset + 0x04, streamFile);
vgmstream = parse_bnk_header(streamFile, bnk_offset, bnk_target_stream, 1);
if (!vgmstream)
goto fail;
@ -702,8 +787,16 @@ fail:
static VGMSTREAM * parse_schl_block(STREAMFILE *streamFile, off_t offset, int standalone) {
off_t start_offset, header_offset;
size_t header_size;
uint32_t header_id;
ea_header ea = { 0 };
/* use higher bits to store target localized block in case of multilang video,
* so only header sub-id will be read and other langs skipped */
header_id = read_32bitBE(offset + 0x00, streamFile);
if ((header_id & 0xFFFF0000) == EA_BLOCKID_LOC_HEADER) {
ea.codec_config |= (header_id & 0xFFFF) << 16;
}
if (guess_endianness32bit(offset + 0x04, streamFile)) { /* size is always LE, except in early SS/MAC */
header_size = read_32bitBE(offset + 0x04, streamFile);
ea.codec_config |= 0x02;
@ -730,7 +823,7 @@ fail:
static VGMSTREAM * parse_bnk_header(STREAMFILE *streamFile, off_t offset, int target_stream, int is_embedded) {
uint32_t i;
uint16_t num_sounds;
off_t header_offset, start_offset, test_offset, table_offset;
off_t header_offset, start_offset, test_offset, table_offset, entry_offset;
size_t header_size;
ea_header ea = { 0 };
int32_t(*read_32bit)(off_t, STREAMFILE*) = NULL;
@ -779,15 +872,17 @@ static VGMSTREAM * parse_bnk_header(STREAMFILE *streamFile, off_t offset, int ta
if (target_stream < 0 || target_stream >= num_sounds)
goto fail;
header_offset = read_32bit(offset + table_offset + 0x04 * target_stream, streamFile);
entry_offset = offset + table_offset + 0x04 * target_stream;
header_offset = entry_offset + read_32bit(entry_offset, streamFile);
} else {
/* some of these are dummies with zero offset, skip them when opening standalone BNK */
for (i = 0; i < num_sounds; i++) {
test_offset = read_32bit(offset + table_offset + 0x04 * i, streamFile);
entry_offset = offset + table_offset + 0x04 * i;
test_offset = read_32bit(entry_offset, streamFile);
if (test_offset != 0) {
if (target_stream == real_bnk_sounds)
header_offset = offset + table_offset + 0x04 * i + test_offset;
header_offset = entry_offset + test_offset;
real_bnk_sounds++;
}
@ -1497,6 +1592,7 @@ static off_t get_ea_stream_mpeg_start_offset(STREAMFILE* streamFile, off_t start
size_t file_size = get_streamfile_size(streamFile);
off_t block_offset = start_offset;
int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE;
uint32_t header_lang = (ea->codec_config >> 16) & 0xFFFF;
while (block_offset < file_size) {
uint32_t block_id, block_size;
@ -1508,27 +1604,16 @@ static off_t get_ea_stream_mpeg_start_offset(STREAMFILE* streamFile, off_t start
if (block_size > 0x00F00000) /* size is always LE, except in early SAT/MAC */
block_size = read_32bitBE(block_offset+0x04,streamFile);
switch(block_id) {
case EA_BLOCKID_DATA: /* "SCDl" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_EN: /* "SDEN" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_FR: /* "SDFR" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_GE: /* "SDGE" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_DE: /* "SDDE" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_IT: /* "SDIT" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_SP: /* "SDSP" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_ES: /* "SDES" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_MX: /* "SDMX" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_RU: /* "SDRU" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_JA: /* "SDJA" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_JP: /* "SDJP" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_PL: /* "SDPL" */
offset = read_32bit(block_offset+0x0c,streamFile); /* first value seems ok, second is something else in EALayer3 */
return block_offset + 0x0c + ea->channels*0x04 + offset;
case 0x00000000:
goto fail; /* just in case */
default:
block_offset += block_size; /* size includes header */
break;
if (block_id == EA_BLOCKID_DATA || block_id == ((EA_BLOCKID_LOC_DATA | header_lang))) {
/* "SCDl" or target "SDxx" multilang blocks */
offset = read_32bit(block_offset+0x0c,streamFile); /* first value seems ok, second is something else in EALayer3 */
return block_offset + 0x0c + ea->channels*0x04 + offset;
}
else if (block_id == 0x00000000) {
goto fail; /* just in case */
}
else {
block_offset += block_size; /* size includes header */
}
}

View File

@ -0,0 +1,97 @@
#include "meta.h"
#include "../coding/coding.h"
/* FFDL - Matrix Software wrapper [Final Fantasy Dimensions (Android/iOS)] */
VGMSTREAM * init_vgmstream_ffdl(STREAMFILE *sf) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE *temp_sf = NULL;
int loop_flag = 0, is_ffdl = 0;
int32_t num_samples = 0, loop_start_sample = 0, loop_end_sample = 0;
off_t start_offset;
size_t file_size;
/* checks */
/* .ogg/logg: probable extension for Android
* .mp4/lmp4: probable extension for iOS
* .bin: iOS FFDL extension
* (extensionless): for FFDL files without names in Android .obb bigfile */
if (!check_extensions(sf, "ogg,logg,mp4,lmp4,bin,"))
goto fail;
/* "FFDL" is a wrapper used in all of the game's files, that may contain standard
* Ogg/MP4 or "mtxs" w/ loops + Ogg/MP4, and may concatenate multiple of them
* (without size in sight), so they should be split externally first. */
start_offset = 0x00;
/* may start with wrapper (not split) */
if (read_u32be(0x00,sf) == 0x4646444C) { /* "FFDL" */
is_ffdl = 1;
start_offset += 0x04;
}
/* may start with sample info (split) or after "FFDL" */
if (read_u32be(start_offset+0x00,sf) == 0x6D747873) { /* "mtxs" */
is_ffdl = 1;
num_samples = read_s32le(start_offset + 0x04,sf);
loop_start_sample = read_s32le(start_offset + 0x08,sf);
loop_end_sample = read_s32le(start_offset + 0x0c,sf);
loop_flag = !(loop_start_sample==0 && loop_end_sample==num_samples);
start_offset += 0x10;
}
/* don't parse regular files */
if (!is_ffdl)
goto fail;
file_size = get_streamfile_size(sf) - start_offset;
if (read_u32be(start_offset + 0x00,sf) == 0x4F676753) { /* "OggS" */
#ifdef VGM_USE_VORBIS
temp_sf = setup_subfile_streamfile(sf, start_offset, file_size, "ogg");
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_ogg_vorbis(temp_sf);
if (!vgmstream) goto fail;
#else
goto fail;
#endif
}
else if (read_u32be(start_offset + 0x04,sf) == 0x66747970) { /* "ftyp" after atom size */
#ifdef VGM_USE_FFMPEG
temp_sf = setup_subfile_streamfile(sf, start_offset, file_size, "mp4");
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_mp4_aac_ffmpeg(temp_sf);
if (!vgmstream) goto fail;
#else
goto fail;
#endif
}
else {
goto fail;
}
/* install loops */
if (loop_flag) {
/* num_samples is erratic (can be bigger = padded, or smaller = cut; doesn't matter for looping though) */
//;VGM_ASSERT(vgmstream->num_samples != num_samples,
// "FFDL: mtxs samples = %i vs num_samples = %i\n", num_samples, vgmstream->num_samples);
//vgmstream->num_samples = num_samples;
/* loop samples are within num_samples, and don't have encoder delay (loop_start=0 starts from encoder_delay) */
vgmstream_force_loop(vgmstream, 1, loop_start_sample, loop_end_sample);
}
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -19,6 +19,11 @@ VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start,
int32_t loop_start = 0, loop_end = 0, num_samples = 0;
int total_subsongs, target_subsong = streamFile->stream_index;
/* no checks */
//if (!check_extensions(streamFile, "..."))
// goto fail;
/* init ffmpeg */
ffmpeg_codec_data *data = init_ffmpeg_offset(streamFile, start, size);
if (!data) return NULL;
@ -41,6 +46,21 @@ VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start,
}
}
/* hack for AAC files (will return 0 samples if not an actual file) */
if (!num_samples && check_extensions(streamFile, "aac,laac")) {
num_samples = aac_get_samples(streamFile, 0x00, get_streamfile_size(streamFile));
}
/* hack for MP3 files (will return 0 samples if not an actual file) */
if (!num_samples && check_extensions(streamFile, "mp3,lmp3")) {
num_samples = mpeg_get_samples(streamFile, 0x00, get_streamfile_size(streamFile));
}
/* default but often inaccurate when calculated using bitrate (wrong for VBR) */
if (!num_samples) {
num_samples = data->totalSamples;
}
/* build VGMSTREAM */
vgmstream = allocate_vgmstream(data->channels, loop_flag);
@ -52,11 +72,7 @@ VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start,
vgmstream->codec_data = data;
vgmstream->layout_type = layout_none;
if (!num_samples) {
num_samples = data->totalSamples;
}
vgmstream->num_samples = num_samples;
if (loop_flag) {
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
@ -66,6 +82,8 @@ VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start,
if (vgmstream->num_samples <= 0)
goto fail;
vgmstream->channel_layout = ffmpeg_get_channel_layout(vgmstream->codec_data);
return vgmstream;
fail:

View File

@ -44,8 +44,10 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
int i;
/* check extension, case insensitive */
if (!check_extensions(streamFile,"fsb"))
/* checks */
/* .fsb: standard
* .snd: Alchemy engine (also Unity) */
if (!check_extensions(streamFile,"fsb,snd"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x46534235) /* "FSB5" */

View File

@ -0,0 +1,54 @@
#include "meta.h"
#include "../coding/coding.h"
/* FEV+FSB5 container [Just Cause 3 (PC), Shantae: Half-Genie Hero (Switch)] */
VGMSTREAM * init_vgmstream_fsb5_fev_bank(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
off_t subfile_offset, chunk_offset, first_offset = 0x0c;
size_t subfile_size, chunk_size;
/* checks */
if (!check_extensions(streamFile, "bank"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x52494646) /* "RIFF" */
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x46455620) /* "FEV " */
goto fail;
/* .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).
* 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" */
goto fail;
if (read_32bitBE(chunk_offset+0x00,streamFile) != 0x50524F4A || /* "PROJ" */
read_32bitBE(chunk_offset+0x04,streamFile) != 0x424E4B49) /* "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 */
first_offset = chunk_offset + 0x04;
if (!find_chunk_le(streamFile, 0x534E4448,first_offset,0, &chunk_offset,&chunk_size)) /* "SNDH" */
goto fail;
if (chunk_size != 0x0c)
goto fail; /* assuming only one FSB5 is possible */
subfile_offset = read_32bitLE(chunk_offset+0x04,streamFile);
subfile_size = read_32bitLE(chunk_offset+0x08,streamFile);
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, "fsb");
if (!temp_streamFile) goto fail;
vgmstream = init_vgmstream_fsb5(temp_streamFile);
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -10,8 +10,10 @@ static STREAMFILE* setup_fsb_streamfile(STREAMFILE *streamFile, const uint8_t *
VGMSTREAM * init_vgmstream_fsb_encrypted(STREAMFILE * streamFile) {
VGMSTREAM * vgmstream = NULL;
/* check extensions */
if ( !check_extensions(streamFile, "fsb") )
/* checks */
/* .fsb: standard
* .fsb.xen: various Guitar Hero (X360) */
if ( !check_extensions(streamFile, "fsb,xen") )
goto fail;
/* ignore non-encrypted FSB */
@ -150,6 +152,10 @@ static STREAMFILE* setup_fsb_streamfile(STREAMFILE *streamFile, const uint8_t *
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:

View File

@ -9,7 +9,7 @@ typedef struct {
} fsbkey_info;
/**
* List of known keys, found in aluigi's site (http://aluigi.altervista.org), forums and with guessfsb.exe
* List of known keys, found in aluigi's site (http://aluigi.altervista.org), forums, guessfsb.exe or manually.
*/
/* DJ Hero 2 (X360) */ //"nos71RiT"
@ -72,6 +72,12 @@ static const uint8_t key_cro[] = { 0x67,0x68,0x66,0x78,0x68,0x73,0x6C,0x72,0x67,
/* Monster Jam (PS2) */ //"truck/impact/carbody"
static const uint8_t key_mtj[] = { 0x74,0x72,0x75,0x63,0x6B,0x2F,0x69,0x6D,0x70,0x61,0x63,0x74,0x2F,0x63,0x61,0x72,0x62,0x6F,0x64,0x79 };
/* Guitar Hero 5 (X360) */
static const uint8_t key_gh5[] = { 0xFC,0xF9,0xE4,0xB3,0xF5,0x57,0x5C,0xA5,0xAC,0x13,0xEC,0x4A,0x43,0x19,0x58,0xEB,0x4E,0xF3,0x84,0x0B,0x8B,0x78,0xFA,0xFD,0xBB,0x18,0x46,0x7E,0x31,0xFB,0xD0 };
/* Sekiro: Shadows Die Twice (PC) */ //"G0KTrWjS9syqF7vVD6RaVXlFD91gMgkC"
static const uint8_t key_sek[] = { 0x47,0x30,0x4B,0x54,0x72,0x57,0x6A,0x53,0x39,0x73,0x79,0x71,0x46,0x37,0x76,0x56,0x44,0x36,0x52,0x61,0x56,0x58,0x6C,0x46,0x44,0x39,0x31,0x67,0x4D,0x67,0x6B,0x43 };
// Unknown:
// - Battle: Los Angeles
// - Guitar Hero: Warriors of Rock, DJ hero FSB
@ -133,6 +139,8 @@ static const fsbkey_info fsbkey_list[] = {
{ 1,1, sizeof(key_sc2),key_sc2 },//untested
{ 1,0, sizeof(key_cro),key_cro },
{ 0,1, sizeof(key_mtj),key_mtj },// FSB3
{ 0,1, sizeof(key_gh5),key_gh5 },// FSB4
{ 1,0, sizeof(key_sek),key_sek },// FSB5
};
static const int fsbkey_list_count = sizeof(fsbkey_list) / sizeof(fsbkey_list[0]);

View File

@ -16,7 +16,7 @@ typedef enum {
DVI_IMA = 7, /* DVI IMA ADPCM (high nibble first) */
MPEG = 8, /* MPEG (MP3) */
IMA = 9, /* IMA ADPCM (low nibble first) */
AICA = 10, /* AICA ADPCM (Dreamcast games) */
YAMAHA = 10, /* YAMAHA (AICA) ADPCM (Dreamcast games) */
MSADPCM = 11, /* MS ADPCM (Windows games) */
NGC_DSP = 12, /* NGC DSP (Nintendo games) */
PCM8_U_int = 13, /* 8-bit unsigned PCM (interleaved) */
@ -33,7 +33,8 @@ typedef enum {
PCFX = 24, /* PC-FX ADPCM */
PCM4 = 25, /* 4-bit signed PCM (3rd and 4th gen games) */
PCM4_U = 26, /* 4-bit unsigned PCM (3rd and 4th gen games) */
OKI16 = 27, /* OKI ADPCM with 16-bit output (unlike OKI/VOX/Dialogic ADPCM's 12-bit) */
OKI16 = 27, /* OKI ADPCM with 16-bit output (unlike OKI/VOX/Dialogic ADPCM's 12-bit) */
AAC = 28, /* Advanced Audio Coding (raw without .mp4) */
} genh_type;
typedef struct {
@ -101,7 +102,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
case MPEG: coding = coding_MPEG_layer3; break; /* we later find out exactly which */
#endif
case IMA: coding = coding_IMA; break;
case AICA: coding = coding_AICA; break;
case YAMAHA: coding = coding_YAMAHA; break;
case MSADPCM: coding = coding_MSADPCM; break;
case NGC_DSP: coding = coding_NGC_DSP; break;
case PCM8_U_int: coding = coding_PCM8_U_int; break;
@ -115,6 +116,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
case XMA1:
case XMA2:
case AC3:
case AAC:
case FFMPEG: coding = coding_FFmpeg; break;
#endif
case PCFX: coding = coding_PCFX; break;
@ -151,7 +153,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
case coding_PSX_badflags:
case coding_DVI_IMA:
case coding_IMA:
case coding_AICA:
case coding_YAMAHA:
case coding_APPLE_IMA4:
vgmstream->interleave_block_size = genh.interleave;
vgmstream->interleave_last_block_size = genh.interleave_last;
@ -170,8 +172,8 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
coding = coding_DVI_IMA_int;
if (coding == coding_IMA)
coding = coding_IMA_int;
if (coding == coding_AICA)
coding = coding_AICA_int;
if (coding == coding_YAMAHA)
coding = coding_YAMAHA_int;
}
/* to avoid endless loops */
@ -188,10 +190,10 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
}
/* setup adpcm */
if (coding == coding_AICA || coding == coding_AICA_int) {
int i;
for (i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].adpcm_step_index = 0x7f;
if (coding == coding_YAMAHA || coding == coding_YAMAHA_int) {
int ch;
for (ch = 0; ch < vgmstream->channels; ch++) {
vgmstream->ch[ch].adpcm_step_index = 0x7f;
}
}
@ -293,7 +295,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
case coding_FFmpeg: {
ffmpeg_codec_data *ffmpeg_data = NULL;
if (genh.codec == FFMPEG || genh.codec == AC3) {
if (genh.codec == FFMPEG || genh.codec == AC3 || genh.codec == AAC) {
/* default FFmpeg */
ffmpeg_data = init_ffmpeg_offset(streamFile, genh.start_offset,genh.data_size);
if ( !ffmpeg_data ) goto fail;

View File

@ -1,18 +1,32 @@
#include "meta.h"
#include "../coding/coding.h"
VGMSTREAM * init_vgmstream_gin_header(STREAMFILE *streamFile, off_t offset);
/* .gin - EA engine sounds [Need for Speed: Most Wanted (multi)] */
VGMSTREAM * init_vgmstream_gin(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate, num_samples;
/* checks */
if (!check_extensions(streamFile, "gin"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x476E7375) /* "Gnsu" */
vgmstream = init_vgmstream_gin_header(streamFile, 0x00);
if (!vgmstream)
goto fail;
return vgmstream;
fail:
return NULL;
}
VGMSTREAM * init_vgmstream_gin_header(STREAMFILE *streamFile, off_t offset) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate, num_samples;
/* checks */
if (read_32bitBE(offset + 0x00, streamFile) != 0x476E7375) /* "Gnsu" */
goto fail;
/* contains mapped values for engine RPM sounds but we'll just play the whole thing */
@ -22,11 +36,11 @@ VGMSTREAM * init_vgmstream_gin(STREAMFILE *streamFile) {
/* 0x14: RPM ??? table size */
/* always LE even on X360/PS3 */
num_samples = read_32bitLE(0x18, streamFile);
sample_rate = read_32bitLE(0x1c, streamFile);
start_offset = 0x20 +
(read_32bitLE(0x10, streamFile) + 1) * 0x04 +
(read_32bitLE(0x14, streamFile) + 1) * 0x04;
num_samples = read_32bitLE(offset + 0x18, streamFile);
sample_rate = read_32bitLE(offset + 0x1c, streamFile);
start_offset = offset + 0x20 +
(read_32bitLE(offset + 0x10, streamFile) + 1) * 0x04 +
(read_32bitLE(offset + 0x14, streamFile) + 1) * 0x04;
channel_count = 1;
loop_flag = 0;
@ -40,10 +54,12 @@ VGMSTREAM * init_vgmstream_gin(STREAMFILE *streamFile) {
vgmstream->num_samples = num_samples;
vgmstream->coding_type = coding_EA_XAS_V0;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x13;
vgmstream->layout_type = layout_none;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
/* calculate size for TMX */
vgmstream->stream_size = (align_size_to_block(num_samples, 32) / 32) * 0x13;
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
goto fail;
return vgmstream;

View File

@ -129,4 +129,6 @@ done:
VGM_ASSERT(best_score > 1, "HCA: best key=%08x%08x (score=%i)\n",
(uint32_t)((*out_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*out_keycode & 0xFFFFFFFF), best_score);
VGM_ASSERT(best_score < 0, "HCA: key not found\n");
}

View File

@ -258,9 +258,6 @@ static const hcakey_info hcakey_list[] = {
// Onsen Musume: Yunohana Kore Kushon (Android) voices
{6667}, // 0000000000001A0B
/* Dragalia Lost (Cygames) [iOS/Android] */
{2967411924141, subkeys_dgl, sizeof(subkeys_dgl) / sizeof(subkeys_dgl[0]) }, // 000002B2E7889CAD
/* Libra of Precatus (Android) */
{0x6D8EFB700870FCD4}, // 6D8EFB700870FCD4
@ -273,6 +270,17 @@ static const hcakey_info hcakey_list[] = {
/* Kotodaman (Android) */
{19850716}, // 00000000012EE5DC
/* Puchiguru Love Live! (Android) */
{355541041372}, // 00000052C7E5C0DC
/* Dolls Order (Android) */
{153438415134838}, // 00008B8D2A3AA076
/* Fantasy Life Online (Android) */
{123456789}, // 00000000075BCD15
/* Dragalia Lost (Cygames) [iOS/Android] */
{2967411924141, subkeys_dgl, sizeof(subkeys_dgl) / sizeof(subkeys_dgl[0]) }, // 000002B2E7889CAD
};
#endif/*_HCA_KEYS_H_*/

View File

@ -4,48 +4,80 @@
/* AWB subkey tables */
static const uint16_t subkeys_dgl[] = { /* Dragalia Lost (Cygames) [iOS/Android] */
0x0152,0x0165,0x0192,0x01E8,0x0240,0x026B,0x02B8,0x0348,0x055E,0x0595,0x05DC,0x0606,0x0636,0x0690,0x06A1,0x06A4,
0x06B3,0x0760,0x0767,0x076E,0x076F,0x077B,0x07A6,0x07AA,0x07B4,0x07CC,0x080D,0x082B,0x084C,0x084E,0x0859,0x085B,
0x0861,0x0864,0x0865,0x0873,0x088A,0x089B,0x08A5,0x08A7,0x08C0,0x08C3,0x08C6,0x08D5,0x08D8,0x08E0,0x08E8,0x08EB,
0x08EF,0x08F0,0x0902,0x0908,0x090B,0x0916,0x0919,0x0923,0x0926,0x0929,0x092C,0x092D,0x092F,0x0942,0x0944,0x094C,
0x094E,0x0957,0x095F,0x0963,0x0964,0x096C,0x097B,0x097D,0x0988,0x099E,0x09AE,0x09C1,0x09C2,0x09C5,0x09C8,0x09D7,
0x09FF,0x0A00,0x0A02,0x0A12,0x0A16,0x0A19,0x0A25,0x0A2A,0x0A2F,0x0A30,0x0A31,0x0A3F,0x0A41,0x0A53,0x0A63,0x0A65,
0x0A6D,0x0A73,0x0A77,0x0A99,0x0A9A,0x0AA5,0x0AA8,0x0AB8,0x0AC2,0x0AC5,0x0ACC,0x0AE0,0x0AE3,0x0AEC,0x0B09,0x0B0C,
0x0B35,0x0B5B,0x0B6F,0x0B7C,0x0B8D,0x0BA1,0x0BB0,0x0BBE,0x0BC9,0x0BDE,0x0BEF,0x0C04,0x0C0F,0x0C30,0x0C8B,0x0C9A,
0x0C9F,0x0CA9,0x0CB9,0x0D71,0x0D7B,0x0DB0,0x0DCF,0x0DD4,0x0DE6,0x0E1C,0x0E66,0x0E9D,0x0EAF,0x0EBB,0x0FDA,0x102F,
0x103A,0x1074,0x10BF,0x10C7,0x1107,0x112F,0x113A,0x116F,0x11A6,0x11FB,0x1220,0x130E,0x1335,0x135B,0x13C0,0x1474,
0x1538,0x1585,0x15AD,0x15E1,0x1748,0x178C,0x1892,0x18A4,0x1944,0x197A,0x19F3,0x1A47,0x1A5B,0x1A89,0x1AAC,0x1BE2,
0x1C31,0x1C3B,0x1C7C,0x1C7E,0x1C89,0x1D01,0x1D0C,0x1D5A,0x1DA3,0x1E1E,0x1E88,0x1F0A,0x1F6D,0x1FC2,0x2000,0x2007,
0x208C,0x20E9,0x20EE,0x2120,0x2160,0x2161,0x216E,0x21CA,0x21DD,0x221E,0x2227,0x2265,0x2275,0x2277,0x22C4,0x22FA,
0x2330,0x2379,0x23C9,0x23D8,0x2415,0x243C,0x245A,0x24AD,0x24CD,0x2514,0x2540,0x2632,0x264C,0x269B,0x26B5,0x26C5,
0x26FC,0x2701,0x2709,0x274D,0x274E,0x2777,0x27EE,0x284B,0x2882,0x288C,0x28A9,0x28B6,0x292B,0x2930,0x29B0,0x29B2,
0x29D9,0x2A0A,0x2A47,0x2A55,0x2A5D,0x2ADB,0x2AE7,0x2D08,0x2DB0,0x2DB7,0x2DC3,0x2E6E,0x2E75,0x2E9E,0x2EB6,0x2ED8,
0x2F64,0x2F66,0x2F72,0x30BB,0x30CA,0x30E6,0x3160,0x3218,0x32E8,0x333F,0x338B,0x33BE,0x355A,0x357D,0x35DD,0x360C,
0x3619,0x36AA,0x3738,0x3752,0x37DE,0x3804,0x380C,0x3920,0x39DB,0x3C7B,0x3CA3,0x3D50,0x3EB2,0x3EF2,0x3F42,0x3F79,
0x4000,0x403D,0x40BF,0x40DE,0x413E,0x414F,0x41A3,0x42EA,0x434A,0x43D3,0x43E9,0x4411,0x4541,0x4663,0x4751,0x4793,
0x47DF,0x4840,0x487A,0x48D7,0x49B4,0x49E3,0x4B0E,0x4B21,0x4B8D,0x4C49,0x4C72,0x4D44,0x4D86,0x4DEA,0x4DF5,0x4E40,
0x4F60,0x4F92,0x4FF2,0x5137,0x5220,0x5493,0x54CE,0x552C,0x559B,0x5639,0x567C,0x56A1,0x56EE,0x5794,0x582E,0x5846,
0x586A,0x58B1,0x58C3,0x59A5,0x59EF,0x5A86,0x5B19,0x5B49,0x5B5C,0x5B90,0x5BCF,0x5C38,0x5C75,0x5C83,0x5D61,0x5DE0,
0x5E47,0x5E57,0x5ED5,0x5FAF,0x6000,0x601F,0x6071,0x6104,0x6188,0x6191,0x61B2,0x61EB,0x6226,0x627D,0x62F9,0x63DE,
0x645F,0x64D3,0x659D,0x65D3,0x65D4,0x65F2,0x6631,0x6914,0x6990,0x6993,0x6A52,0x6A85,0x6B16,0x6BF6,0x6CD6,0x6CE3,
0x6CF9,0x6CFA,0x6D0E,0x6D16,0x6D1E,0x6D3E,0x6D80,0x6DCF,0x6E73,0x6EC5,0x6F14,0x6FD0,0x7033,0x704C,0x7098,0x7242,
0x7278,0x72B7,0x7319,0x7427,0x7432,0x747F,0x7484,0x749D,0x74D7,0x74D8,0x756A,0x7576,0x7588,0x75A9,0x764D,0x773C,
0x7766,0x7895,0x78B0,0x78F3,0x7976,0x797F,0x798F,0x79AB,0x79E7,0x79F9,0x7A1D,0x7A24,0x7A47,0x7B64,0x7BBC,0x7C2E,
0x7CBA,0x7D0D,0x7D12,0x7E66,0x7EB5,0x7EBA,0x7EC5,0x7F1B,0x7F26,0x7F5F,0x7FC1,0x7FCE,0x7FFC,0x8000,0x8075,0x80B2,
0x80FF,0x81C8,0x826C,0x8274,0x82B5,0x8412,0x8458,0x8467,0x8533,0x8577,0x85FF,0x8658,0x86E3,0x86E6,0x878E,0x885E,
0x8A7E,0x8B1F,0x8B25,0x8B33,0x8B4D,0x8B80,0x8BFF,0x8C38,0x8D46,0x8D8B,0x8E10,0x8E79,0x8F01,0x8FF1,0x9000,0x9029,
0x9082,0x924A,0x92F8,0x9342,0x940C,0x94B9,0x9580,0x95ED,0x9630,0x97D1,0x97FC,0x9810,0x9825,0x9861,0x98FB,0x990E,
0x9970,0x9A37,0x9B36,0x9B67,0x9DBF,0x9FA3,0x9FF2,0xA000,0xA0A3,0xA0AA,0xA1C6,0xA27A,0xA2FB,0xA3AB,0xA3C2,0xA4E1,
0xA548,0xA553,0xA585,0xA6A7,0xA71C,0xA723,0xA77E,0xA7D6,0xA894,0xA8BF,0xA8E0,0xA90A,0xAA3A,0xAA57,0xAADF,0xAAF4,
0xAB0B,0xABF3,0xAC0C,0xAC23,0xAC55,0xAD00,0xADC4,0xADF1,0xAE02,0xAE16,0xAE6A,0xAEA7,0xAEB6,0xB040,0xB073,0xB122,
0xB14B,0xB175,0xB177,0xB25D,0xB262,0xB332,0xB378,0xB400,0xB52E,0xB54B,0xB592,0xB59C,0xB5AD,0xB5CE,0xB5D3,0xB5D5,
0xB613,0xB65D,0xB79F,0xB89D,0xB907,0xBC78,0xBCCC,0xBDBF,0xBE21,0xBF21,0xBF64,0xC13F,0xC2EA,0xC303,0xC385,0xC3C9,
0xC3D8,0xC452,0xC5CB,0xC5EB,0xC62D,0xC655,0xC67B,0xC6D9,0xC728,0xC8A8,0xCAF6,0xCDAC,0xCDF7,0xCE3B,0xD075,0xD163,
0xD203,0xD410,0xD49E,0xD70A,0xD718,0xD815,0xD876,0xD99C,0xDA29,0xDAA7,0xDBA0,0xDC8F,0xDCFA,0xDD3D,0xDD55,0xDE02,
0xDE30,0xE000,0xE02E,0xE073,0xE1C5,0xE1CD,0xE288,0xE3AE,0xE597,0xE5C3,0xE5E3,0xE652,0xE775,0xE930,0xE947,0xEC15,
0xEC1B,0xEC56,0xED0A,0xED93,0xED95,0xEDC2,0xEF7F,0xEFA6,0xEFB6,0xF049,0xF0C7,0xF107,0xF41F,0xF558,0xF5C8,0xF7DC,
0xF7ED,0xF89E,0xF8B2,0xF9C9,0xFAAA,0xFB77,0xFCAF,0xFCCA,0xFD01,0xFD13,0xFD57,0xFD68,0xFDDB,0xFE07,0xFF43,0xFF65,
0xFF85,0xFF8B,0xFF9A,0xFFD0,
0x0152,0x0165,0x0192,0x0240,0x024F,0x026B,0x026F,0x02B8,0x0348,0x037D,0x03C9,0x03DA,0x0440,0x0468,0x0526,0x0552,
0x055E,0x058C,0x0597,0x05DC,0x05F6,0x05FE,0x0606,0x064D,0x0661,0x0687,0x06CC,0x0752,0x07A1,0x07B9,0x07CD,0x07F7,
0x0823,0x08A5,0x08D8,0x08E1,0x08EF,0x09AC,0x09D7,0x0A9A,0x0AA8,0x0B0C,0x0B51,0x0BBA,0x0BBE,0x0C9A,0x0D71,0x0D7B,
0x0DCF,0x0DD4,0x0DF7,0x0E1C,0x0E4F,0x0E6A,0x0E9D,0x0EAF,0x0F2B,0x0F85,0x0FDA,0x1011,0x102F,0x103A,0x1041,0x1074,
0x107E,0x10BF,0x10C7,0x10E5,0x1102,0x1107,0x112F,0x113A,0x116A,0x116F,0x1182,0x11A6,0x11FA,0x1220,0x126A,0x1280,
0x12B8,0x12D7,0x130E,0x1335,0x135B,0x13C0,0x13C6,0x13EC,0x142C,0x1469,0x1474,0x14E4,0x1518,0x1536,0x1538,0x1585,
0x15AD,0x15E1,0x16F3,0x1748,0x1756,0x178C,0x179A,0x17F4,0x1802,0x184F,0x1892,0x1903,0x1944,0x198E,0x19A1,0x19F3,
0x1A0C,0x1A5B,0x1A89,0x1AAC,0x1AC7,0x1B11,0x1B92,0x1C31,0x1C7C,0x1C7E,0x1D01,0x1D0C,0x1D5A,0x1DC1,0x1DCF,0x1E3B,
0x1E64,0x1E72,0x1E88,0x1F90,0x1FAE,0x1FC2,0x208C,0x20E9,0x2106,0x2117,0x2122,0x2160,0x2161,0x216E,0x21BE,0x21FE,
0x2277,0x22D9,0x22FA,0x230C,0x23C9,0x23D8,0x2402,0x2415,0x243C,0x245A,0x24AD,0x2600,0x2632,0x266E,0x2692,0x269B,
0x26D4,0x26FC,0x2701,0x2723,0x274D,0x2777,0x27C2,0x27E7,0x27EE,0x2865,0x2882,0x28B2,0x28B6,0x2973,0x29B0,0x29B1,
0x2A04,0x2A33,0x2A55,0x2ADB,0x2AE7,0x2B48,0x2B7D,0x2BAA,0x2C09,0x2C2E,0x2C77,0x2D08,0x2D1F,0x2DAE,0x2DB0,0x2DB7,
0x2DE5,0x2DF5,0x2E6E,0x2E75,0x2E9E,0x2EB6,0x2EBF,0x2ED8,0x2EE7,0x2F54,0x2F66,0x2F72,0x2F83,0x2FCB,0x3046,0x30BB,
0x30BE,0x30CA,0x30E6,0x312C,0x3160,0x3180,0x31C7,0x31ED,0x31F8,0x3218,0x324D,0x32A9,0x32E8,0x32E9,0x32F9,0x3319,
0x333F,0x334E,0x336C,0x3373,0x338B,0x33AE,0x33BE,0x33FB,0x3459,0x3486,0x34A5,0x34A8,0x34C3,0x34C6,0x34EB,0x3527,
0x355A,0x357D,0x35DC,0x35F1,0x3619,0x3645,0x365C,0x36AA,0x36BC,0x3738,0x3745,0x3749,0x3752,0x3791,0x37C3,0x37DE,
0x3804,0x380A,0x380C,0x3818,0x3920,0x3946,0x3952,0x395C,0x3999,0x39D0,0x39DB,0x3AB7,0x3B79,0x3BBD,0x3BCE,0x3C7B,
0x3CA3,0x3D2C,0x3D50,0x3DA7,0x3DEF,0x3E7B,0x3E89,0x3EB2,0x3ED0,0x3EF2,0x3F18,0x3F42,0x3F79,0x4004,0x4069,0x406A,
0x40BF,0x40DE,0x410B,0x410F,0x413E,0x414F,0x416B,0x41A3,0x41B3,0x41BC,0x41E3,0x426E,0x4284,0x42EA,0x42EB,0x434A,
0x43D3,0x43E6,0x43E9,0x4411,0x444F,0x4457,0x449E,0x44B9,0x4541,0x458B,0x463E,0x4751,0x476E,0x477D,0x4793,0x47B2,
0x47D1,0x47DF,0x4840,0x487A,0x4894,0x48C5,0x48D7,0x49B4,0x49E3,0x4A52,0x4B03,0x4B0E,0x4B21,0x4B52,0x4B70,0x4B8D,
0x4B94,0x4BA7,0x4C14,0x4C49,0x4C72,0x4CBF,0x4D1F,0x4D35,0x4D44,0x4D86,0x4D9F,0x4DDC,0x4DF5,0x4E29,0x4E40,0x4E48,
0x4E5A,0x4E7C,0x4E93,0x4EE5,0x4F26,0x4F36,0x4F60,0x4F6C,0x4F92,0x4FAB,0x4FBB,0x4FE5,0x4FF2,0x5137,0x514C,0x51A9,
0x51B3,0x51F8,0x5220,0x5406,0x543B,0x5487,0x5493,0x5496,0x54B1,0x54CE,0x552C,0x558B,0x559B,0x55F4,0x5639,0x567C,
0x56A1,0x56EE,0x577B,0x5794,0x581E,0x582E,0x5846,0x586A,0x58B1,0x58C3,0x58C9,0x596A,0x59A5,0x59CD,0x59EF,0x59F7,
0x5A3C,0x5A81,0x5A86,0x5ABB,0x5AE5,0x5B0B,0x5B19,0x5B1C,0x5B49,0x5B5C,0x5B90,0x5BC1,0x5BC2,0x5BCF,0x5BD8,0x5BFE,
0x5C38,0x5C75,0x5C83,0x5C9C,0x5CFC,0x5D4D,0x5D54,0x5D61,0x5D70,0x5DE0,0x5DEF,0x5DFA,0x5E30,0x5E47,0x5E57,0x5E63,
0x5E74,0x5EB0,0x5EB3,0x5ED5,0x5F1B,0x5F5C,0x5F8F,0x5F9D,0x5FAF,0x5FD1,0x601F,0x6054,0x6062,0x6071,0x6073,0x60AA,
0x60CE,0x6104,0x6124,0x6149,0x617F,0x6188,0x618B,0x6191,0x61B2,0x61EB,0x61F3,0x621C,0x6226,0x623A,0x627D,0x627F,
0x62F9,0x6364,0x63DE,0x63F3,0x6452,0x645F,0x64A5,0x64AE,0x64D3,0x64E6,0x651A,0x659D,0x65D3,0x65D4,0x65F2,0x6631,
0x66F1,0x6739,0x68E0,0x6914,0x6955,0x697B,0x6990,0x6993,0x6A01,0x6A45,0x6A52,0x6A64,0x6A85,0x6AFA,0x6B08,0x6B16,
0x6B75,0x6B79,0x6BF6,0x6BF8,0x6C2F,0x6C3C,0x6CA5,0x6CBD,0x6CD6,0x6CE3,0x6CF9,0x6CFA,0x6D0E,0x6D16,0x6D1E,0x6D3E,
0x6D6F,0x6D80,0x6D8B,0x6DCF,0x6DFD,0x6E73,0x6EC5,0x6ECF,0x6F14,0x6F6F,0x6FD0,0x7033,0x704C,0x7098,0x7106,0x71A3,
0x721B,0x7235,0x7242,0x7278,0x72B7,0x7319,0x7359,0x73B9,0x73F5,0x7427,0x742F,0x7432,0x7452,0x745F,0x747F,0x7484,
0x749D,0x74C8,0x74D7,0x74D8,0x74FB,0x74FE,0x756A,0x7575,0x7576,0x7588,0x75A9,0x75DE,0x7604,0x7640,0x764D,0x773C,
0x7742,0x7751,0x7766,0x77C3,0x77D7,0x77E6,0x7860,0x786B,0x7895,0x78B0,0x78F1,0x78F3,0x7976,0x797F,0x798A,0x798F,
0x79AB,0x79E7,0x79F9,0x7A1D,0x7A24,0x7A47,0x7A6B,0x7AB5,0x7AE2,0x7B64,0x7B68,0x7BBC,0x7C2E,0x7C77,0x7C7D,0x7C8A,
0x7CBA,0x7D0D,0x7D12,0x7D2C,0x7E0E,0x7E4B,0x7E66,0x7E9D,0x7EB5,0x7EBA,0x7EC5,0x7F10,0x7F17,0x7F1B,0x7F26,0x7F5F,
0x7FB8,0x7FC1,0x7FCE,0x7FFC,0x8075,0x80A2,0x80A5,0x80B2,0x80CB,0x80E7,0x80FF,0x8116,0x8183,0x81C8,0x8205,0x826C,
0x8274,0x82B5,0x82FD,0x830D,0x8330,0x833C,0x8346,0x8349,0x8412,0x8413,0x8458,0x8467,0x8486,0x849D,0x8533,0x8540,
0x8577,0x8586,0x858E,0x85AD,0x85FF,0x862D,0x863D,0x863E,0x8658,0x86E3,0x86E6,0x86E9,0x8739,0x873C,0x878E,0x8797,
0x879F,0x87EB,0x87FD,0x8801,0x8812,0x8828,0x885E,0x88C3,0x890D,0x891F,0x899E,0x89BA,0x89D9,0x8A0F,0x8A7E,0x8A87,
0x8AC1,0x8B1F,0x8B25,0x8B33,0x8B4D,0x8B76,0x8B80,0x8BFF,0x8C38,0x8C4A,0x8CF2,0x8D46,0x8D86,0x8D8B,0x8DAE,0x8DEF,
0x8E10,0x8E79,0x8F01,0x8F7C,0x8FCF,0x8FF1,0x9000,0x9029,0x9082,0x9130,0x9166,0x91D6,0x924A,0x9277,0x92F8,0x9342,
0x9375,0x940C,0x942A,0x9496,0x94B9,0x94D3,0x9512,0x9521,0x953A,0x9551,0x9580,0x95ED,0x9625,0x962D,0x9630,0x963A,
0x9664,0x96EF,0x971B,0x97D1,0x97FC,0x9810,0x981A,0x9825,0x9828,0x9861,0x98E3,0x98FB,0x990E,0x9970,0x998A,0x99A2,
0x99DA,0x99F8,0x9A37,0x9A6F,0x9A8A,0x9AFE,0x9B06,0x9B36,0x9B54,0x9B67,0x9B81,0x9B91,0x9CC5,0x9D17,0x9D41,0x9D99,
0x9DBF,0x9DEA,0x9E16,0x9E1D,0x9E5A,0x9EAC,0x9F39,0x9FA3,0x9FED,0x9FF2,0xA020,0xA03C,0xA081,0xA0A3,0xA0AA,0xA145,
0xA1C6,0xA221,0xA27A,0xA2FB,0xA3AB,0xA3C2,0xA457,0xA458,0xA49E,0xA4E1,0xA548,0xA553,0xA585,0xA597,0xA5EA,0xA655,
0xA6A7,0xA6D9,0xA6F6,0xA71C,0xA723,0xA75F,0xA77E,0xA7D6,0xA88B,0xA894,0xA8BF,0xA8C8,0xA8E0,0xA90A,0xA933,0xAA21,
0xAA3A,0xAA57,0xAA5E,0xAADF,0xAAF4,0xAB0B,0xAB52,0xAB8F,0xABC3,0xABD3,0xABF3,0xAC0C,0xAC23,0xAC55,0xACCF,0xACD5,
0xACDF,0xAD00,0xAD12,0xADC4,0xADF1,0xAE02,0xAE16,0xAE45,0xAE6A,0xAEA7,0xAEB6,0xAFFA,0xB015,0xB040,0xB05B,0xB073,
0xB099,0xB10A,0xB122,0xB14B,0xB155,0xB160,0xB175,0xB177,0xB221,0xB238,0xB25D,0xB262,0xB271,0xB30B,0xB332,0xB378,
0xB3FF,0xB400,0xB437,0xB473,0xB4A9,0xB4F1,0xB52E,0xB54B,0xB556,0xB57D,0xB592,0xB59C,0xB5AD,0xB5CE,0xB5D3,0xB5D5,
0xB603,0xB613,0xB65D,0xB75E,0xB761,0xB79F,0xB7A0,0xB7BC,0xB7C3,0xB7F8,0xB893,0xB89D,0xB8F5,0xB907,0xB989,0xB9B8,
0xBAE5,0xBB0D,0xBB0F,0xBBA3,0xBBBC,0xBBD3,0xBBE4,0xBC3D,0xBC78,0xBC98,0xBCCC,0xBD5D,0xBD67,0xBDBF,0xBE10,0xBE21,
0xBE57,0xBEA2,0xBEBF,0xBF21,0xBF22,0xBF3F,0xBF64,0xBF8B,0xC01B,0xC022,0xC036,0xC041,0xC04D,0xC055,0xC075,0xC095,
0xC0B4,0xC0DC,0xC0E4,0xC133,0xC13F,0xC156,0xC1DB,0xC2EA,0xC303,0xC36C,0xC385,0xC394,0xC3C9,0xC3D8,0xC3DB,0xC434,
0xC452,0xC4AD,0xC5CB,0xC5E0,0xC5EB,0xC5F2,0xC625,0xC62D,0xC655,0xC67B,0xC68E,0xC6B3,0xC6D9,0xC709,0xC728,0xC78E,
0xC7A4,0xC838,0xC873,0xC887,0xC8A1,0xC8A8,0xC8E6,0xC8F6,0xC952,0xC98B,0xC9AD,0xCA13,0xCA4D,0xCA99,0xCAB9,0xCAF6,
0xCB1B,0xCBC1,0xCBE6,0xCC3F,0xCC77,0xCD13,0xCDAC,0xCDC5,0xCDF7,0xCE16,0xCE32,0xCE3B,0xCEB8,0xCF0F,0xCF80,0xCFF7,
0xD062,0xD075,0xD0B2,0xD0D5,0xD159,0xD163,0xD19D,0xD1DD,0xD1E9,0xD203,0xD23D,0xD2AB,0xD2B1,0xD2E0,0xD305,0xD410,
0xD422,0xD446,0xD47B,0xD47F,0xD493,0xD49E,0xD591,0xD59C,0xD5A0,0xD70A,0xD710,0xD718,0xD815,0xD876,0xD91D,0xD921,
0xD96B,0xD99C,0xDA29,0xDA77,0xDAA7,0xDB38,0xDBA0,0xDC31,0xDC33,0xDC5A,0xDC8F,0xDCFA,0xDD0B,0xDD3D,0xDD55,0xDE02,
0xDE30,0xDE57,0xDE8A,0xDED3,0xDED7,0xDF38,0xDF9A,0xE02E,0xE073,0xE114,0xE125,0xE164,0xE195,0xE1A6,0xE1C5,0xE1CD,
0xE1D5,0xE1D6,0xE1F1,0xE222,0xE22C,0xE25F,0xE288,0xE297,0xE3A0,0xE3AE,0xE3D3,0xE405,0xE434,0xE437,0xE49D,0xE4AC,
0xE4BE,0xE50E,0xE51F,0xE52F,0xE53B,0xE597,0xE5A9,0xE5C3,0xE5E3,0xE5F1,0xE652,0xE659,0xE6AA,0xE6D7,0xE6DF,0xE6EE,
0xE76D,0xE775,0xE795,0xE7A2,0xE7B5,0xE7CE,0xE8DD,0xE8EB,0xE930,0xE944,0xE947,0xE99F,0xEA1C,0xEACB,0xEBBA,0xEC15,
0xEC1B,0xEC36,0xEC56,0xED0A,0xED17,0xED24,0xED5A,0xED87,0xED93,0xED95,0xED99,0xEDC2,0xEDEB,0xEE1F,0xEEC6,0xEF04,
0xEF63,0xEF7F,0xEFA6,0xEFB6,0xEFCC,0xEFD1,0xEFD8,0xF00A,0xF049,0xF055,0xF0C7,0xF107,0xF108,0xF132,0xF16D,0xF1E7,
0xF221,0xF24B,0xF2E3,0xF2F6,0xF32A,0xF3FE,0xF412,0xF41F,0xF429,0xF4F7,0xF52B,0xF558,0xF585,0xF5C8,0xF66E,0xF675,
0xF685,0xF6A3,0xF6D7,0xF78A,0xF7A6,0xF7D7,0xF7DC,0xF7ED,0xF82E,0xF84C,0xF89E,0xF8B2,0xF982,0xF9A9,0xF9C9,0xFA0B,
0xFA6B,0xFAAA,0xFB77,0xFCAF,0xFCB8,0xFCCA,0xFD01,0xFD0B,0xFD13,0xFD38,0xFD57,0xFD5D,0xFD68,0xFD6D,0xFD86,0xFDDB,
0xFDDC,0xFE07,0xFE33,0xFEA6,0xFF43,0xFF48,0xFF65,0xFF85,0xFF8B,0xFF8C,0xFF9A,0xFFD0,
};
#if 0

View File

@ -0,0 +1,125 @@
#include "meta.h"
#include "../coding/coding.h"
/* IKM - MiCROViSiON PS2 container [Zwei (PS2)] */
VGMSTREAM * init_vgmstream_ikm_ps2(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
/* checks */
if ( !check_extensions(streamFile,"ikm") )
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x494B4D00) /* "IKM\0" */
goto fail;
if (read_32bitBE(0x40,streamFile) != 0x41535400) /* "AST\0" */
goto fail;
/* 0x20: type 03? */
loop_flag = (read_32bitLE(0x14, streamFile) > 0);
channel_count = read_32bitLE(0x50, streamFile);
start_offset = 0x800;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_IKM;
vgmstream->sample_rate = read_32bitLE(0x44, streamFile);
vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x4c, streamFile), channel_count);
vgmstream->loop_start_sample = read_32bitLE(0x14, streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x18, streamFile);
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10; /* @0x40 / channels */
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* IKM - MiCROViSiON PC container [Chaos Legion (PC)] */
VGMSTREAM * init_vgmstream_ikm_pc(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
/* checks */
if ( !check_extensions(streamFile,"ikm") )
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x494B4D00) /* "IKM\0" */
goto fail;
if (read_32bitBE(0x30,streamFile) != 0x4F676753) /* "OggS" */
goto fail;
/* 0x20: type 01? */
start_offset = 0x30;
#ifdef VGM_USE_VORBIS
{
ogg_vorbis_meta_info_t ovmi = {0};
ovmi.meta_type = meta_IKM;
ovmi.loop_start = read_32bitLE(0x14, streamFile);
ovmi.loop_end = read_32bitLE(0x18, streamFile);
ovmi.loop_end_found = ovmi.loop_end;
ovmi.loop_flag = ovmi.loop_end > 0;
ovmi.stream_size = read_32bitLE(0x24, streamFile);
vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
}
#else
goto fail;
#endif
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* IKM - MiCROViSiON PSP container [The Legend of Heroes: A Tear of Vermillion (PSP)] */
VGMSTREAM * init_vgmstream_ikm_psp(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
off_t start_offset;
size_t data_size;
/* checks */
if ( !check_extensions(streamFile,"ikm") )
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x494B4D00) /* "IKM\0" */
goto fail;
if (read_32bitBE(0x800,streamFile) != 0x52494646) /* "RIFF" */
goto fail;
/* 0x20: type 00? */
/* loop values (pre-adjusted without encoder delay) at 0x14/18 are found in the RIFF too */
data_size = read_32bitLE(0x24, streamFile);
start_offset = 0x800;
temp_streamFile = setup_subfile_streamfile(streamFile, start_offset, data_size, "at3");
if (!temp_streamFile) goto fail;
vgmstream = init_vgmstream_riff(temp_streamFile);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_IKM;
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -29,19 +29,9 @@ VGMSTREAM * init_vgmstream_imc(STREAMFILE *streamFile) {
if (interleave*blocks + start_offset != file_size)
goto fail;
/* remove padding (important to play gapless subsongs, happens even for mono) */
{
off_t min_offset = file_size - interleave;
off_t offset = file_size - 0x10;
data_size = file_size - start_offset;
data_size -= ps_find_padding(streamFile, start_offset, data_size, channel_count, interleave, 0);
data_size = file_size - start_offset;
while (offset > min_offset) {
if (read_32bitLE(offset, streamFile) != 0)
break;
data_size -= 0x10*channel_count;
offset -= 0x10;
}
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);

View File

@ -4,10 +4,10 @@
VGMSTREAM * init_vgmstream_ktss(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int loop_flag, channel_count;
int8_t version;
int8_t version, num_layers, codec_id;
int32_t loop_length, coef_start_offset, coef_spacing;
off_t start_offset;
int8_t channelMultiplier;
size_t data_size, skip = 0;
if (!check_extensions(streamFile, "kns,ktss"))
goto fail;
@ -15,30 +15,18 @@ VGMSTREAM * init_vgmstream_ktss(STREAMFILE *streamFile) {
if (read_32bitBE(0, streamFile) != 0x4B545353) /* "KTSS" */
goto fail;
/* check type details */
version = read_8bit(0x22, streamFile);
if (version == 1) {
coef_start_offset = 0x40;
coef_spacing = 0x2e;
}
else if (version == 3) { // Fire Emblem Warriors (Switch)
coef_start_offset = 0x5c;
coef_spacing = 0x60;
}
else
goto fail;
codec_id = read_8bit(0x20, streamFile);
loop_length = read_32bitLE(0x38, streamFile);
loop_flag = loop_length > 0;
// For unknown reasons, a channel multiplier is necessary in Hyrule Warriors (Switch)
// It seems to be present in other Koei Tecmo KNS but the channel count was always
// explicitly defined in the 0x29 byte. Here, 10 channel files have '2' in 0x29*
// and '5' in 0x28 whereas previous titles usually contained '1'
// This is super meh on KT's part but whatever
channelMultiplier = read_8bit(0x28, streamFile);
// A layered stream/track model seems to be used in Hyrule Warriors (Switch).
// It's also present in other Koei Tecmo KNS but the channel count was always
// explicitly defined in the 0x29 byte and the number of layers was set to 1.
// Here, 10 channel files are set up with 2 channels in 5 layers.
// Super hacky on KT's part and ours to implement but it works.
num_layers = read_8bit(0x28, streamFile);
channel_count = read_8bit(0x29, streamFile) * channelMultiplier;
channel_count = read_8bit(0x29, streamFile) * num_layers;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
@ -46,19 +34,53 @@ VGMSTREAM * init_vgmstream_ktss(STREAMFILE *streamFile) {
/* fill in the vital statistics */
vgmstream->num_samples = read_32bitLE(0x30, streamFile);
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x2c, streamFile);
vgmstream->sample_rate = read_32bitLE(0x2c, streamFile);
vgmstream->loop_start_sample = read_32bitLE(0x34, streamFile);
vgmstream->loop_end_sample = vgmstream->loop_start_sample + loop_length;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->meta_type = meta_KTSS;
vgmstream->interleave_block_size = 0x8;
dsp_read_coefs_le(vgmstream, streamFile, coef_start_offset, coef_spacing);
start_offset = read_32bitLE(0x24, streamFile) + 0x20;
switch (codec_id) {
case 0x2: /* DSP ADPCM - Hyrule Warriors, Fire Emblem Warriors, and other Koei Tecmo games */
/* check type details */
version = read_8bit(0x22, streamFile);
if (version == 1) {
coef_start_offset = 0x40;
coef_spacing = 0x2e;
}
else if (version == 3) { // Fire Emblem Warriors (Switch)
coef_start_offset = 0x5c;
coef_spacing = 0x60;
}
else
goto fail;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x8;
dsp_read_coefs_le(vgmstream, streamFile, coef_start_offset, coef_spacing);
break;
#ifdef VGM_USE_FFMPEG
case 0x9: /* Opus - Dead or Alive Xtreme 3: Scarlet */
data_size = read_32bitLE(0x44, streamFile);
{
vgmstream->codec_data = init_ffmpeg_switch_opus(streamFile, start_offset, data_size, vgmstream->channels, skip, vgmstream->sample_rate);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
if (vgmstream->num_samples == 0) {
vgmstream->num_samples = switch_opus_get_samples(start_offset, data_size, streamFile) - skip;
}
}
break;
default:
goto fail;
#endif
}
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
goto fail;
return vgmstream;

View File

@ -49,6 +49,7 @@ VGMSTREAM * init_vgmstream_dsp_switch_audio(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_dsp_sps_n1(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_dsp_itl_ch(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_dsp_adpcmx(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_dsp_ds2(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_csmp(STREAMFILE *streamFile);
@ -57,7 +58,7 @@ VGMSTREAM * init_vgmstream_rfrm(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ps2_ads_container(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ps2_npsf(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_nps(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_rs03(STREAMFILE *streamFile);
@ -116,6 +117,7 @@ typedef struct {
off_t stream_size;
int total_subsongs;
int disable_reordering;
/* decryption setup */
void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource);
@ -209,7 +211,9 @@ VGMSTREAM * init_vgmstream_leg(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_filp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ikm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ikm_ps2(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ikm_pc(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ikm_psp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_sfs(STREAMFILE * streamFile);
@ -358,7 +362,7 @@ VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_vgs(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_dc_dcsw_dcs(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_dcs_wav(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_mul(STREAMFILE * streamFile);
@ -511,7 +515,7 @@ VGMSTREAM * init_vgmstream_ngc_nst_dsp(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_baf(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_baf_badrip(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_msf(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_nub_vag(STREAMFILE* streamFile);
@ -550,7 +554,7 @@ VGMSTREAM * init_vgmstream_pc_adp_otns(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_eb_sfx(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_eb_sf0(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_mtaf(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_mtaf(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_tun(STREAMFILE* streamFile);
@ -627,7 +631,8 @@ VGMSTREAM * init_vgmstream_ta_aac_vita(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_va3(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ps3_mta2(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_mta2(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_mta2_container(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ngc_ulw(STREAMFILE * streamFile);
@ -638,6 +643,7 @@ VGMSTREAM * init_vgmstream_wii_04sw(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_txth(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ea_schl_video(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_hdr_dat(STREAMFILE * streamFile);
@ -670,6 +676,7 @@ VGMSTREAM * init_vgmstream_naac(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ubi_sm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ubi_bnm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ezw(STREAMFILE * streamFile);
@ -681,6 +688,7 @@ VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_abk_eaac(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_tmx(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE * streamFile);
@ -830,4 +838,20 @@ VGMSTREAM * init_vgmstream_dsf(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_208(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ffdl(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_mus_vc(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_strm_abylight(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_sfh(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_msf_konami(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_xwma_konami(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_9tav(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_fsb5_fev_bank(STREAMFILE * streamFile);
#endif /*_META_H*/

View File

@ -7,7 +7,7 @@ VGMSTREAM * init_vgmstream_mib_mih(STREAMFILE *streamFile) {
STREAMFILE * streamHeader = NULL;
off_t start_offset;
size_t data_size, frame_size, frame_last, frame_count;
int channel_count, loop_flag;
int channel_count, loop_flag, sample_rate;
/* check extension */
if (!check_extensions(streamFile, "mib"))
@ -19,20 +19,22 @@ VGMSTREAM * init_vgmstream_mib_mih(STREAMFILE *streamFile) {
if (read_32bitBE(0x00,streamHeader) != 0x40000000) /* header size */
goto fail;
loop_flag = 0; /* MIB+MIH don't PS-ADPCM loop flags */
channel_count = read_32bitLE(0x08,streamHeader);
loop_flag = 0; /* MIB+MIH don't loop (nor use PS-ADPCM flags) per spec */
start_offset = 0x00;
/* 0x04: padding (0x20, MIH header must be multiple of 0x40) */
frame_last = (uint16_t)read_16bitLE(0x05,streamHeader);
frame_size = read_32bitLE(0x10,streamHeader);
frame_count = read_32bitLE(0x14,streamHeader);
/* 0x04: padding size (always 0x20, MIH header must be multiple of 0x40) */
frame_last = (uint32_t)read_32bitLE(0x05,streamHeader) & 0x00FFFFFF; /* 24b */
channel_count = read_32bitLE(0x08,streamHeader);
sample_rate = read_32bitLE(0x0c,streamHeader);
frame_size = read_32bitLE(0x10,streamHeader);
frame_count = read_32bitLE(0x14,streamHeader);
if (frame_count == 0) { /* rarely [Gladius (PS2)] */
frame_count = get_streamfile_size(streamFile) / (frame_size * channel_count);
}
data_size = frame_count * frame_size;
data_size -= frame_last ? (frame_size-frame_last) : 0; /* last frame has less usable data */
if (frame_last)
data_size -= frame_size - frame_last; /* last frame has less usable data */
data_size *= channel_count;
@ -40,7 +42,7 @@ VGMSTREAM * init_vgmstream_mib_mih(STREAMFILE *streamFile) {
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(0x0C,streamHeader);
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
vgmstream->meta_type = meta_PS2_MIB_MIH;

View File

@ -171,11 +171,10 @@ VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset = 0;
int loop_flag = 0;
int32_t num_samples = 0, loop_start_sample = 0, loop_end_sample = 0;
int32_t loop_start_sample = 0, loop_end_sample = 0;
size_t filesize;
off_t atom_offset;
size_t atom_size;
int is_ffdl = 0;
ffmpeg_codec_data *ffmpeg_data = NULL;
@ -188,31 +187,6 @@ VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE *streamFile) {
filesize = streamFile->get_size(streamFile);
/* check header for Final Fantasy Dimensions */
if (read_32bitBE(0x00,streamFile) == 0x4646444C) { /* "FFDL" (any kind of file) */
is_ffdl = 1;
if (read_32bitBE(0x04,streamFile) == 0x6D747873) { /* "mtxs" (bgm file) */
/* this value is erratic so we'll use FFmpeg's num_samples
* (can be bigger = silence-padded, or smaller = cut; doesn't matter for looping though)*/
num_samples = read_32bitLE(0x08,streamFile);
/* loop samples are within num_samples, and don't have encoder delay (loop_start=0 starts from encoder_delay) */
loop_start_sample = read_32bitLE(0x0c,streamFile);
loop_end_sample = read_32bitLE(0x10,streamFile);
loop_flag = !(loop_start_sample==0 && loop_end_sample==num_samples);
start_offset = 0x14;
/* some FFDL have muxed streams ("FFDL" + "mtxs" data1 + mp4 data1 + "mtxs" data2 + mp4 data2 + etc)
* check if there is anything after the first mp4 data */
if (!find_atom_be(streamFile, 0x6D646174, start_offset, &atom_offset, &atom_size)) goto fail; /* "mdat" */
if (atom_offset-8 + atom_size < filesize && read_32bitBE(atom_offset-8 + atom_size,streamFile) == 0x6D747873) { /*"mtxs"*/
VGM_LOG("FFDL: multiple streams found\n");
filesize = atom_offset-8 + atom_size; /* clamp size, though FFmpeg will ignore the extra data anyway */
}
} else {
start_offset = 0x4; /* some SEs contain "ftyp" after "FFDL" */
}
}
/* check header */
if ( read_32bitBE(start_offset+0x04,streamFile) != 0x66747970) /* atom size @0x00 + "ftyp" @0x04 */
goto fail;
@ -221,7 +195,7 @@ VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE *streamFile) {
if ( !ffmpeg_data ) goto fail;
/* Tales of Hearts iOS has loop info in the first "free" atom */
if (!is_ffdl && find_atom_be(streamFile, 0x66726565, start_offset, &atom_offset, &atom_size)) { /* "free" */
if (find_atom_be(streamFile, 0x66726565, start_offset, &atom_offset, &atom_size)) { /* "free" */
if (read_32bitBE(atom_offset,streamFile) == 0x4F700002
&& (atom_size == 0x38 || atom_size == 0x40)) { /* make sure it's ToHr "free" */
/* 0x00: id? 0x04/8: s_rate; 0x10: num_samples (without padding, same as FFmpeg's) */
@ -242,12 +216,13 @@ VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE *streamFile) {
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_MP4;
vgmstream->num_samples = ffmpeg_data->totalSamples;
vgmstream->sample_rate = ffmpeg_data->sampleRate;
vgmstream->channels = ffmpeg_data->channels;
vgmstream->num_samples = ffmpeg_data->totalSamples;
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->channel_layout = ffmpeg_get_channel_layout(vgmstream->codec_data);
return vgmstream;
fail:
@ -259,11 +234,7 @@ fail:
return NULL;
}
/**
* Almost the same as streamfile.c's find_chunk but for "atom" chunks, which have chunk_size first because Apple.
*
* returns 0 on failure
*/
/* Almost the same as streamfile.c's find_chunk but for "atom" chunks, which have chunk_size first because Apple, returns 0 on failure */
static int find_atom_be(STREAMFILE *streamFile, uint32_t atom_id, off_t start_offset, off_t *out_atom_offset, size_t *out_atom_size) {
size_t filesize;
off_t current_atom = start_offset;

View File

@ -2,12 +2,12 @@
#include "../coding/coding.h"
/* MSF - Sony's PS3 SDK format (MultiStream File) */
VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
VGMSTREAM * init_vgmstream_msf(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
uint32_t data_size, loop_start = 0, loop_end = 0;
uint32_t id, codec_id, flags;
int loop_flag = 0, channel_count;
uint32_t codec, flags;
int loop_flag, channel_count, sample_rate;
/* checks */
@ -17,19 +17,19 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
if (!check_extensions(streamFile,"msf,at3,mp3"))
goto fail;
start_offset = 0x40;
/* check header "MSF" + version-char, usually:
* 0x01, 0x02, 0x30 ("0"), 0x35 ("5"), 0x43 ("C") (last/most common version) */
id = read_32bitBE(0x00,streamFile);
if ((id & 0xffffff00) != 0x4D534600) goto fail;
if ((read_32bitBE(0x00,streamFile) & 0xffffff00) != 0x4D534600) /* "MSF\0" */
goto fail;
start_offset = 0x40;
codec_id = read_32bitBE(0x04,streamFile);
codec = read_32bitBE(0x04,streamFile);
channel_count = read_32bitBE(0x08,streamFile);
data_size = read_32bitBE(0x0C,streamFile); /* without header */
if (data_size == 0xFFFFFFFF) /* unneeded? */
data_size = get_streamfile_size(streamFile) - start_offset;
sample_rate = read_32bitBE(0x10,streamFile);
/* byte flags, not in MSFv1 or v2
* 0x01/02/04/08: loop marker 0/1/2/3
@ -56,17 +56,15 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitBE(0x10,streamFile);
/* sample rate hack for strange MSFv1 files (PS ADPCM only?) */
if (vgmstream->sample_rate == 0x00000000)
vgmstream->sample_rate = 48000;
vgmstream->meta_type = meta_MSF;
vgmstream->sample_rate = sample_rate;
if (vgmstream->sample_rate == 0) /* some MSFv1 (PS-ADPCM only?) [Megazone 23 - Aoi Garland (PS3)] */
vgmstream->sample_rate = 48000;
vgmstream->meta_type = meta_PS3_MSF;
switch (codec_id) {
switch (codec) {
case 0x00: /* PCM (Big Endian) */
case 0x01: { /* PCM (Little Endian) [Smash Cars (PS3)] */
vgmstream->coding_type = codec_id==0 ? coding_PCM16BE : coding_PCM16LE;
vgmstream->coding_type = codec==0 ? coding_PCM16BE : coding_PCM16LE;
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
vgmstream->interleave_block_size = 2;
@ -85,7 +83,7 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
case 0x03: { /* PS ADPCM [Smash Cars (PS3)] */
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
@ -105,8 +103,8 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
uint8_t buf[100];
int32_t bytes, block_size, encoder_delay, joint_stereo;
block_size = (codec_id==4 ? 0x60 : (codec_id==5 ? 0x98 : 0xC0)) * vgmstream->channels;
joint_stereo = (codec_id==4); /* interleaved joint stereo (ch must be even) */
block_size = (codec==4 ? 0x60 : (codec==5 ? 0x98 : 0xC0)) * vgmstream->channels;
joint_stereo = (codec==4); /* interleaved joint stereo (ch must be even) */
/* MSF skip samples: from tests with MSEnc and real files (ex. TTT2 eddy.msf v43, v01 demos) seems like 1162 is consistent.
* Atelier Rorona bt_normal01 needs it to properly skip the beginning garbage but usually doesn't matter.

View File

@ -19,7 +19,7 @@ VGMSTREAM * init_vgmstream_msf_banpresto_wmsf(STREAMFILE *streamFile) {
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
if (!temp_streamFile) goto fail;
vgmstream = init_vgmstream_ps3_msf(temp_streamFile);
vgmstream = init_vgmstream_msf(temp_streamFile);
if (!vgmstream) goto fail;
close_streamfile(temp_streamFile);

View File

@ -0,0 +1,58 @@
#include "meta.h"
#include "../coding/coding.h"
/* MSFC - Konami (Armature?) variation [Metal Gear Solid 2 HD (PS3), Metal Gear Solid 3 HD (PS3)] */
VGMSTREAM * init_vgmstream_msf_konami(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
uint32_t codec;
int loop_flag, channel_count, sample_rate;
size_t data_size;
/* checks */
if (!check_extensions(streamFile,"msf"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4D534643) /* "MSFC" */
goto fail;
start_offset = 0x20;
codec = read_32bitBE(0x04,streamFile);
channel_count = read_32bitBE(0x08,streamFile);
sample_rate = read_32bitBE(0x0c,streamFile);
data_size = read_32bitBE(0x10,streamFile); /* without header */
if (data_size + start_offset != get_streamfile_size(streamFile))
goto fail;
loop_flag = 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_MSF_KONAMI;
vgmstream->sample_rate = sample_rate;
switch (codec) {
case 0x01:
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
break;
default:
goto fail;
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -0,0 +1,133 @@
#include "meta.h"
#include "mta2_streamfile.h"
/* MTA2 - found in Metal Gear Solid 4 (PS3) */
VGMSTREAM * init_vgmstream_mta2(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate;
int32_t loop_start, loop_end;
uint32_t sample_rate_int;
/* checks */
if ( !check_extensions(streamFile,"mta2"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4d544132) /* "MTA2" */
goto fail;
/* allow truncated files for now? */
//if (read_32bitBE(0x04, streamFile) + 0x08 != get_streamfile_size(streamFile))
// goto fail;
/* base header (everything is very similar to MGS3's MTAF but BE) */
/* 0x08(4): version? (1), 0x0c(52): null */
/* HEAD chunk */
if (read_32bitBE(0x40, streamFile) != 0x48454144) /* "HEAD" */
goto fail;
if (read_32bitBE(0x44, streamFile) != 0xB0) /* HEAD size */
goto fail;
/* 0x48(4): null, 0x4c: ? (0x10), 0x50(4): 0x7F (vol?), 0x54(2): 0x40 (pan?) */
channel_count = read_16bitBE(0x56, streamFile); /* counting all tracks */
/* 0x60(4): full block size (0x110 * channels), indirectly channels_per_track = channels / (block_size / 0x110) */
/* 0x80 .. 0xf8: null */
loop_start = read_32bitBE(0x58, streamFile);
loop_end = read_32bitBE(0x5c, streamFile);
loop_flag = (loop_start != loop_end); /* also flag possibly @ 0x73 */
#if 0
/* those values look like some kind of loop offsets */
if (loop_start/0x100 != read_32bitBE(0x68, streamFile) ||
loop_end /0x100 != read_32bitBE(0x6C, streamFile) ) {
VGM_LOG("MTA2: wrong loop points\n");
goto fail;
}
#endif
sample_rate_int = read_32bitBE(0x7c, streamFile);
if (sample_rate_int) { /* sample rate in 32b float (WHY?) typically 48000.0 */
float* sample_float = (float*)&sample_rate_int;
sample_rate = (int)*sample_float;
} else { /* default when not specified (most of the time) */
sample_rate = 48000;
}
/* TRKP chunks (x16) */
/* just seem to contain pan/vol stuff (0x7f/0x40), TRKP per track (sometimes +1 main track?) */
/* there is channel layout bitmask at 0x0f (ex. 1ch = 0x04, 3ch = 0x07, 4ch = 0x33, 6ch = 0x3f), surely:
* FL 0x01, FR 0x02, FC = 0x04, BL = 0x08, BR = 0x10, BC = 0x20 */
start_offset = 0x800;
/* DATA chunk */
if (read_32bitBE(0x7f8, streamFile) != 0x44415441) // "DATA"
goto fail;
//if (read_32bitBE(0x7fc, streamFile) + start_offset != get_streamfile_size(streamFile))
// goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = loop_end;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->coding_type = coding_MTA2;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_MTA2;
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* ****************************************************************************** */
/* MTA2 in containers */
VGMSTREAM * init_vgmstream_mta2_container(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
off_t subfile_offset;
/* checks */
/* .dbm: iPod metadata + mta2 with KCEJ blocks, .bgm: mta2 with KCEJ blocks (fake?) */
if ( !check_extensions(streamFile,"dbm,bgm,mta2"))
goto fail;
if (read_32bitBE(0x00,streamFile) == 0x444C424D) { /* "DLBM" */
subfile_offset = 0x800;
}
else if (read_32bitBE(0x00,streamFile) == 0x00000010) {
subfile_offset = 0x00;
}
else {
goto fail;
}
/* subfile size is implicit in KCEJ blocks */
temp_streamFile = setup_mta2_streamfile(streamFile, subfile_offset, 1, "mta2");
if (!temp_streamFile) goto fail;
vgmstream = init_vgmstream_mta2(temp_streamFile);
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -0,0 +1,154 @@
#ifndef _MTA2_STREAMFILE_H_
#define _MTA2_STREAMFILE_H_
#include "../streamfile.h"
typedef struct {
/* config */
int big_endian;
uint32_t target_type;
off_t stream_offset;
size_t stream_size;
/* state */
off_t logical_offset; /* fake offset */
off_t physical_offset; /* actual offset */
size_t block_size; /* current size */
size_t skip_size; /* size from block start to reach data */
size_t data_size; /* usable size in a block */
size_t logical_size;
} mta2_io_data;
static size_t mta2_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, mta2_io_data* data) {
size_t total_read = 0;
uint32_t (*read_u32)(off_t,STREAMFILE*) = data->big_endian ? read_u32be : read_u32le;
/* re-start when previous offset (can't map logical<>physical offsets) */
if (data->logical_offset < 0 || offset < data->logical_offset) {
data->physical_offset = data->stream_offset;
data->logical_offset = 0x00;
data->data_size = 0;
}
/* read blocks */
while (length > 0) {
/* ignore EOF */
if (offset < 0 || data->physical_offset >= data->stream_offset + data->stream_size) {
break;
}
/* process new block */
if (data->data_size == 0) {
uint32_t block_type, block_size, block_track;
block_type = read_u32(data->physical_offset+0x00, streamfile); /* subtype and type */
block_size = read_u32(data->physical_offset+0x04, streamfile);
//block_unk = read_u32(data->physical_offset+0x08, streamfile); /* usually 0 except for 0xF0 'end' block */
block_track = read_u32(data->physical_offset+0x0c, streamfile);
if (block_type != data->target_type || block_size == 0xFFFFFFFF)
break;
data->block_size = block_size;
data->skip_size = 0x10;
data->data_size = block_size - data->skip_size;
/* no audio data (padding block), but write first (header) */
if (block_track == 0 && data->logical_offset > 0)
data->data_size = 0;
}
/* move to next block */
if (data->data_size == 0 || offset >= data->logical_offset + data->data_size) {
data->physical_offset += data->block_size;
data->logical_offset += data->data_size;
data->data_size = 0;
continue;
}
/* read data */
{
size_t bytes_consumed, bytes_done, to_read;
bytes_consumed = offset - data->logical_offset;
to_read = data->data_size - bytes_consumed;
if (to_read > length)
to_read = length;
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
total_read += bytes_done;
dest += bytes_done;
offset += bytes_done;
length -= bytes_done;
if (bytes_done != to_read || bytes_done == 0) {
break; /* error/EOF */
}
}
}
return total_read;
}
static size_t mta2_io_size(STREAMFILE *streamfile, mta2_io_data* data) {
uint8_t buf[1];
if (data->logical_size)
return data->logical_size;
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
mta2_io_read(streamfile, buf, 0x7FFFFFFF, 1, data);
data->logical_size = data->logical_offset;
return data->logical_size;
}
/* Handles removing KCE Japan-style blocks in MTA2 streams
* (these blocks exist in most KCEJ games and aren't actually related to audio) */
static STREAMFILE* setup_mta2_streamfile(STREAMFILE *streamFile, off_t stream_offset, int big_endian, const char* extension) {
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
mta2_io_data io_data = {0};
size_t io_data_size = sizeof(mta2_io_data);
uint32_t (*read_u32)(off_t,STREAMFILE*) = big_endian ? read_u32be : read_u32le;
/* blocks must start with a 'new sub-stream' id */
if (read_u32(stream_offset+0x00, streamFile) != 0x00000010)
goto fail;
io_data.target_type = read_u32(stream_offset + 0x0c, streamFile);
io_data.stream_offset = stream_offset + 0x10;
io_data.stream_size = get_streamfile_size(streamFile) - io_data.stream_offset;
io_data.big_endian = big_endian;
io_data.logical_offset = -1; /* force phys offset reset */
/* setup subfile */
new_streamFile = open_wrap_streamfile(streamFile);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_io_streamfile(new_streamFile, &io_data,io_data_size, mta2_io_read,mta2_io_size);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_buffer_streamfile(new_streamFile,0);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
if (extension) {
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,extension);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
}
return temp_streamFile;
fail:
close_streamfile(temp_streamFile);
return NULL;
}
#endif /* _MTA2_STREAMFILE_H_ */

View File

@ -2,19 +2,17 @@
#include "../util.h"
/* MTAF - found in Metal Gear Solid 3: Snake Eater (Subsistence and HD too) */
VGMSTREAM * init_vgmstream_ps2_mtaf(STREAMFILE *streamFile) {
/* MTAF - found in Metal Gear Solid 3: Snake Eater (PS2), Subsistence and HD too */
VGMSTREAM * init_vgmstream_mtaf(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
int32_t loop_start, loop_end;
/* check extension */
/* checks */
if ( !check_extensions(streamFile,"mtaf"))
goto fail;
/* base header */
if (read_32bitBE(0x00, streamFile) != 0x4d544146) /* "MTAF" */
goto fail;
/* 0x04(4): pseudo file size (close but smaller) */
@ -34,7 +32,7 @@ VGMSTREAM * init_vgmstream_ps2_mtaf(STREAMFILE *streamFile) {
loop_start = read_32bitLE(0x58, streamFile);
loop_end = read_32bitLE(0x5c, streamFile);
loop_flag = (loop_start != loop_end);
loop_flag = read_32bitLE(0x70, streamFile) & 1;
/* check loop points vs frame counts */
if (loop_start/0x100 != read_32bitLE(0x64, streamFile) ||
@ -51,12 +49,9 @@ VGMSTREAM * init_vgmstream_ps2_mtaf(STREAMFILE *streamFile) {
goto fail;
/* 0x7fc: data size (without blocks in case of blocked layout) */
/* without blocks it should start with 0x00000100 ("frame 1 from track 0") */
//is_blocked = read_32bitLE(0x800,streamFile) != 0x00000100 && read_32bitLE(0x810,streamFile) == 0x00000100;
start_offset = 0x800;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
@ -68,23 +63,11 @@ VGMSTREAM * init_vgmstream_ps2_mtaf(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_MTAF;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x110/2; /* kinda hacky for MTAF track layout */
vgmstream->meta_type = meta_PS2_MTAF;
vgmstream->interleave_block_size = 0x110 / 2; /* kinda hacky for MTAF (stereo codec) track layout */
vgmstream->meta_type = meta_MTAF;
/* open the file for reading, in a specific way */
{
int i;
char filename[PATH_LIMIT];
streamFile->get_name(streamFile,filename,sizeof(filename));
for (i = 0; i < channel_count; i++) {
STREAMFILE * file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset = vgmstream->ch[i].offset = start_offset + vgmstream->interleave_block_size*2*(i/2);
}
}
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;

View File

@ -0,0 +1,79 @@
#include "meta.h"
#include "../coding/coding.h"
/* .MUS - Vicious Cycle games [Dinotopia: The Sunstone Odyssey (GC/Xbox), Robotech: Battlecry (PS2/Xbox)] */
VGMSTREAM * init_vgmstream_mus_vc(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate;
int big_endian, type;
int32_t(*read_32bit)(off_t, STREAMFILE*) = NULL;
/* checks */
if (!check_extensions(streamFile, "mus"))
goto fail;
if (read_32bitBE(0x08,streamFile) != 0xBBBBBBBB &&
read_32bitBE(0x14,streamFile) != 0xBBBBBBBB &&
read_32bitBE(0x2c,streamFile) != 0xBEBEBEBE)
goto fail;
big_endian = (read_32bitBE(0x00,streamFile) == 0xFBBFFBBF);
read_32bit = big_endian ? read_32bitBE : read_32bitLE;
type = read_32bit(0x04, streamFile);
/* 0x08: pseudo size? */
/* other fields may be chunk sizes and lesser stuff */
/* 0x88: codec header */
channel_count = read_32bit(0x54,streamFile); /* assumed */
if (channel_count != 1) goto fail;
sample_rate = read_32bit(0x58,streamFile);
loop_flag = 1; /* most files repeat except small jingles, but smaller ambient tracks also repeat */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_MUS_VC;
vgmstream->sample_rate = sample_rate;
switch(type) {
case 0x01:
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = dsp_bytes_to_samples(read_32bit(0xB0,streamFile), vgmstream->channels);
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
start_offset = 0xB8;
dsp_read_coefs_be(vgmstream,streamFile,0x88,0x00);
dsp_read_hist_be (vgmstream,streamFile,0xac,0x00);
break;
case 0x02:
vgmstream->coding_type = coding_XBOX_IMA;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bit(0x9a,streamFile), vgmstream->channels);
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
start_offset = 0x9e;
break;
default:
goto fail;
}
read_string(vgmstream->stream_name,0x14, 0x34,streamFile); /* repeated at 0x64, size at 0x30/0x60 */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -27,9 +27,9 @@ VGMSTREAM * init_vgmstream_naomi_adpcm(STREAMFILE *streamFile) {
if (!vgmstream) goto fail;
vgmstream->sample_rate = 44100;
vgmstream->num_samples = aica_bytes_to_samples(data_size, channel_count);
vgmstream->num_samples = yamaha_bytes_to_samples(data_size, channel_count);
vgmstream->coding_type = coding_AICA_int;
vgmstream->coding_type = coding_YAMAHA_int;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = data_size / channel_count;
vgmstream->meta_type = meta_NAOMI_ADPCM;

View File

@ -59,9 +59,9 @@ VGMSTREAM * init_vgmstream_naomi_spsd(STREAMFILE *streamFile) {
break;
case 0x03: /* standard */
vgmstream->coding_type = coding_AICA_int;
vgmstream->num_samples = aica_bytes_to_samples(data_size,channel_count);
vgmstream->loop_start_sample = /*read_32bitLE(0x2c,streamFile) +*/ aica_bytes_to_samples(0x2000*channel_count,channel_count);
vgmstream->coding_type = coding_YAMAHA_int;
vgmstream->num_samples = yamaha_bytes_to_samples(data_size,channel_count);
vgmstream->loop_start_sample = /*read_32bitLE(0x2c,streamFile) +*/ yamaha_bytes_to_samples(0x2000*channel_count,channel_count);
vgmstream->loop_end_sample = vgmstream->num_samples;
break;

View File

@ -35,6 +35,8 @@ static int read_dsp_header_endian(struct dsp_header *header, off_t offset, STREA
int i;
uint8_t buf[0x4e];
if (offset > get_streamfile_size(streamFile))
return 1;
if (read_streamfile(buf, offset, 0x4e, streamFile) != 0x4e)
return 1;
header->sample_count = get_32bit(buf+0x00);
@ -223,7 +225,7 @@ static VGMSTREAM * init_vgmstream_dsp_common(STREAMFILE *streamFile, dsp_meta *d
if (dspm->fix_looping && vgmstream->loop_end_sample > vgmstream->num_samples)
vgmstream->loop_end_sample = vgmstream->num_samples;
if (dspm->single_header) {
if (dspm->single_header == 2) { /* double the samples */
vgmstream->num_samples /= dspm->channel_count;
vgmstream->loop_start_sample /= dspm->channel_count;
vgmstream->loop_end_sample /= dspm->channel_count;
@ -270,14 +272,29 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) {
* out thoroughly, we're probably not dealing with a genuine mono DSP.
* In many cases these will pass all the other checks, including the
* predictor/scale check if the first byte is 0 */
//todo maybe this meta should be after others, so they have a chance to detect >1ch .dsp
{
int ko;
struct dsp_header header2;
read_dsp_header(&header2, header_size, streamFile);
if (header.sample_count == header2.sample_count &&
header.nibble_count == header2.nibble_count &&
header.sample_rate == header2.sample_rate &&
header.loop_flag == header2.loop_flag) {
/* ignore headers one after another */
ko = read_dsp_header(&header2, header_size, streamFile);
if (!ko &&
header.sample_count == header2.sample_count &&
header.nibble_count == header2.nibble_count &&
header.sample_rate == header2.sample_rate &&
header.loop_flag == header2.loop_flag) {
goto fail;
}
/* ignore headers after interleave [Ultimate Board Collection (Wii)] */
ko = read_dsp_header(&header2, 0x10000, streamFile);
if (!ko &&
header.sample_count == header2.sample_count &&
header.nibble_count == header2.nibble_count &&
header.sample_rate == header2.sample_rate &&
header.loop_flag == header2.loop_flag) {
goto fail;
}
}
@ -517,14 +534,13 @@ VGMSTREAM * init_vgmstream_ngc_mpdsp(STREAMFILE *streamFile) {
if (!check_extensions(streamFile, "mpdsp"))
goto fail;
/* at 0x48 is extra data that could help differenciating these DSPs, but other games
* put similar stuff there, needs more checks (ex. Battallion Wars, Army Men) */
//0x00005300 60A94000 64FF1200 00000000 00000000 00000000
/* at 0x48 is extra data that could help differenciating these DSPs, but seems like
* memory garbage created by the encoder that other games also have */
/* 0x02(2): sample rate, 0x08+: channel sizes/loop offsets? */
dspm.channel_count = 2;
dspm.max_channels = 2;
dspm.single_header = 1;
dspm.single_header = 2;
dspm.header_offset = 0x00;
dspm.header_spacing = 0x00; /* same header for both channels */
@ -1196,3 +1212,37 @@ VGMSTREAM * init_vgmstream_dsp_adpcmx(STREAMFILE *streamFile) {
fail:
return NULL;
}
/* .ds2 - LucasArts wrapper [Star Wars: Bounty Hunter (GC)] */
VGMSTREAM * init_vgmstream_dsp_ds2(STREAMFILE *streamFile) {
dsp_meta dspm = {0};
size_t file_size, channel_offset;
/* checks */
/* .ds2: real extension, dsp: fake/renamed */
if (!check_extensions(streamFile, "ds2,dsp"))
goto fail;
if (!(read_32bitBE(0x50,streamFile) == 0 &&
read_32bitBE(0x54,streamFile) == 0 &&
read_32bitBE(0x58,streamFile) == 0 &&
read_32bitBE(0x5c,streamFile) != 0))
goto fail;
file_size = get_streamfile_size(streamFile);
channel_offset = read_32bitBE(0x5c,streamFile); /* absolute offset to 2nd channel */
if (channel_offset < file_size / 2 || channel_offset > file_size) /* just to make sure */
goto fail;
dspm.channel_count = 2;
dspm.max_channels = 2;
dspm.single_header = 1;
dspm.header_offset = 0x00;
dspm.header_spacing = 0x00;
dspm.start_offset = 0x60;
dspm.interleave = channel_offset - dspm.start_offset;
dspm.meta_type = meta_DSP_DS2;
return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
return NULL;
}

View File

@ -1,98 +1,55 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
/*
SCK+DSP
2009-08-25 - manakoAT : Scorpion King (NGC)...
*/
//todo this was extracted from a .pak bigfile. Inside are headers then data (no extensions),
// but headers are VAGp in the PS2 version, so it would make more sense to extract pasting
// header+data together, or support as-is (.SCK is a fake extension).
/* SCK+DSP - Scorpion King (GC) */
VGMSTREAM * init_vgmstream_ngc_sck_dsp(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * streamFileDSP = NULL;
char filename[PATH_LIMIT];
char filenameDSP[PATH_LIMIT];
int i;
int channel_count;
int loop_flag;
STREAMFILE * streamHeader = NULL;
int channel_count, loop_flag;
size_t data_size;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("sck",filename_extension(filename))) goto fail;
strcpy(filenameDSP,filename);
strcpy(filenameDSP+strlen(filenameDSP)-3,"dsp");
streamFileDSP = streamFile->open(streamFile,filenameDSP,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (read_32bitBE(0x5C,streamFile) != 0x60A94000)
if (!check_extensions(streamFile, "dsp"))
goto fail;
if (!streamFile) goto fail;
streamHeader = open_streamfile_by_ext(streamFile, "sck");
if (!streamHeader) goto fail;
if (read_32bitBE(0x5C,streamHeader) != 0x60A94000)
goto fail;
channel_count = 2;
loop_flag = 0;
data_size = read_32bitBE(0x14,streamHeader);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x18,streamFile);
vgmstream->num_samples=read_32bitBE(0x14,streamFile)/8/channel_count*14;
vgmstream->sample_rate = read_32bitBE(0x18,streamHeader);
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
vgmstream->coding_type = coding_NGC_DSP;
if(loop_flag) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = read_32bitBE(0x10,streamFile)/8/channel_count*14;
}
if (channel_count == 1) {
vgmstream->layout_type = layout_none;
} else if (channel_count == 2) {
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size=read_32bitBE(0xC,streamFile);
}
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitBE(0xC,streamHeader);
if (vgmstream->interleave_block_size > 0)
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size * channel_count)) / channel_count;
vgmstream->meta_type = meta_NGC_SCK_DSP;
/* open the file for reading */
{
for (i=0;i<channel_count;i++) {
/* Not sure, i'll put a fake value here for now */
vgmstream->ch[i].streamfile = streamFile->open(streamFileDSP,filenameDSP,STREAMFILE_DEFAULT_BUFFER_SIZE);
vgmstream->ch[i].offset = 0;
dsp_read_coefs_be(vgmstream,streamHeader, 0x2c, 0x00);
if (!vgmstream->ch[i].streamfile) goto fail;
}
}
if (vgmstream->coding_type == coding_NGC_DSP) {
int i;
for (i=0;i<16;i++) {
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x2C+i*2,streamFile);
}
if (vgmstream->channels == 2) {
for (i=0;i<16;i++) {
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x2C+i*2,streamFile);
}
}
}
close_streamfile(streamFileDSP); streamFileDSP=NULL;
if (!vgmstream_open_stream(vgmstream,streamFile,0x00))
goto fail;
close_streamfile(streamHeader);
return vgmstream;
/* clean up anything we may have opened */
fail:
if (streamFileDSP) close_streamfile(streamFileDSP);
if (vgmstream) close_vgmstream(vgmstream);
close_streamfile(streamHeader);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,13 +1,15 @@
#include "meta.h"
#include "../coding/coding.h"
/* NPFS - found in Namco PS2/PSP games (Tekken 5, Ace Combat 5, Yumeria, Venus & Braves, Ridge Racer PSP) */
VGMSTREAM * init_vgmstream_ps2_npsf(STREAMFILE *streamFile) {
/* NPFS - found in Namco PS2/PSP games [Tekken 5 (PS2), Venus & Braves (PS2), Ridge Racer (PSP)] */
VGMSTREAM * init_vgmstream_nps(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
/* check extension, case insensitive (should be .nps as per Venus & Braves data files) */
/* checks */
/* .nps: referenced extension (ex. Venus & Braves data files)
* .npsf: header id (Namco Production Sound File?) */
if ( !check_extensions(streamFile,"nps,npsf"))
goto fail;
@ -16,7 +18,8 @@ VGMSTREAM * init_vgmstream_ps2_npsf(STREAMFILE *streamFile) {
loop_flag = (read_32bitLE(0x14,streamFile) != 0xFFFFFFFF);
channel_count = read_32bitLE(0x0C,streamFile);
start_offset = (off_t)read_32bitLE(0x10,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
@ -32,13 +35,9 @@ VGMSTREAM * init_vgmstream_ps2_npsf(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitLE(0x04,streamFile) / 2;
vgmstream->meta_type = meta_PS2_NPSF;
vgmstream->meta_type = meta_NPS;
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, 0x34,streamFile);
start_offset = (off_t)read_32bitLE(0x10,streamFile);
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;

View File

@ -35,7 +35,7 @@ VGMSTREAM * init_vgmstream_nxap(STREAMFILE *streamFile) {
//vgmstream->loop_end_sample = vgmstream->loop_start_sample + vgmstream->loop_end_sample;
vgmstream->meta_type = meta_NXAP;
vgmstream->coding_type = coding_YAMAHA_NXAP;
vgmstream->coding_type = coding_NXAP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x40;

View File

@ -111,6 +111,7 @@ VGMSTREAM * init_vgmstream_ogg_opus(STREAMFILE *streamFile) {
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->channel_layout = ffmpeg_get_channel_layout(vgmstream->codec_data);
/* FFmpeg+libopus handles skip samples ok, FFmpeg+opus doesn't */
}
#else

View File

@ -275,6 +275,18 @@ static void lse_ff_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb,
}
}
static const uint32_t xiph_mappings[] = {
0,
mapping_MONO,
mapping_STEREO,
mapping_2POINT1_xiph,
mapping_QUAD,
mapping_5POINT0_xiph,
mapping_5POINT1,
mapping_7POINT0,
mapping_7POINT1,
};
/* Ogg Vorbis, by way of libvorbisfile; may contain loop comments */
VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
@ -298,8 +310,9 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
* .adx: KID [Remember11 (PC)]
* .rof: The Rhythm of Fighters (Mobile)
* .acm: Planescape Torment Enhanced Edition (PC)
* .sod: Zone 4 (PC) */
if (check_extensions(streamFile,"ogg,logg,adx,rof,acm,sod")) {
* .sod: Zone 4 (PC)
* .aif/laif/aif-Loop: Psychonauts (PC) raw extractions (named) */
if (check_extensions(streamFile,"ogg,logg,adx,rof,acm,sod,aif,laif,aif-Loop")) {
is_ogg = 1;
} else if (check_extensions(streamFile,"um3")) {
is_um3 = 1;
@ -369,6 +382,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
ovmi.xor_value = read_32bitBE(0x00,streamFile);
ovmi.decryption_callback = sngw_ogg_decryption_callback;
}
ovmi.disable_reordering = 1; /* must be an MT Framework thing */
ovmi.meta_type = meta_OGG_encrypted;
}
@ -518,6 +532,9 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb
data->bitstream = OGG_DEFAULT_BITSTREAM;
vi = ov_info(ovf,OGG_DEFAULT_BITSTREAM);
/* other settings */
data->disable_reordering = ovmi->disable_reordering;
/* search for loop comments */
{
int i;
@ -601,6 +618,13 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb
}
}
/* Hatsune Miku Project DIVA games, though only 'Arcade Future Tone' has >4ch files
* ENCODER tag is common but ogg_vorbis_encode looks unique enough
* (arcade ends with "2010-11-26" while consoles have "2011-02-07" */
if (strstr(user_comment, "ENCODER=ogg_vorbis_encode/") == user_comment) {
data->disable_reordering = 1;
}
;VGM_LOG("OGG: user_comment=%s\n", user_comment);
}
}
@ -634,6 +658,10 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb
vgmstream->layout_type = layout_none;
vgmstream->meta_type = ovmi->meta_type;
if (vgmstream->channels <= 8) {
vgmstream->channel_layout = xiph_mappings[vgmstream->channels];
}
return vgmstream;
fail:

View File

@ -35,7 +35,7 @@ VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile) {
{
codec = read_32bitLE(0x08,streamFile);
sample_rate = read_32bitLE(0x0C,streamFile);
channel_count = read_32bitLE(0x10,streamFile); /* up to 4 [Eve of Extinction (PS2)]*/
channel_count = read_32bitLE(0x10,streamFile); /* up to 4 [Eve of Extinction (PS2)] */
interleave = read_32bitLE(0x14,streamFile); /* set even when mono */
@ -150,7 +150,7 @@ VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile) {
loop_start_sample = loop_start / 2 / channel_count;
is_loop_samples = 1;
}
else if ((loop_start % 0x800 == 0) && loop_start > 0) {/* sector-aligned, min/0 is 0x800 */
else if ((loop_start % 0x800 == 0) && loop_start > 0) { /* sector-aligned, min/0 is 0x800 */
/* cavia games: loop_start is offset [Drakengard 1/2, GITS: Stand Alone Complex] */
/* offset is absolute from the "cavia stream format" container that adjusts ADS start */
loop_flag = 1;
@ -192,12 +192,18 @@ VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile) {
loop_start_offset = loop_start * 0x20;
loop_end_offset = loop_end * 0x20;
}
else if (loop_end <= body_size / 0x20 && coding_type == coding_PSX) { /* close to body_size */
else if (loop_end <= body_size / 0x20 && coding_type == coding_PSX) {
/* various games: loops is address * 0x20 [Fire Pro Wrestling Returns, A.C.E. - Another Century's Episode] */
loop_flag = 1;
loop_start_offset = loop_start * 0x20;
loop_end_offset = loop_end * 0x20;
}
else if (loop_end <= body_size / 0x10 && coding_type == coding_PSX
&& (read_32bitBE(0x28 + loop_end*0x10 + 0x10 + 0x00, streamFile) == 0x00077777 ||
read_32bitBE(0x28 + loop_end*0x10 + 0x20 + 0x00, streamFile) == 0x00077777)) {
/* not-quite-looping sfx, ending with a "non-looping PS-ADPCM end frame" [Kono Aozora ni Yakusoku, Chanter] */
loop_flag = 0;
}
else if ((loop_end > body_size / 0x20 && coding_type == coding_PSX) ||
(loop_end > body_size / 0x70 && coding_type == coding_PCM16LE)) {
/* various games: loops in samples [Eve of Extinction, Culdcept, WWE Smackdown! 3] */

View File

@ -1,63 +0,0 @@
#include "meta.h"
#include "../util.h"
/* IKM (found in Zwei!) */
VGMSTREAM * init_vgmstream_ikm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag = 0;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("ikm",filename_extension(filename))) goto fail;
/* check header */
if ((read_32bitBE(0x00,streamFile) != 0x494B4D00) && /* "IKM\0" */
(read_32bitBE(0x40,streamFile) != 0x41535400)) /* "AST\0" */
goto fail;
loop_flag = (read_32bitLE(0x14,streamFile)!=0); /* Not sure */
channel_count = read_32bitLE(0x50,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x800;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x44,streamFile);
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = (read_32bitLE(0x4C,streamFile)-start_offset)/16/channel_count*28;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x18,streamFile);
}
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
vgmstream->meta_type = meta_IKM;
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,104 +0,0 @@
#include "meta.h"
#include "../util.h"
/* MTA2 - found in Metal Gear Solid 4 */
VGMSTREAM * init_vgmstream_ps3_mta2(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t header_offset, start_offset;
int loop_flag, channel_count, sample_rate; //block_offset;
int32_t loop_start, loop_end;
/* check extension */
/* .mta2: normal file, .bgm: mta2 with block layout, .dbm: iPod metadata + block layout mta2 */
if ( !check_extensions(streamFile,"mta2,bgm,dbm"))
goto fail;
/* base header (everything is very similar to MGS3's MTAF but BE) */
if (read_32bitBE(0x00,streamFile) == 0x4d544132) { /* "MTA2" (.mta) */
//block_offset = 0;
header_offset = 0x00;
} else if (read_32bitBE(0x20,streamFile) == 0x4d544132) { /* "MTA2" @ 0x20 (.bgm) */
//block_offset = 0x10;
header_offset = 0x20;
} else if (read_32bitBE(0x00, streamFile) == 0x444C424D
&& read_32bitBE(0x820,streamFile) == 0x4d544132) { /* "DLBM" + "MTA2" @ 0x820 (.dbm) */
//block_offset = 0x810;
header_offset = 0x820;
} else {
goto fail;
}
/* 0x04(4): file size -4-4 (not including block headers in case of block layout) */
/* 0x08(4): version? (1), 0x0c(52): null */
/* HEAD chunk */
if (read_32bitBE(header_offset+0x40, streamFile) != 0x48454144) /* "HEAD" */
goto fail;
if (read_32bitBE(header_offset+0x44, streamFile) != 0xB0) /* HEAD size */
goto fail;
/* 0x48(4): null, 0x4c: ? (0x10), 0x50(4): 0x7F (vol?), 0x54(2): 0x40 (pan?) */
channel_count = read_16bitBE(header_offset+0x56, streamFile); /* counting all tracks */
/* 0x60(4): full block size (0x110 * channels), indirectly channels_per_track = channels / (block_size / 0x110) */
/* 0x80 .. 0xf8: null */
loop_start = read_32bitBE(header_offset+0x58, streamFile);
loop_end = read_32bitBE(header_offset+0x5c, streamFile);
loop_flag = (loop_start != loop_end); /* also flag possibly @ 0x73 */
#if 0
/* those values look like some kind of loop offsets */
if (loop_start/0x100 != read_32bitBE(header_offset+0x68, streamFile) ||
loop_end /0x100 != read_32bitBE(header_offset+0x6C, streamFile) ) {
VGM_LOG("MTA2: wrong loop points\n");
goto fail;
}
#endif
sample_rate = read_32bitBE(header_offset+0x7c, streamFile);
if (sample_rate) { /* sample rate in 32b float (WHY?) typically 48000.0 */
float sample_float;
memcpy(&sample_float, &sample_rate, 4);
sample_rate = (int)sample_float;
} else { /* default when not specified (most of the time) */
sample_rate = 48000;
}
/* TRKP chunks (x16) */
/* just seem to contain pan/vol stuff (0x7f/0x40), TRKP per track (sometimes +1 main track?) */
/* there is channel layout bitmask @ 0x0f (ex. 1ch = 0x04, 3ch = 0x07, 4ch = 0x33, 6ch = 0x3f), surely:
* FRONT_L = 0x01, FRONT_R = 0x02, FRONT_M = 0x04, BACK_L = 0x08, BACK_R = 0x10, BACK_M = 0x20 */
/* DATA chunk */
if (read_32bitBE(header_offset+0x7f8, streamFile) != 0x44415441) // "DATA"
goto fail;
/* 0x7fc: data size (without blocks in case of blocked layout) */
start_offset = header_offset + 0x800;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = loop_end;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->coding_type = coding_MTA2;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_PS3_MTA2;
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -87,9 +87,14 @@ typedef struct {
int channel_count;
uint32_t block_size;
int bps;
off_t extra_size;
uint32_t channel_layout;
int coding_type;
int interleave;
int is_at3;
int is_at9;
} riff_fmt_chunk;
static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk, riff_fmt_chunk * fmt, int mwv) {
@ -99,18 +104,35 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
fmt->offset = current_chunk;
fmt->size = read_32bit(current_chunk+0x04,streamFile);
fmt->codec = (uint16_t)read_16bit(current_chunk+0x08,streamFile);
fmt->sample_rate = read_32bit(current_chunk+0x0c,streamFile);
fmt->channel_count = read_16bit(current_chunk+0x0a,streamFile);
fmt->block_size = read_16bit(current_chunk+0x14,streamFile);
fmt->bps = read_16bit(current_chunk+0x16,streamFile);
fmt->interleave = 0;
/* WAVEFORMAT */
fmt->codec = (uint16_t)read_16bit(current_chunk+0x08,streamFile);
fmt->channel_count = read_16bit(current_chunk+0x0a,streamFile);
fmt->sample_rate = read_32bit(current_chunk+0x0c,streamFile);
//fmt->avg_bps = read_32bit(current_chunk+0x10,streamFile);
fmt->block_size = read_16bit(current_chunk+0x14,streamFile);
fmt->bps = read_16bit(current_chunk+0x16,streamFile);
/* WAVEFORMATEX */
if (fmt->size >= 0x10) {
fmt->extra_size = read_16bit(current_chunk+0x18,streamFile);
/* 0x1a+ depends on codec (ex. coef table for MSADPCM, samples_per_frame in MS-IMA, etc) */
}
/* WAVEFORMATEXTENSIBLE */
if (fmt->codec == 0xFFFE && fmt->extra_size >= 0x16) {
//fmt->extra_samples = read_16bit(current_chunk+0x1a,streamFile); /* valid_bits_per_sample or samples_per_block */
fmt->channel_layout = read_32bit(current_chunk+0x1c,streamFile);
/* 0x10 guid at 0x20 */
/* happens in .at3/at9, may be a bug in their encoder b/c MS's defs set mono as FC */
if (fmt->channel_count == 1 && fmt->channel_layout == speaker_FL) { /* other channels are fine */
fmt->channel_layout = speaker_FC;
}
}
switch (fmt->codec) {
case 0x00: /* Yamaha ADPCM (raw) [Headhunter (DC), Bomber hehhe (DC)] (unofficial) */
if (fmt->bps != 4) goto fail;
if (fmt->block_size != 0x02*fmt->channel_count) goto fail;
fmt->coding_type = coding_AICA_int;
fmt->coding_type = coding_YAMAHA_int;
fmt->interleave = 0x01;
break;
@ -129,7 +151,7 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
}
break;
case 0x02: /* MS ADPCM */
case 0x02: /* MSADPCM */
if (fmt->bps == 4) {
fmt->coding_type = coding_MSADPCM;
}
@ -141,14 +163,14 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
}
break;
case 0x11: /* MS IMA ADPCM [Layton Brothers: Mystery Room (iOS/Android)] */
case 0x11: /* MS-IMA ADPCM [Layton Brothers: Mystery Room (iOS/Android)] */
if (fmt->bps != 4) goto fail;
fmt->coding_type = coding_MS_IMA;
break;
case 0x20: /* Yamaha ADPCM (raw) [Takuyo/Dynamix/etc DC games] */
if (fmt->bps != 4) goto fail;
fmt->coding_type = coding_AICA;
fmt->coding_type = coding_YAMAHA;
break;
case 0x69: /* XBOX IMA ADPCM [Dynasty Warriors 5 (Xbox)] */
@ -186,39 +208,56 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
case 0x270: /* ATRAC3 */
#ifdef VGM_USE_FFMPEG
fmt->coding_type = coding_FFmpeg;
fmt->is_at3 = 1;
break;
#else
goto fail;
#endif
case 0xFFFE: /* WAVEFORMATEXTENSIBLE */
case 0xFFFE: { /* WAVEFORMATEXTENSIBLE (see ksmedia.h for known GUIDs) */
uint32_t guid1 = (uint32_t)read_32bit (current_chunk+0x20,streamFile);
uint32_t guid2 = ((uint16_t)read_16bit (current_chunk+0x24,streamFile) << 16u) |
((uint16_t)read_16bit (current_chunk+0x26,streamFile));
uint32_t guid3 = (uint32_t)read_32bitBE(current_chunk+0x28,streamFile);
uint32_t guid4 = (uint32_t)read_32bitBE(current_chunk+0x2c,streamFile);
//;VGM_LOG("RIFF: guid %08x %08x %08x %08x\n", guid1, guid2, guid3, guid4);
/* ATRAC3plus GUID (0xBFAA23E9 58CB7144 A119FFFA 01E4CE62) */
if (read_32bit(current_chunk+0x20,streamFile) == 0xE923AABF &&
read_16bit(current_chunk+0x24,streamFile) == (int16_t)0xCB58 &&
read_16bit(current_chunk+0x26,streamFile) == 0x4471 &&
read_32bitLE(current_chunk+0x28,streamFile) == 0xFAFF19A1 &&
read_32bitLE(current_chunk+0x2C,streamFile) == 0x62CEE401) {
/* PCM GUID (0x00000001,0000,0010,80,00,00,AA,00,38,9B,71) */
if (guid1 == 0x00000001 && guid2 == 0x00000010 && guid3 == 0x800000AA && guid4 == 0x00389B71) {
switch (fmt->bps) {
case 16:
fmt->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
fmt->interleave = 0x02;
break;
default:
goto fail;
}
break;
}
/* ATRAC3plus GUID (0xE923AABF,CB58,4471,A1,19,FF,FA,01,E4,CE,62) */
if (guid1 == 0xE923AABF && guid2 == 0xCB584471 && guid3 == 0xA119FFFA && guid4 == 0x01E4CE62) {
#ifdef VGM_USE_MAIATRAC3PLUS
uint16_t bztmp = read_16bit(current_chunk+0x32,streamFile);
bztmp = (bztmp >> 8) | (bztmp << 8);
fmt->coding_type = coding_AT3plus;
fmt->block_size = (bztmp & 0x3FF) * 8 + 8; //should match fmt->block_size
fmt->block_size = (bztmp & 0x3FF) * 8 + 8; /* should match fmt->block_size */
fmt->is_at3 = 1;
break;
#elif defined(VGM_USE_FFMPEG)
fmt->coding_type = coding_FFmpeg;
fmt->is_at3 = 1;
break;
#else
goto fail;
#endif
}
/* ATRAC9 GUID 47E142D2-36BA-4d8d-88FC-61654F8C836C (D242E147 BA368D4D 88FC6165 4F8C836C) */
if (read_32bitBE(current_chunk+0x20,streamFile) == 0xD242E147 &&
read_32bitBE(current_chunk+0x24,streamFile) == 0xBA368D4D &&
read_32bitBE(current_chunk+0x28,streamFile) == 0x88FC6165 &&
read_32bitBE(current_chunk+0x2c,streamFile) == 0x4F8C836C) {
/* ATRAC9 GUID (0x47E142D2,36BA,4D8D,88,FC,61,65,4F,8C,83,6C) */
if (guid1 == 0x47E142D2 && guid2 == 0x36BA4D8D && guid3 == 0x88FC6165 && guid4 == 0x4F8C836C) {
#ifdef VGM_USE_ATRAC9
fmt->coding_type = coding_ATRAC9;
fmt->is_at9 = 1;
break;
#else
goto fail;
@ -226,15 +265,16 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
}
goto fail; /* unknown GUID */
}
default:
goto fail;
}
return 0;
return 1;
fail:
return -1;
return 0;
}
static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* streamFile, riff_fmt_chunk* fmt, int fact_sample_count, off_t start_offset);
@ -261,8 +301,6 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
int mwv = 0; /* Level-5 .mwv (Dragon Quest VIII, Rogue Galaxy) */
off_t mwv_pflt_offset = -1;
off_t mwv_ctrl_offset = -1;
int at3 = 0; /* Sony ATRAC3 / ATRAC3plus */
int at9 = 0; /* Sony ATRAC9 */
/* check extension */
@ -282,22 +320,18 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
* .wd: Genma Onimusha (Xbox) voices
* (extensionless): Myst III (Xbox)
* .sbv: Spongebob Squarepants - The Movie (PC)
* .wvx: Godzilla - Destroy All Monsters Melee (Xbox) */
if ( check_extensions(streamFile, "wav,lwav,xwav,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv") ) {
* .wvx: Godzilla - Destroy All Monsters Melee (Xbox)
* .at3: standard ATRAC3
* .rws: Climax games (Silent Hill Origins PSP, Oblivion PSP) ATRAC3
* .aud: EA Replay ATRAC3
* .at9: standard ATRAC9
*/
if ( check_extensions(streamFile, "wav,lwav,xwav,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv,wvx,at3,rws,aud,at9") ) {
;
}
else if ( check_extensions(streamFile, "mwv") ) {
mwv = 1;
}
/* .at3: standard
* .rws: Climax games (Silent Hill Origins PSP, Oblivion PSP)
* .aud: EA Replay */
else if ( check_extensions(streamFile, "at3,rws,aud") ) {
at3 = 1;
}
else if ( check_extensions(streamFile, "at9") ) {
at9 = 1;
}
else {
goto fail;
}
@ -330,27 +364,21 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
/* read through chunks to verify format and find metadata */
{
off_t current_chunk = 0xc; /* start with first chunk */
off_t current_chunk = 0x0c; /* start with first chunk */
while (current_chunk < file_size && current_chunk < riff_size+8) {
uint32_t chunk_type = read_32bitBE(current_chunk,streamFile);
size_t chunk_size = read_32bitLE(current_chunk+4,streamFile);
uint32_t chunk_id = read_32bitBE(current_chunk + 0x00,streamFile); /* FOURCC */
size_t chunk_size = read_32bitLE(current_chunk + 0x04,streamFile);
if (fmt.codec == 0x6771 && chunk_type == 0x64617461) /* Liar-soft again */
chunk_size += (chunk_size%2) ? 0x01 : 0x00;
if (current_chunk + 0x08 + chunk_size > file_size)
goto fail;
if (current_chunk+0x08+chunk_size > file_size) goto fail;
switch(chunk_type) {
switch(chunk_id) {
case 0x666d7420: /* "fmt " */
if (FormatChunkFound) goto fail; /* only one per file */
FormatChunkFound = 1;
if (-1 == read_fmt(0, /* big endian == false*/
streamFile,
current_chunk,
&fmt,
mwv))
if (!read_fmt(0, streamFile, current_chunk, &fmt, mwv))
goto fail;
/* some Dreamcast/Naomi games again [Headhunter (DC), Bomber hehhe (DC)] */
@ -367,7 +395,6 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
break;
case 0x4C495354: /* "LIST" */
/* what lurks within?? */
switch (read_32bitBE(current_chunk+0x08, streamFile)) {
case 0x6164746C: /* "adtl" */
/* yay, atdl is its own little world */
@ -417,10 +444,10 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
} else if (chunk_size == 0x10 && read_32bitBE(current_chunk+0x08+0x04, streamFile) == 0x4C794E20) { /* "LyN " */
goto fail; /* parsed elsewhere */
} else if ((at3 || at9) && chunk_size == 0x08) {
} else if ((fmt.is_at3 || fmt.is_at9) && chunk_size == 0x08) {
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
fact_sample_skip = read_32bitLE(current_chunk+0x0c, streamFile);
} else if ((at3 || at9) && chunk_size == 0x0c) {
} else if ((fmt.is_at3 || fmt.is_at9) && chunk_size == 0x0c) {
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
fact_sample_skip = read_32bitLE(current_chunk+0x10, streamFile);
}
@ -430,6 +457,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
if (!mwv) break; /* ignore if not in an mwv */
mwv_pflt_offset = current_chunk; /* predictor filters */
break;
case 0x6374726c: /* "ctrl" (.mwv extension) */
if (!mwv) break;
loop_flag = read_32bitLE(current_chunk+0x08, streamFile);
@ -457,7 +485,13 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
break;
}
current_chunk += 8+chunk_size;
/* chunks are even-sized with padding byte (for 16b reads) as per spec (normally
* pre-adjusted except for a few like Liar-soft's), at end may not have padding though
* (done *after* chunk parsing since size without padding is needed) */
if (chunk_size % 0x02 && current_chunk + 0x08 + chunk_size+0x01 <= file_size)
chunk_size += 0x01;
current_chunk += 0x08 + chunk_size;
}
}
@ -481,6 +515,10 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
read_32bitBE(start_offset+0x3c, streamFile) == 0xFFFFFFFF)
goto fail;
/* ignore Gitaroo Man Live! (PSP) multi-RIFF (to allow chunked TXTH) */
if (fmt.is_at3 && get_streamfile_size(streamFile) > 0x2800 && read_32bitBE(0x2800, streamFile) == 0x52494646) { /* "RIFF" */
goto fail;
}
#ifdef VGM_USE_VORBIS
/* special case using init_vgmstream_ogg_vorbis */
@ -495,6 +533,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
if (!vgmstream) goto fail;
vgmstream->sample_rate = fmt.sample_rate;
vgmstream->channel_layout = fmt.channel_layout;
/* init, samples */
switch (fmt.coding_type) {
@ -544,9 +583,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
vgmstream->num_samples = fact_sample_count;
break;
case coding_AICA:
case coding_AICA_int:
vgmstream->num_samples = aica_bytes_to_samples(data_size, fmt.channel_count);
case coding_YAMAHA:
case coding_YAMAHA_int:
vgmstream->num_samples = yamaha_bytes_to_samples(data_size, fmt.channel_count);
break;
case coding_XBOX_IMA:
@ -567,13 +606,28 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact_sample_count */
if (at3) {
if (fmt.is_at3) {
/* the encoder introduces some garbage (not always silent) samples to skip before the stream */
/* manually set skip_samples if FFmpeg didn't do it */
if (ffmpeg_data->skipSamples <= 0) {
ffmpeg_set_skip_samples(ffmpeg_data, fact_sample_skip);
}
/* LFE channel should be reordered on decode, but FFmpeg doesn't do it automatically:
* - 6ch: FL FR FC BL BR LFE > FL FR FC LFE BL BR
* - 8ch: FL FR FC BL BR SL SR LFE > FL FR FC LFE BL BR SL SR
* (ATRAC3Plus only, 5/7ch can't be encoded) */
if (ffmpeg_data->channels == 6) {
/* LFE BR BL > LFE BL BR > same */
int channel_remap[] = { 0, 1, 2, 5, 5, 5, };
ffmpeg_set_channel_remapping(ffmpeg_data, channel_remap);
}
else if (ffmpeg_data->channels == 8) {
/* LFE BR SL SR BL > LFE BL SL SR BR > LFE BL BR SR SL > LFE BL BR SL SR > same */
int channel_remap[] = { 0, 1, 2, 7, 7, 7, 7, 7};
ffmpeg_set_channel_remapping(ffmpeg_data, channel_remap);
}
/* RIFF loop/sample values are absolute (with skip samples), adjust */
if (loop_flag) {
loop_start_smpl -= (int32_t)ffmpeg_data->skipSamples;
@ -624,7 +678,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
switch (fmt.coding_type) {
case coding_MSADPCM:
case coding_MS_IMA:
case coding_AICA:
case coding_YAMAHA:
case coding_XBOX_IMA:
case coding_IMA:
#ifdef VGM_USE_FFMPEG
@ -803,11 +857,7 @@ VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
if (FormatChunkFound) goto fail;
FormatChunkFound = 1;
if (-1 == read_fmt(1, /* big endian == true */
streamFile,
current_chunk,
&fmt,
0)) /* mwv == false */
if (!read_fmt(1, streamFile, current_chunk, &fmt, 0))
goto fail;
break;

View File

@ -0,0 +1,46 @@
#include "meta.h"
#include "../coding/coding.h"
#include "sfh_streamfile.h"
/* .SFH - Capcom wrapper [Devil May Cry 4 Demo (PS3), Jojo's Bizarre Adventure HD (PS3)] */
VGMSTREAM * init_vgmstream_sfh(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
uint32_t version;
size_t clean_size, block_size;
/* check extensions */
if ( !check_extensions(streamFile,"at3"))
goto fail;
if (read_32bitBE(0x00, streamFile) != 0x00534648) /* "\0SFH" */
goto fail;
if (read_32bitBE(0x10, streamFile) != 0x52494646) /* "RIFF" */
goto fail;
/* mini header */
version = read_32bitBE(0x04,streamFile);
clean_size = read_32bitBE(0x08,streamFile); /* there is padding data at the end */
/* 0x0c: always 0 */
switch(version) {
case 0x00010000: block_size = 0x10010; break; /* DMC4 Demo (not retail) */
case 0x00010001: block_size = 0x20000; break; /* Jojo */
default: goto fail;
}
temp_streamFile = setup_sfh_streamfile(streamFile, 0x00, block_size, clean_size, "at3");
if (!temp_streamFile) goto fail;
vgmstream = init_vgmstream_riff(temp_streamFile);
if (!vgmstream) goto fail;
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -0,0 +1,133 @@
#ifndef _SFH_STREAMFILE_H_
#define _SFH_STREAMFILE_H_
#include "../streamfile.h"
typedef struct {
/* config */
off_t stream_offset;
size_t stream_size;
/* state */
off_t logical_offset; /* fake offset */
off_t physical_offset; /* actual offset */
size_t block_size; /* current size */
size_t skip_size; /* size from block start to reach data */
size_t data_size; /* usable size in a block */
size_t logical_size;
} sfh_io_data;
static size_t sfh_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, sfh_io_data* data) {
size_t total_read = 0;
/* re-start when previous offset (can't map logical<>physical offsets) */
if (data->logical_offset < 0 || offset < data->logical_offset) {
data->physical_offset = data->stream_offset;
data->logical_offset = 0x00;
data->data_size = 0;
}
/* read blocks */
while (length > 0) {
/* ignore EOF */
if (offset < 0 || data->physical_offset >= data->stream_offset + data->stream_size) {
break;
}
/* process new block */
if (data->data_size == 0) {
data->skip_size = 0x10; /* skip 0x10 garbage on every block */
data->data_size = data->block_size - 0x10;
}
/* move to next block */
if (data->data_size == 0 || offset >= data->logical_offset + data->data_size) {
data->physical_offset += data->block_size;
data->logical_offset += data->data_size;
data->data_size = 0;
continue;
}
/* read data */
{
size_t bytes_consumed, bytes_done, to_read;
bytes_consumed = offset - data->logical_offset;
to_read = data->data_size - bytes_consumed;
if (to_read > length)
to_read = length;
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
total_read += bytes_done;
dest += bytes_done;
offset += bytes_done;
length -= bytes_done;
if (bytes_done != to_read || bytes_done == 0) {
break; /* error/EOF */
}
}
}
return total_read;
}
static size_t sfh_io_size(STREAMFILE *streamfile, sfh_io_data* data) {
uint8_t buf[1];
if (data->logical_size)
return data->logical_size;
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
sfh_io_read(streamfile, buf, 0x7FFFFFFF, 1, data);
data->logical_size = data->logical_offset;
return data->logical_size;
}
/* Handles deinterleaving of SFH blocked streams */
static STREAMFILE* setup_sfh_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t block_size, size_t clean_size, const char* extension) {
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
sfh_io_data io_data = {0};
size_t io_data_size = sizeof(sfh_io_data);
io_data.stream_offset = stream_offset;
io_data.stream_size = get_streamfile_size(streamFile) - stream_offset;
io_data.block_size = block_size;
io_data.logical_offset = -1; /* force phys offset reset */
/* setup subfile */
new_streamFile = open_wrap_streamfile(streamFile);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_io_streamfile(new_streamFile, &io_data,io_data_size, sfh_io_read,sfh_io_size);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_buffer_streamfile(new_streamFile,0);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_clamp_streamfile(new_streamFile,0x00, clean_size);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
if (extension) {
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,extension);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
}
return temp_streamFile;
fail:
close_streamfile(temp_streamFile);
return NULL;
}
#endif /* _SFH_STREAMFILE_H_ */

View File

@ -39,7 +39,7 @@ VGMSTREAM * init_vgmstream_scd_sscf(STREAMFILE *streamFile) {
total_subsongs = 0;
for (i = 0; i < entries; i++) {
off_t entry_offset = 0x20 + (0x20*i);
off_t stream_offset;
off_t entry_stream_offset;
/* skip dummies */
if (read_32bitLE(entry_offset+0x08,streamFile) == 0) /* size 0 */
@ -49,16 +49,16 @@ VGMSTREAM * init_vgmstream_scd_sscf(STREAMFILE *streamFile) {
/* skip repeated sounds */
is_dupe = 0;
stream_offset = read_32bitLE(entry_offset+0x04,streamFile);
entry_stream_offset = read_32bitLE(entry_offset+0x04,streamFile);
for (j = 0; j < total_subsongs; j++) {
if (stream_offset == stream_offsets[j]) {
if (entry_stream_offset == stream_offsets[j]) {
is_dupe = 1;
break;
}
}
if (is_dupe)
continue;
stream_offsets[total_subsongs] = stream_offset;
stream_offsets[total_subsongs] = entry_stream_offset;
/* ok */
total_subsongs++;

View File

@ -2,7 +2,7 @@
#include "../coding/coding.h"
typedef enum { PSX, DSP, XBOX, WMA } strwav_codec;
typedef enum { PSX, DSP, XBOX, WMA, IMA } strwav_codec;
typedef struct {
int32_t channels;
int32_t sample_rate;
@ -126,6 +126,12 @@ VGMSTREAM * init_vgmstream_str_wav(STREAMFILE *streamFile) {
goto fail; /* only 2ch+..+2ch layout is known */
break;
case IMA:
vgmstream->coding_type = coding_BLITZ_IMA;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = strwav.interleave;
break;
#ifdef VGM_USE_FFMPEG
case WMA: {
ffmpeg_codec_data *ffmpeg_data = NULL;
@ -330,6 +336,27 @@ static int parse_header(STREAMFILE* streamHeader, strwav_header* strwav) {
return 1;
}
/* Zapper: One Wicked Cricket! (PC)[2005] */
if ( read_32bitBE(0x04,streamHeader) == 0x00000900 &&
read_32bitLE(0x24,streamHeader) == read_32bitLE(0x114,streamHeader) && /* sample rate repeat */
read_32bitLE(0x28,streamHeader) == 0x10 &&
read_32bitLE(0x12c,streamHeader) == header_size /* ~0x130 */
) {
strwav->num_samples = read_32bitLE(0x20,streamHeader);
strwav->sample_rate = read_32bitLE(0x24,streamHeader);
strwav->flags = read_32bitLE(0x2c,streamHeader);
strwav->loop_start = read_32bitLE(0x54,streamHeader);
strwav->loop_end = read_32bitLE(0x30,streamHeader);
strwav->channels = read_32bitLE(0xF8,streamHeader) * (strwav->flags & 0x02 ? 2 : 1); /* tracks of 2/1ch */
strwav->loop_flag = strwav->flags & 0x01;
strwav->interleave = strwav->channels > 2 ? 0x8000 : 0x10000;
strwav->codec = IMA;
//;VGM_LOG("STR+WAV: header Zapper (PC)\n");
return 1;
}
/* Pac-Man World 3 (GC)[2005] */
/* SpongeBob SquarePants: Creature from the Krusty Krab (GC)[2006] */
if ( read_32bitBE(0x04,streamHeader) == 0x00000800 &&
@ -405,6 +432,7 @@ static int parse_header(STREAMFILE* streamHeader, strwav_header* strwav) {
read_32bitBE(0x04,streamHeader) == 0x00000700) && /* rare? */
read_32bitLE(0x08,streamHeader) != 0x00000000 &&
read_32bitBE(0x0c,streamHeader) == header_size && /* variable per DSP header */
read_32bitBE(0x7c,streamHeader) != 0 && /* has DSP header */
read_32bitBE(0x38,streamHeader) == read_32bitBE(read_32bitBE(0x7c,streamHeader)+0x38,streamHeader) /* sample rate vs 1st DSP header */
) {
strwav->loop_start = 0; //read_32bitLE(0x24,streamHeader); //not ok?
@ -419,10 +447,31 @@ static int parse_header(STREAMFILE* streamHeader, strwav_header* strwav) {
strwav->coefs_table = 0x7c;
strwav->codec = DSP;
//;VGM_LOG("STR+WAV: header Tak (Wii)\n");
//;VGM_LOG("STR+WAV: header Tak/HOTD:O (Wii)\n");
return 1;
}
/* The House of the Dead: Overkill (PS3)[2009] (not Blitz but still the same format) */
if ((read_32bitBE(0x04,streamHeader) == 0x00000800 ||
read_32bitBE(0x04,streamHeader) == 0x00000700) && /* rare? */
read_32bitLE(0x08,streamHeader) != 0x00000000 &&
read_32bitBE(0x0c,streamHeader) == header_size && /* variable per DSP header */
read_32bitBE(0x7c,streamHeader) == 0 /* not DSP header */
) {
strwav->loop_start = 0; //read_32bitLE(0x24,streamHeader); //not ok?
strwav->num_samples = read_32bitBE(0x30,streamHeader);
strwav->loop_end = read_32bitBE(0x34,streamHeader);
strwav->sample_rate = read_32bitBE(0x38,streamHeader);
strwav->flags = read_32bitBE(0x3c,streamHeader);
strwav->channels = read_32bitBE(0x70,streamHeader); /* tracks of 1ch */
strwav->loop_flag = strwav->flags & 0x01;
strwav->interleave = strwav->channels > 4 ? 0x4000 : 0x8000;
strwav->codec = PSX;
//;VGM_LOG("STR+WAV: header HOTD:O (PS3)\n");
return 1;
}
/* unknown */
goto fail;

View File

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

View File

@ -5,32 +5,62 @@
/* SXD - Sony/SCE's SNDX lib format (cousin of SGXD) [Gravity Rush, Freedom Wars, Soul Sacrifice PSV] */
VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * streamHeader = NULL, *streamData = NULL;
STREAMFILE *streamHeader = NULL, *streamExternal = NULL, *streamData = NULL, *streamHead = NULL, *streamBody = NULL;
off_t start_offset, chunk_offset, first_offset = 0x60, name_offset = 0;
size_t chunk_size, stream_size = 0;
int is_dual = 0, is_external = 0;
int is_dual, is_external;
int loop_flag, channels, codec, flags;
int sample_rate, num_samples, loop_start_sample, loop_end_sample;
uint32_t at9_config_data = 0;
int total_subsongs, target_subsong = streamFile->stream_index;
/* check extension, case insensitive */
/* .sxd: header+data (SXDF), .sxd1: header (SXDF) + .sxd2 = data (SXDS) */
if (!check_extensions(streamFile,"sxd,sxd2")) goto fail;
is_dual = !check_extensions(streamFile,"sxd");
/* checks */
/* .sxd: header+data (SXDF)
* .sxd1: header (SXDF) + .sxd2 = data (SXDS)
* .sxd3: sxd1 + sxd2 pasted together (found in some PS4 games, ex. Fate Extella)*/
if (!check_extensions(streamFile,"sxd,sxd2,sxd3"))
goto fail;
/* sxd1+sxd2: use sxd1 as header; otherwise use the current file as header */
if (is_dual) {
if (read_32bitBE(0x00,streamFile) != 0x53584453) /* "SXDS" */
goto fail;
streamHeader = open_streamfile_by_ext(streamFile, "sxd1");
if (!streamHeader) goto fail;
} else {
streamHeader = streamFile;
/* setup head/body variations */
if (check_extensions(streamFile,"sxd2")) {
/* sxd1+sxd2: open sxd1 as header */
streamHead = open_streamfile_by_ext(streamFile, "sxd1");
if (!streamHead) goto fail;
streamHeader = streamHead;
streamExternal = streamFile;
is_dual = 1;
}
if (read_32bitBE(0x00,streamHeader) != 0x53584446) /* "SXDF" */
else if (check_extensions(streamFile,"sxd3")) {
/* sxd3: make subfiles for head and body to simplify parsing */
off_t sxd1_offset = 0x00;
size_t sxd1_size = read_32bitLE(0x08, streamFile);
off_t sxd2_offset = sxd1_size;
size_t sxd2_size = get_streamfile_size(streamFile) - sxd1_size;
streamHead = setup_subfile_streamfile(streamFile, sxd1_offset, sxd1_size, "sxd1");
if (!streamHead) goto fail;
streamBody = setup_subfile_streamfile(streamFile, sxd2_offset, sxd2_size, "sxd2");
if (!streamBody) goto fail;
streamHeader = streamHead;
streamExternal = streamBody;
is_dual = 1;
}
else {
/* sxd: use the current file as header */
streamHeader = streamFile;
streamExternal = NULL;
is_dual = 0;
}
if (streamHeader && read_32bitBE(0x00,streamHeader) != 0x53584446) /* "SXDF" */
goto fail;
if (streamExternal && read_32bitBE(0x00,streamExternal) != 0x53584453) /* "SXDS" */
goto fail;
@ -132,8 +162,9 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
goto fail;
}
/* even dual files may have some non-external streams */
if (is_external) {
streamData = streamFile;
streamData = streamExternal;
} else {
streamData = streamHeader;
}
@ -196,11 +227,13 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
if (!vgmstream_open_stream(vgmstream,streamData,start_offset))
goto fail;
if (is_dual) close_streamfile(streamHeader);
if (streamHead) close_streamfile(streamHead);
if (streamBody) close_streamfile(streamBody);
return vgmstream;
fail:
if (is_dual) close_streamfile(streamHeader);
if (streamHead) close_streamfile(streamHead);
if (streamBody) close_streamfile(streamBody);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,7 +1,7 @@
#include "meta.h"
#include "../coding/coding.h"
/* AAC - Tri-Ace Audio Container */
/* AAC - tri-Ace (Aska engine) Audio Container */
/* Xbox 360 Variants (Star Ocean 4, End of Eternity, Infinite Undiscovery) */
VGMSTREAM * init_vgmstream_ta_aac_x360(STREAMFILE *streamFile) {
@ -297,12 +297,12 @@ VGMSTREAM * init_vgmstream_ta_aac_mobile(STREAMFILE *streamFile) {
if (read_32bitLE(0x148, streamFile) != (0x40-0x04*channel_count)*2 / channel_count) goto fail; /* frame samples */
if (channel_count > 2) goto fail; /* unknown data layout */
vgmstream->coding_type = coding_YAMAHA;
vgmstream->coding_type = coding_ASKA;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = yamaha_bytes_to_samples(data_size, channel_count);
vgmstream->loop_start_sample = yamaha_bytes_to_samples(read_32bitLE(0x130, streamFile), channel_count);
vgmstream->loop_end_sample = yamaha_bytes_to_samples(read_32bitLE(0x134, streamFile), channel_count);
vgmstream->num_samples = aska_bytes_to_samples(data_size, channel_count);
vgmstream->loop_start_sample = aska_bytes_to_samples(read_32bitLE(0x130, streamFile), channel_count);
vgmstream->loop_end_sample = aska_bytes_to_samples(read_32bitLE(0x134, streamFile), channel_count);
break;
default:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,161 @@
#ifndef _TXTH_STREAMFILE_H_
#define _TXTH_STREAMFILE_H_
#include "../streamfile.h"
typedef struct {
off_t chunk_start;
size_t chunk_size;
size_t chunk_header_size;
size_t chunk_data_size;
int chunk_count;
int chunk_number;
} txth_io_config_data;
typedef struct {
/* config */
txth_io_config_data cfg;
size_t stream_size;
/* state */
off_t logical_offset; /* fake offset */
off_t physical_offset; /* actual offset */
size_t block_size; /* current size */
size_t skip_size; /* size from block start to reach data */
size_t data_size; /* usable size in a block */
size_t logical_size;
} txth_io_data;
static size_t txth_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, txth_io_data* data) {
size_t total_read = 0;
/* re-start when previous offset (can't map logical<>physical offsets) */
if (data->logical_offset < 0 || offset < data->logical_offset) {
data->physical_offset = data->cfg.chunk_start;
data->logical_offset = 0x00;
data->data_size = 0;
data->skip_size = 0;
}
/* read blocks */
while (length > 0) {
/* ignore EOF */
if (offset < 0 || data->physical_offset >= data->cfg.chunk_start + data->stream_size) {
break;
}
/* process new block */
if (data->data_size == 0) {
/* base sizes */
data->block_size = data->cfg.chunk_size * data->cfg.chunk_count;
data->skip_size = data->cfg.chunk_size * data->cfg.chunk_number;
data->data_size = data->cfg.chunk_size;
/* chunk size modifiers */
if (data->cfg.chunk_header_size) {
data->skip_size += data->cfg.chunk_header_size;
data->data_size -= data->cfg.chunk_header_size;
}
if (data->cfg.chunk_data_size) {
data->data_size = data->cfg.chunk_data_size;
}
/* clamp for games where last block is smaller */ //todo not correct for all cases
if (data->physical_offset + data->block_size > data->cfg.chunk_start + data->stream_size) {
data->block_size = (data->cfg.chunk_start + data->stream_size) - data->physical_offset;
data->skip_size = (data->block_size / data->cfg.chunk_count) * data->cfg.chunk_number;
}
if (data->physical_offset + data->data_size > data->cfg.chunk_start + data->stream_size) {
data->data_size = (data->cfg.chunk_start + data->stream_size) - data->physical_offset;
}
}
/* move to next block */
if (data->data_size == 0 || offset >= data->logical_offset + data->data_size) {
data->physical_offset += data->block_size;
data->logical_offset += data->data_size;
data->data_size = 0;
continue;
}
/* read data */
{
size_t bytes_consumed, bytes_done, to_read;
bytes_consumed = offset - data->logical_offset;
to_read = data->data_size - bytes_consumed;
if (to_read > length)
to_read = length;
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
total_read += bytes_done;
dest += bytes_done;
offset += bytes_done;
length -= bytes_done;
if (bytes_done != to_read || bytes_done == 0) {
break; /* error/EOF */
}
}
}
return total_read;
}
static size_t txth_io_size(STREAMFILE *streamfile, txth_io_data* data) {
uint8_t buf[1];
if (data->logical_size)
return data->logical_size;
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
txth_io_read(streamfile, buf, 0x7FFFFFFF, 1, data);
data->logical_size = data->logical_offset;
return data->logical_size;
}
/* Handles deinterleaving of generic chunked streams */
static STREAMFILE* setup_txth_streamfile(STREAMFILE *streamFile, txth_io_config_data cfg, int is_opened_streamfile) {
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
txth_io_data io_data = {0};
size_t io_data_size = sizeof(txth_io_data);
io_data.cfg = cfg; /* memcpy */
io_data.stream_size = (get_streamfile_size(streamFile) - cfg.chunk_start);
io_data.logical_offset = -1; /* force phys offset reset */
//io_data.logical_size = io_data.stream_size / cfg.chunk_count; //todo would help with performance but not ok if data_size is set
new_streamFile = streamFile;
/* setup subfile */
if (!is_opened_streamfile) {
/* if streamFile was opened by txth code we MUST close it once done (as it's now "fused"),,
* otherwise it was external to txth and must be wrapped to avoid closing it */
new_streamFile = open_wrap_streamfile(new_streamFile);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
}
new_streamFile = open_io_streamfile(new_streamFile, &io_data,io_data_size, txth_io_read,txth_io_size);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
//new_streamFile = open_buffer_streamfile(new_streamFile,0);
//if (!new_streamFile) goto fail;
//temp_streamFile = new_streamFile;
return temp_streamFile;
fail:
close_streamfile(temp_streamFile);
return NULL;
}
#endif /* _TXTH_STREAMFILE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
#define BAO_MAX_CHAIN_COUNT 128 /* POP:TFS goes up to ~100 */
typedef enum { CODEC_NONE = 0, UBI_IMA, RAW_PCM, RAW_PSX, RAW_XMA1, RAW_XMA2_OLD, RAW_XMA2_NEW, RAW_AT3, RAW_AT3_105, FMT_AT3, RAW_DSP, FMT_OGG } ubi_bao_codec;
typedef enum { TYPE_NONE = 0, UBI_AUDIO, UBI_LAYER, UBI_SEQUENCE } ubi_bao_type;
typedef enum { TYPE_NONE = 0, UBI_AUDIO, UBI_LAYER, UBI_SEQUENCE, UBI_SILENCE } ubi_bao_type;
typedef enum { FILE_NONE = 0, UBI_FORGE, UBI_FORGE_b } ubi_bao_file;
typedef struct {
@ -16,6 +16,8 @@ typedef struct {
size_t header_base_size;
size_t header_skip;
int header_less_le_flag; /* horrid but not sure what to do */
off_t header_id;
off_t header_type;
@ -30,7 +32,7 @@ typedef struct {
off_t audio_stream_type;
off_t audio_prefetch_size;
size_t audio_interleave;
int audio_channel_samples;
int audio_fix_psx_samples;
int audio_external_and;
int audio_loop_and;
@ -56,7 +58,7 @@ typedef struct {
int layer_external_and;
int layer_ignore_error;
//off_t silence_duration_float;
off_t silence_duration_float;
ubi_bao_codec codec_map[16];
ubi_bao_file file_type;
@ -106,12 +108,13 @@ typedef struct {
int stream_type;
int layer_count;
int layer_channels[BAO_MAX_LAYER_COUNT];
int sequence_count;
uint32_t sequence_chain[BAO_MAX_CHAIN_COUNT];
int sequence_loop;
int sequence_single;
//float duration;
float duration;
char resource_name[255];
@ -201,12 +204,12 @@ VGMSTREAM * init_vgmstream_ubi_bao_spk(STREAMFILE *streamFile) {
/* Variation of .pk:
* - 0x00: 0x014B5053 ("SPK\01" LE)
* - 0x04: BAO count
* - 0x08 * count: BAO ids inside
* - 0x08: BAO ids inside (0x04 * BAO count)
* - per BAO count
* - 0x00: 1?
* - 0x04: id that references this? (ex. id of an event BAO)
* - 0x08: BAO size
* - 0x0c+: BAO data
* - 0x00: table count
* - 0x04: ids related to this BAO? (0x04 * table count)
* - 0x08/NN: BAO size
* - 0x0c/NN+: BAO data up to size
*
* BAOs reference .sbao by name (are considered atomic) so perhaps could
* be considered a type of bigfile.
@ -396,7 +399,8 @@ static VGMSTREAM * init_vgmstream_ubi_bao_base(ubi_bao_header * bao, STREAMFILE
vgmstream->layout_type = layout_none;
vgmstream->num_samples = bao->num_samples; /* ffmpeg_data->totalSamples */
VGM_ASSERT(bao->num_samples != ffmpeg_data->totalSamples, "UBI BAO: header samples differ\n");
VGM_ASSERT(bao->num_samples != ffmpeg_data->totalSamples,
"UBI BAO: header samples %i vs ffmpeg %i differ\n", bao->num_samples, (uint32_t)ffmpeg_data->totalSamples);
break;
}
@ -444,7 +448,7 @@ static VGMSTREAM * init_vgmstream_ubi_bao_layer(ubi_bao_header *bao, STREAMFILE
STREAMFILE* temp_streamFile = NULL;
STREAMFILE * streamData = NULL;
size_t full_stream_size = bao->stream_size;
int i;
int i, total_channels = 0;
streamData = setup_bao_streamfile(bao, streamFile);
if (!streamData) goto fail;
@ -461,6 +465,8 @@ static VGMSTREAM * init_vgmstream_ubi_bao_layer(ubi_bao_header *bao, STREAMFILE
if (!temp_streamFile) goto fail;
bao->stream_size = get_streamfile_size(temp_streamFile);
bao->channels = bao->layer_channels[i];
total_channels += bao->layer_channels[i];
/* build the layer VGMSTREAM (standard sb with custom streamfile) */
data->layers[i] = init_vgmstream_ubi_bao_base(bao, streamFile, temp_streamFile);
@ -474,7 +480,7 @@ static VGMSTREAM * init_vgmstream_ubi_bao_layer(ubi_bao_header *bao, STREAMFILE
goto fail;
/* build the base VGMSTREAM */
vgmstream = allocate_vgmstream(bao->channels * bao->layer_count, bao->loop_flag);
vgmstream = allocate_vgmstream(total_channels, bao->loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_UBI_BAO;
@ -576,6 +582,7 @@ static VGMSTREAM * init_vgmstream_ubi_bao_sequence(ubi_bao_header *bao, STREAMFI
if (!setup_layout_segmented(data))
goto fail;
/* build the base VGMSTREAM */
vgmstream = allocate_vgmstream(data->segments[0]->channels, !bao->sequence_single);
if (!vgmstream) goto fail;
@ -605,9 +612,78 @@ fail:
return NULL;
}
//static VGMSTREAM * init_vgmstream_ubi_bao_silence(ubi_bao_header *bao, STREAMFILE *streamFile) {
// return NULL;
//}
static size_t silence_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, void* data) {
int i;
for (i = 0; i < length; i++) {
dest[i] = 0;
}
return length; /* pretend we read zeroes */
}
static size_t silence_io_size(STREAMFILE *streamfile, void* data) {
return 0x7FFFFFF; /* whatevs */
}
static STREAMFILE* setup_silence_streamfile(STREAMFILE *streamFile) {
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
/* setup custom streamfile */
new_streamFile = open_wrap_streamfile(streamFile);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_io_streamfile(temp_streamFile, NULL,0, silence_io_read,silence_io_size);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
return temp_streamFile;
fail:
close_streamfile(temp_streamFile);
return NULL;
}
static VGMSTREAM * init_vgmstream_ubi_bao_silence(ubi_bao_header *bao, STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
int channel_count, sample_rate;
channel_count = bao->channels;
sample_rate = bao->sample_rate;
/* by default silences don't have settings so let's pretend */
if (channel_count == 0)
channel_count = 2;
if (sample_rate == 0)
sample_rate = 48000;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, 0);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_UBI_BAO;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = bao->duration * sample_rate;
vgmstream->num_streams = bao->total_subsongs;
vgmstream->stream_size = vgmstream->num_samples * channel_count * 0x02; /* PCM size */
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
temp_streamFile = setup_silence_streamfile(streamFile);
if ( !vgmstream_open_stream(vgmstream, temp_streamFile, 0x00) )
goto fail;
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_vgmstream(vgmstream);
close_streamfile(temp_streamFile);
return vgmstream;
}
static VGMSTREAM * init_vgmstream_ubi_bao_header(ubi_bao_header * bao, STREAMFILE * streamFile) {
@ -618,12 +694,12 @@ static VGMSTREAM * init_vgmstream_ubi_bao_header(ubi_bao_header * bao, STREAMFIL
goto fail; /* not uncommon */
}
;VGM_LOG("UBI BAO: target at %x, h_id=%08x, s_id=%08x, p_id=%08x\n",
(uint32_t)bao->header_offset, bao->header_id, bao->stream_id, bao->prefetch_id);
;VGM_LOG("UBI BAO: stream=%x, size=%x, res=%s\n",
(uint32_t)bao->stream_offset, bao->stream_size, (bao->is_external ? bao->resource_name : "internal"));
;VGM_LOG("UBI BAO: type=%i, header=%x, extra=%x, prefetch=%x, size=%x\n",
bao->header_type, bao->header_size, bao->extra_size, (uint32_t)bao->prefetch_offset, bao->prefetch_size);
//;VGM_LOG("UBI BAO: target at %x, h_id=%08x, s_id=%08x, p_id=%08x\n",
// (uint32_t)bao->header_offset, bao->header_id, bao->stream_id, bao->prefetch_id);
//;VGM_LOG("UBI BAO: stream=%x, size=%x, res=%s\n",
// (uint32_t)bao->stream_offset, bao->stream_size, (bao->is_external ? bao->resource_name : "internal"));
//;VGM_LOG("UBI BAO: type=%i, header=%x, extra=%x, prefetch=%x, size=%x\n",
// bao->header_type, bao->header_size, bao->extra_size, (uint32_t)bao->prefetch_offset, bao->prefetch_size);
switch(bao->type) {
@ -640,16 +716,15 @@ static VGMSTREAM * init_vgmstream_ubi_bao_header(ubi_bao_header * bao, STREAMFIL
vgmstream = init_vgmstream_ubi_bao_sequence(bao, streamFile);
break;
//case UBI_SILENCE:
// vgmstream = init_vgmstream_ubi_bao_silence(bao, streamFile);
// break;
case UBI_SILENCE:
vgmstream = init_vgmstream_ubi_bao_silence(bao, streamFile);
break;
default:
VGM_LOG("UBI BAO: subsong not found/parsed\n");
goto fail;
}
if (!vgmstream) goto fail;
strcpy(vgmstream->stream_name, bao->readable_name);
@ -729,8 +804,8 @@ static int parse_pk(ubi_bao_header * bao, STREAMFILE *streamFile) {
bao_offset += bao_size; /* files simply concat BAOs */
}
;VGM_LOG("UBI BAO: class "); {int i; for (i=0;i<16;i++){ VGM_ASSERT(bao->classes[i],"%02x=%i ",i,bao->classes[i]); }} VGM_LOG("\n");
;VGM_LOG("UBI BAO: types "); {int i; for (i=0;i<16;i++){ VGM_ASSERT(bao->types[i],"%02x=%i ",i,bao->types[i]); }} VGM_LOG("\n");
//;VGM_LOG("UBI BAO: class "); {int i; for (i=0;i<16;i++){ VGM_ASSERT(bao->classes[i],"%02x=%i ",i,bao->classes[i]); }} VGM_LOG("\n");
//;VGM_LOG("UBI BAO: types "); {int i; for (i=0;i<16;i++){ VGM_ASSERT(bao->types[i],"%02x=%i ",i,bao->types[i]); }} VGM_LOG("\n");
close_streamfile(streamIndex);
close_streamfile(streamTest);
@ -827,10 +902,6 @@ static int parse_type_audio(ubi_bao_header * bao, off_t offset, STREAMFILE* stre
bao->stream_type = read_32bit(h_offset + bao->cfg.audio_stream_type, streamFile);
if (bao->loop_flag && bao->cfg.audio_channel_samples) {
bao->num_samples = bao->num_samples / bao->channels;
}
return 1;
//fail:
// return 0;
@ -919,7 +990,7 @@ static int parse_type_layer(ubi_bao_header * bao, off_t offset, STREAMFILE* stre
/* get 1st layer header in extra table and validate all headers match */
table_offset = offset + bao->header_size + cues_size;
bao->channels = read_32bit(table_offset + bao->cfg.layer_channels, streamFile);
//bao->channels = read_32bit(table_offset + bao->cfg.layer_channels, streamFile);
bao->sample_rate = read_32bit(table_offset + bao->cfg.layer_sample_rate, streamFile);
bao->stream_type = read_32bit(table_offset + bao->cfg.layer_stream_type, streamFile);
bao->num_samples = read_32bit(table_offset + bao->cfg.layer_num_samples, streamFile);
@ -933,15 +1004,14 @@ static int parse_type_layer(ubi_bao_header * bao, off_t offset, STREAMFILE* stre
VGM_LOG("UBI BAO: layer headers don't match at %x\n", (uint32_t)table_offset);
if (bao->cfg.layer_ignore_error) {
bao->layer_count -= 1;
break;
continue;
}
goto fail;
}
/* unusual but happens, layers handle it fine [Rayman Raving Rabbids: TV Party (Wii) ex. 0x22000cbc.pk] */
VGM_ASSERT_ONCE(bao->channels != channels, "UBI BAO: layer channels don't match at %x\n", (uint32_t)table_offset);
/* uncommonly channels may vary per layer [Rayman Raving Rabbids: TV Party (Wii) ex. 0x22000cbc.pk] */
bao->layer_channels[i] = channels;
/* can be +-1 */
if (bao->num_samples != num_samples && bao->num_samples + 1 == num_samples) {
@ -956,10 +1026,39 @@ fail:
return 0;
}
static int parse_type_silence(ubi_bao_header * bao, off_t offset, STREAMFILE* streamFile) {
int32_t (*read_32bit)(off_t,STREAMFILE*) = bao->big_endian ? read_32bitBE : read_32bitLE;
off_t h_offset = offset + bao->header_skip;
uint32_t duration_int;
float* duration_float;
/* silence header */
bao->type = UBI_SILENCE;
if (bao->cfg.silence_duration_float == 0) {
VGM_LOG("UBI BAO: silence duration not configured at %x\n", (uint32_t)offset);
goto fail;
}
{
duration_int = (uint32_t)read_32bit(h_offset + bao->cfg.silence_duration_float, streamFile);
duration_float = (float*)&duration_int;
bao->duration = *duration_float;
}
if (bao->duration <= 0) {
VGM_LOG("UBI BAO: bad duration %f at %x\n", bao->duration, (uint32_t)offset);
goto fail;
}
return 1;
fail:
return 0;
}
/* adjust some common values */
static int parse_values(ubi_bao_header * bao, STREAMFILE *streamFile) {
if (bao->type == UBI_SEQUENCE)
if (bao->type == UBI_SEQUENCE || bao->type == UBI_SILENCE)
return 1;
/* common validations */
@ -979,6 +1078,10 @@ static int parse_values(ubi_bao_header * bao, STREAMFILE *streamFile) {
goto fail;
}
if (bao->type == UBI_AUDIO && bao->codec == RAW_PSX && bao->cfg.audio_fix_psx_samples && bao->loop_flag) { //todo: loop flag only?
bao->num_samples = bao->num_samples / bao->channels;
}
/* set prefetch id */
if (bao->is_prefetched) {
@ -1015,7 +1118,7 @@ static int parse_offsets(ubi_bao_header * bao, STREAMFILE *streamFile) {
off_t bao_offset;
size_t bao_size;
if (bao->type == UBI_SEQUENCE)
if (bao->type == UBI_SEQUENCE || bao->type == UBI_SILENCE)
return 1;
if (!bao->is_external && bao->is_prefetched) {
@ -1036,7 +1139,8 @@ static int parse_offsets(ubi_bao_header * bao, STREAMFILE *streamFile) {
if (bao->is_prefetched) {
bao->prefetch_offset = bao->memory_skip;
}
else if (bao->is_external) {
if (bao->is_external) {
bao->stream_offset = bao->stream_skip;
}
else {
@ -1153,9 +1257,14 @@ static int parse_header(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offs
bao->header_size = bao->cfg.header_base_size;
/* hack for games with smaller than standard
* (can't use lowest size as other games also have extra unused field) */
if (bao->cfg.header_less_le_flag && !bao->big_endian) {
bao->header_size -= 0x04;
}
/* detect extra unused field in PC/Wii
* (could be improved but no apparent flags or anything useful) */
if (get_streamfile_size(streamFile) > offset + bao->header_size) {
else if (get_streamfile_size(streamFile) > offset + bao->header_size) {
/* may read next BAO version, layer header, cues, resource table size, etc, always > 1 */
int32_t end_field = read_32bit(offset + bao->header_size, streamFile);
@ -1176,6 +1285,10 @@ static int parse_header(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offs
if (!parse_type_layer(bao, offset, streamFile))
goto fail;
break;
case 0x08:
if (!parse_type_silence(bao, offset, streamFile))
goto fail;
break;
default:
VGM_LOG("UBI BAO: unknown header type at %x\n", (uint32_t)offset);
goto fail;
@ -1267,6 +1380,10 @@ static STREAMFILE * open_atomic_bao(ubi_bao_file file_type, uint32_t file_id, in
streamBAO = open_streamfile_by_filename(streamFile, buf);
if (streamBAO) return streamBAO;
snprintf(buf,buf_size, "Spanish_BAO_0x%08x", file_id);
streamBAO = open_streamfile_by_filename(streamFile, buf);
if (streamBAO) return streamBAO;
snprintf(buf,buf_size, "German_BAO_0x%08x", file_id);
streamBAO = open_streamfile_by_filename(streamFile, buf);
if (streamBAO) return streamBAO;
@ -1275,7 +1392,11 @@ static STREAMFILE * open_atomic_bao(ubi_bao_file file_type, uint32_t file_id, in
streamBAO = open_streamfile_by_filename(streamFile, buf);
if (streamBAO) return streamBAO;
snprintf(buf,buf_size, "Spanish_BAO_0x%08x", file_id);
snprintf(buf,buf_size, "Japanese_BAO_0x%08x", file_id);
streamBAO = open_streamfile_by_filename(streamFile, buf);
if (streamBAO) return streamBAO;
snprintf(buf,buf_size, "Korean_BAO_0x%08x", file_id);
streamBAO = open_streamfile_by_filename(streamFile, buf);
if (streamBAO) return streamBAO;
@ -1283,7 +1404,15 @@ static STREAMFILE * open_atomic_bao(ubi_bao_file file_type, uint32_t file_id, in
streamBAO = open_streamfile_by_filename(streamFile, buf);
if (streamBAO) return streamBAO;
/* there may be more per language */
snprintf(buf,buf_size, "Czech_BAO_0x%08x", file_id);
streamBAO = open_streamfile_by_filename(streamFile, buf);
if (streamBAO) return streamBAO;
snprintf(buf,buf_size, "Polish_BAO_0x%08x", file_id);
streamBAO = open_streamfile_by_filename(streamFile, buf);
if (streamBAO) return streamBAO;
/* these are all of the languages that were referenced in Assassin's Creed exe (out of each platform), there may be more */
}
else {
snprintf(buf,buf_size, "BAO_0x%08x", file_id);
@ -1501,7 +1630,7 @@ static void config_bao_layer_m(ubi_bao_header * bao, off_t stream_id, off_t laye
bao->cfg.layer_external_flag = external_flag;
bao->cfg.layer_stream_size = stream_size;
bao->cfg.layer_extra_size = extra_size;
bao->cfg.layer_prefetch_size = prefetch_size; /* possible flag: 0x3c */
bao->cfg.layer_prefetch_size = prefetch_size;
bao->cfg.layer_cue_count = cue_count;
bao->cfg.layer_cue_labels = cue_labels;
bao->cfg.layer_external_and = external_and;
@ -1515,6 +1644,12 @@ static void config_bao_layer_e(ubi_bao_header * bao, off_t entry_size, off_t sam
bao->cfg.layer_num_samples = num_samples;
}
static void config_bao_silence_f(ubi_bao_header * bao, off_t duration) {
/* silence headers in float value */
bao->cfg.silence_duration_float = duration;
}
static int config_bao_version(ubi_bao_header * bao, STREAMFILE *streamFile) {
/* Ubi BAO evolved from Ubi SB and are conceptually quite similar, see that first.
@ -1525,14 +1660,15 @@ static int config_bao_version(ubi_bao_header * bao, STREAMFILE *streamFile) {
* - 0x04+: mini header (varies with version, see parse_header)
*
* Then are divided into "classes":
* - 0x10000000: event (links by id to another event or header BAO)
* - 0x10000000: event (links by id to another event or header BAO, may set volume/reverb/filters/etc)
* - 0x20000000: header
* - 0x30000000: memory audio (in .pk/.bao)
* - 0x40000000: project info
* - 0x50000000: stream audio (in .spk/.sbao)
* - 0x60000000: unused?
* - 0x70000000: info? has a count+table of id-things
* - 0x80000000: unknown (some id/info?)
* - 0x80000000: unknown (some floats?)
* - 0x90000000: unknown (some kind of command config?), rare [Ghost Recon Future Soldier (PC)]
* Class 1/2/3 are roughly equivalent to Ubi SB's section1/2/3, and class 4 is
* basically .spN project files.
*
@ -1581,18 +1717,20 @@ static int config_bao_version(ubi_bao_header * bao, STREAMFILE *streamFile) {
switch(bao->version) {
case 0x001B0100: /* Assassin's Creed (PS3/X360/PC)-atomic-forge */
config_bao_entry(bao, 0xA4, 0x28);
config_bao_entry(bao, 0xA4, 0x28); /* PC: 0xA8, PS3/X360: 0xA4 */
config_bao_audio_b(bao, 0x08, 0x1c, 0x28, 0x34, 1, 1); /* 0x2c: prefetch flag? */
config_bao_audio_m(bao, 0x44, 0x4c, 0x50, 0x58, 0x64, 0x74);
config_bao_audio_m(bao, 0x44, 0x48, 0x50, 0x58, 0x64, 0x74);
bao->cfg.audio_interleave = 0x10;
bao->cfg.audio_channel_samples = 1; //todo check all looping ps-adpcm
bao->cfg.audio_fix_psx_samples = 1;
config_bao_sequence(bao, 0x2c, 0x20, 0x1c, 0x14);
config_bao_layer_m(bao, 0x4c, 0x20, 0x2c, 0x44, 0x00, 0x50, 0x00, 0x00, 1); /* stream size: 0x48? */
config_bao_layer_e(bao, 0x30, 0x00, 0x04, 0x08, 0x10);
config_bao_silence_f(bao, 0x1c);
bao->cfg.codec_map[0x02] = RAW_PSX;
bao->cfg.codec_map[0x03] = UBI_IMA;
bao->cfg.codec_map[0x04] = FMT_OGG;
@ -1606,7 +1744,7 @@ static int config_bao_version(ubi_bao_header * bao, STREAMFILE *streamFile) {
case 0x001F0011: /* Naruto: The Broken Bond (X360)-package */
case 0x0022000D: /* Just Dance (Wii)-package */
case 0x0022001B: /* Prince of Persia: The Forgotten Sands (Wii)-package */
config_bao_entry(bao, 0xA4, 0x28);
config_bao_entry(bao, 0xA4, 0x28); /* PC/Wii: 0xA8 */
config_bao_audio_b(bao, 0x08, 0x1c, 0x28, 0x34, 1, 1);
config_bao_audio_m(bao, 0x44, 0x4c, 0x54, 0x5c, 0x64, 0x74); /* cues: 0x68, 0x6c */
@ -1616,6 +1754,8 @@ static int config_bao_version(ubi_bao_header * bao, STREAMFILE *streamFile) {
config_bao_layer_m(bao, 0x00, 0x20, 0x2c, 0x44, 0x4c, 0x50, 0x54, 0x58, 1); /* 0x1c: id-like, 0x3c: prefetch flag? */
config_bao_layer_e(bao, 0x28, 0x00, 0x04, 0x08, 0x10);
config_bao_silence_f(bao, 0x1c);
bao->cfg.codec_map[0x01] = RAW_PCM;
bao->cfg.codec_map[0x03] = UBI_IMA;
bao->cfg.codec_map[0x04] = FMT_OGG;
@ -1628,7 +1768,7 @@ static int config_bao_version(ubi_bao_header * bao, STREAMFILE *streamFile) {
case 0x00220015: /* James Cameron's Avatar: The Game (PSP)-package */
case 0x0022001E: /* Prince of Persia: The Forgotten Sands (PSP)-package */
config_bao_entry(bao, 0x84, 0x28);
config_bao_entry(bao, 0x84, 0x28); /* PSP: 0x84 */
config_bao_audio_b(bao, 0x08, 0x1c, 0x20, 0x20, (1 << 2), (1 << 5)); /* (1 << 4): prefetch flag? */
config_bao_audio_m(bao, 0x28, 0x30, 0x38, 0x40, 0x48, 0x58);
@ -1642,7 +1782,7 @@ static int config_bao_version(ubi_bao_header * bao, STREAMFILE *streamFile) {
return 1;
case 0x00230008: /* Splinter Cell: Conviction (X360/PC)-package */
config_bao_entry(bao, 0xB4, 0x28);
config_bao_entry(bao, 0xB4, 0x28); /* PC: 0xB8, X360: 0xB4 */
config_bao_audio_b(bao, 0x08, 0x24, 0x38, 0x44, 1, 1);
config_bao_audio_m(bao, 0x54, 0x5c, 0x64, 0x6c, 0x74, 0x84);
@ -1663,17 +1803,24 @@ static int config_bao_version(ubi_bao_header * bao, STREAMFILE *streamFile) {
case 0x00250108: /* Scott Pilgrim vs the World (PS3/X360)-package */
case 0x0025010A: /* Prince of Persia: The Forgotten Sands (PS3/X360)-atomic-forge */
case 0x00250119: /* Shaun White Skateboarding (Wii)-package */
case 0x0025011D: /* Shaun White Skateboarding (PS3)-atomic-forge */
config_bao_entry(bao, 0xB4, 0x28);
case 0x0025011D: /* Shaun White Skateboarding (PC/PS3)-atomic-forge */
config_bao_entry(bao, 0xB4, 0x28); /* PC: 0xB0, PS3/X360: 0xB4, Wii: 0xB8 */
if (bao->version == 0x0025011D)
bao->cfg.header_less_le_flag = 1;
config_bao_audio_b(bao, 0x08, 0x24, 0x2c, 0x38, 1, 1);
config_bao_audio_m(bao, 0x48, 0x50, 0x58, 0x60, 0x68, 0x78);
bao->cfg.audio_interleave = 0x10;
config_bao_sequence(bao, 0x34, 0x28, 0x24, 0x14);
config_bao_layer_m(bao, 0x00, 0x28, 0x30, 0x48, 0x50, 0x54, 0x58, 0x5c, 1); /* 0x24: id-like */
config_bao_layer_e(bao, 0x30, 0x00, 0x04, 0x08, 0x18);
//todo some SPvsTW layers look like should loop (0x30 flag?)
//todo some POP layers have different sample rates (ambience)
config_bao_silence_f(bao, 0x24);
bao->cfg.codec_map[0x01] = RAW_PCM;
bao->cfg.codec_map[0x02] = UBI_IMA;
@ -1687,6 +1834,29 @@ static int config_bao_version(ubi_bao_header * bao, STREAMFILE *streamFile) {
bao->cfg.file_type = UBI_FORGE_b;
return 1;
case 0x00280303: /* Tom Clancy's Ghost Recon Future Soldier (PC/PS3)-pk */
config_bao_entry(bao, 0xBC, 0x28); /* PC/PS3: 0xBC */
config_bao_audio_b(bao, 0x08, 0x38, 0x3c, 0x48, 1, 1);
config_bao_audio_m(bao, 0x54, 0x5c, 0x64, 0x6c, 0x74, 0x80);
config_bao_sequence(bao, 0x48, 0x3c, 0x38, 0x14);
config_bao_layer_m(bao, 0x00, 0x3c, 0x44, 0x58, 0x60, 0x64, 0x00, 0x00, 1);
config_bao_layer_e(bao, 0x2c, 0x00, 0x04, 0x08, 0x1c);
bao->cfg.layer_ignore_error = 1; //todo some layer sample rates don't match
//todo some files have strange prefetch+stream of same size (2 segments?), ex. CEND_30_VOX.lpk
config_bao_silence_f(bao, 0x38);
bao->cfg.codec_map[0x01] = RAW_PCM;
bao->cfg.codec_map[0x02] = UBI_IMA; /* v6 */
bao->cfg.codec_map[0x04] = FMT_OGG;
bao->cfg.codec_map[0x07] = RAW_AT3; //todo some layers use AT3_105
bao->cfg.file_type = UBI_FORGE_b;
return 1;
case 0x001B0200: /* Beowulf (PS3)-atomic-bin+fat */
/* same as 0x001B0100 except:
* - base 0xA0, skip 0x24, name style %08x (.bao/sbao?) */
@ -1694,6 +1864,7 @@ static int config_bao_version(ubi_bao_header * bao, STREAMFILE *streamFile) {
/* same as 0x001B0100 except:
* - base 0xA0, skip 0x24, name style %08x.bao (not .sbao?) */
case 0x001D0A00: /* Shaun White Snowboarding (PSP)-atomic-opal */
case 0x00220017: /* Avatar (PS3)-atomic/spk */
case 0x00220018: /* Avatar (PS3)-atomic/spk */
case 0x00260102: /* Prince of Persia Trilogy HD (PS3)-package-gear */
/* similar to 0x00250108 but most values are moved +4
@ -1704,6 +1875,8 @@ static int config_bao_version(ubi_bao_header * bao, STREAMFILE *streamFile) {
* - base varies per type (0xF0=audio), skip 0x20
* - 0x74: type, 0x78: channels, 0x7c: sample rate, 0x80: num_samples
* - 0x94: stream id? 0x9C: extra size */
case 0x002A0300: /* Watch Dogs (Wii U) */
/* similar to SC:B */
default: /* others possibly using BAO: Just Dance, Watch_Dogs, Far Cry Primal, Far Cry 4 */
VGM_LOG("UBI BAO: unknown BAO version %08x\n", bao->version);
return 0;

View File

@ -5,7 +5,7 @@
#include "ubi_sb_streamfile.h"
static STREAMFILE* setup_ubi_bao_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t stream_size, int layer_number, int layer_count, int big_endian) {
return setup_ubi_sb_streamfile(streamFile, stream_offset, stream_size, layer_number, layer_count, big_endian);
return setup_ubi_sb_streamfile(streamFile, stream_offset, stream_size, layer_number, layer_count, big_endian, 0);
}
#endif /* _UBI_BAO_STREAMFILE_H_ */

View File

@ -233,7 +233,7 @@ VGMSTREAM * init_vgmstream_ubi_jade(STREAMFILE *streamFile) {
temp_streamFile = setup_subfile_streamfile(streamFile, start_offset, data_size, "msf");
if (!temp_streamFile) goto fail;
temp_vgmstream = init_vgmstream_ps3_msf(temp_streamFile);
temp_vgmstream = init_vgmstream_msf(temp_streamFile);
close_streamfile(temp_streamFile);
if (!temp_vgmstream) goto fail;

View File

@ -103,20 +103,20 @@ VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE *streamFile) {
case 0x4361666561647063: /* "Cafeadpc" (Cafe = WiiU) */
/* chunks: "datS" (stereo), "datL" (mono or full interleave), "datR" (full interleave), "data" equivalents */
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = channel_count==1 ? layout_none : layout_interleave;
vgmstream->interleave_block_size = 8;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x8;
/* we need to know if the file uses "datL" and is full-interleave */
if (channel_count > 1) {
off_t chunk_off = offset+ 0x20 + 0xc; /* after "fmt" */
while (chunk_off < header_size) {
if (read_32bitBE(chunk_off,streamFile) == 0x6461744C) { /*"datL" found */
size_t chunk_size = read_32bit(chunk_off+0x8,streamFile);
off_t chunk_offset = offset+ 0x20 + 0xc; /* after "fmt" */
while (chunk_offset < header_size) {
if (read_32bitBE(chunk_offset,streamFile) == 0x6461744C) { /* "datL" found */
size_t chunk_size = read_32bit(chunk_offset+0x8,streamFile);
data_size = chunk_size * channel_count; /* to avoid counting the "datR" chunk */
vgmstream->interleave_block_size = (4+4) + chunk_size; /* don't forget to skip the "datR"+size chunk */
break;
}
chunk_off += 0xc;
chunk_offset += 0xc;
}
/* not found? probably "datS" (regular stereo interleave) */
@ -132,6 +132,38 @@ VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE *streamFile) {
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
break;
case 0x4354520061647063: /* "CTR\0adpc" (Citrus = 3DS) */
/* chunks: "dspL" (CWAV-L header), "dspR" (CWAV-R header), "cwav" ("data" equivalent) */
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x8;
/* reading could be improved but should work with some luck since most values are semi-fixed */
if (channel_count > 1) {
/* find "dspL" pointing to "CWAV" header and read coefs (separate from data at start_offset) */
off_t chunk_offset = offset+ 0x20 + 0xc; /* after "fmt" */
while (chunk_offset < header_size) {
if (read_32bitBE(chunk_offset,streamFile) == 0x6473704C) { /* "dspL" found */
off_t cwav_offset = read_32bit(chunk_offset+0x4,streamFile);
size_t cwav_size = read_32bit(chunk_offset+0x8,streamFile);
dsp_read_coefs(vgmstream,streamFile, cwav_offset + 0x7c, cwav_size, big_endian);
break;
}
chunk_offset += 0xc;
}
}
else {
/* CWAV at start (a full CWAV, unlike the above) */
dsp_read_coefs(vgmstream,streamFile, start_offset + 0x7c, 0x00, big_endian);
start_offset += 0xE0;
data_size = get_streamfile_size(streamFile) - start_offset;
}
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
break;
#ifdef VGM_USE_MPEG
case 0x505333206D703320: { /* "PS3 mp3 " */
/* chunks: "MARK" (optional seek table), "STRG" (optional description), "Msf " ("data" equivalent) */

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