Updated VGMStream to r1050-3774-gbecac809
parent
75a4f1e722
commit
636120c9d5
|
@ -155,7 +155,6 @@
|
|||
8349A9091FE6258200E26435 /* pc_ast.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8F01FE6257C00E26435 /* pc_ast.c */; };
|
||||
8349A90A1FE6258200E26435 /* sab.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8F11FE6257D00E26435 /* sab.c */; };
|
||||
8349A90B1FE6258200E26435 /* ps2_pcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8F21FE6257D00E26435 /* ps2_pcm.c */; };
|
||||
8349A90C1FE6258200E26435 /* sqex_scd_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8349A8F31FE6257D00E26435 /* sqex_scd_streamfile.h */; };
|
||||
8349A90D1FE6258200E26435 /* ubi_sb.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8F41FE6257D00E26435 /* ubi_sb.c */; };
|
||||
8349A90E1FE6258200E26435 /* scd_pcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8F51FE6257D00E26435 /* scd_pcm.c */; };
|
||||
8349A90F1FE6258200E26435 /* aix_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8349A8F61FE6257E00E26435 /* aix_streamfile.h */; };
|
||||
|
@ -266,7 +265,6 @@
|
|||
836F6F6518BDC2190095E648 /* 2dx9.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2918BDC2180095E648 /* 2dx9.c */; };
|
||||
836F6F6618BDC2190095E648 /* aax.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2A18BDC2180095E648 /* aax.c */; };
|
||||
836F6F6718BDC2190095E648 /* acm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2B18BDC2180095E648 /* acm.c */; };
|
||||
836F6F6818BDC2190095E648 /* ads.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2C18BDC2180095E648 /* ads.c */; };
|
||||
836F6F6B18BDC2190095E648 /* agsc.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2F18BDC2180095E648 /* agsc.c */; };
|
||||
836F6F6C18BDC2190095E648 /* ahx.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E3018BDC2180095E648 /* ahx.c */; };
|
||||
836F6F6D18BDC2190095E648 /* aifc.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E3118BDC2180095E648 /* aifc.c */; };
|
||||
|
@ -333,7 +331,6 @@
|
|||
836F6FB718BDC2190095E648 /* ngc_ssm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7B18BDC2180095E648 /* ngc_ssm.c */; };
|
||||
836F6FB818BDC2190095E648 /* ngc_tydsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7C18BDC2180095E648 /* ngc_tydsp.c */; };
|
||||
836F6FBA18BDC2190095E648 /* ngc_ymf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7E18BDC2180095E648 /* ngc_ymf.c */; };
|
||||
836F6FBB18BDC2190095E648 /* ngca.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7F18BDC2180095E648 /* ngca.c */; };
|
||||
836F6FBD18BDC2190095E648 /* nwa.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8118BDC2180095E648 /* nwa.c */; };
|
||||
836F6FBF18BDC2190095E648 /* otm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8318BDC2180095E648 /* otm.c */; };
|
||||
836F6FC018BDC2190095E648 /* p3d.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8418BDC2180095E648 /* p3d.c */; };
|
||||
|
@ -447,7 +444,6 @@
|
|||
83709E051ECBC1A4005C03D3 /* gtd.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709DFF1ECBC1A4005C03D3 /* gtd.c */; };
|
||||
83709E061ECBC1A4005C03D3 /* mc3.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E001ECBC1A4005C03D3 /* mc3.c */; };
|
||||
83709E071ECBC1A4005C03D3 /* mss.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E011ECBC1A4005C03D3 /* mss.c */; };
|
||||
83709E081ECBC1A4005C03D3 /* ps2_rxws.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E021ECBC1A4005C03D3 /* ps2_rxws.c */; };
|
||||
83709E091ECBC1A4005C03D3 /* ta_aac.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E031ECBC1A4005C03D3 /* ta_aac.c */; };
|
||||
83709E0D1ECBC1C3005C03D3 /* mc3_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E0B1ECBC1C3005C03D3 /* mc3_decoder.c */; };
|
||||
83709E0E1ECBC1C3005C03D3 /* psv_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E0C1ECBC1C3005C03D3 /* psv_decoder.c */; };
|
||||
|
@ -497,6 +493,8 @@
|
|||
837CEB0423487F2C00E62A4A /* jstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 837CEAEF23487F2C00E62A4A /* jstm.c */; };
|
||||
837CEB0523487F2C00E62A4A /* sqex_sead_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 837CEAF023487F2C00E62A4A /* sqex_sead_streamfile.h */; };
|
||||
837CEB072348809400E62A4A /* seb.c in Sources */ = {isa = PBXBuildFile; fileRef = 837CEB062348809400E62A4A /* seb.c */; };
|
||||
83852B0B2680247900378854 /* rxws.c in Sources */ = {isa = PBXBuildFile; fileRef = 83852B092680247900378854 /* rxws.c */; };
|
||||
83852B0C2680247900378854 /* ads_midway.c in Sources */ = {isa = PBXBuildFile; fileRef = 83852B0A2680247900378854 /* ads_midway.c */; };
|
||||
8385D4E6245174C700FF8E67 /* diva.c in Sources */ = {isa = PBXBuildFile; fileRef = 8385D4E2245174C600FF8E67 /* diva.c */; };
|
||||
838BDB681D3AF70D0022CA6F /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB671D3AF70D0022CA6F /* libz.tbd */; };
|
||||
838BDB6A1D3AF7140022CA6F /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB691D3AF7140022CA6F /* libiconv.tbd */; };
|
||||
|
@ -949,7 +947,6 @@
|
|||
8349A8F01FE6257C00E26435 /* pc_ast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pc_ast.c; sourceTree = "<group>"; };
|
||||
8349A8F11FE6257D00E26435 /* sab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sab.c; sourceTree = "<group>"; };
|
||||
8349A8F21FE6257D00E26435 /* ps2_pcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_pcm.c; sourceTree = "<group>"; };
|
||||
8349A8F31FE6257D00E26435 /* sqex_scd_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqex_scd_streamfile.h; sourceTree = "<group>"; };
|
||||
8349A8F41FE6257D00E26435 /* ubi_sb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ubi_sb.c; sourceTree = "<group>"; };
|
||||
8349A8F51FE6257D00E26435 /* scd_pcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scd_pcm.c; sourceTree = "<group>"; };
|
||||
8349A8F61FE6257E00E26435 /* aix_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aix_streamfile.h; sourceTree = "<group>"; };
|
||||
|
@ -1060,7 +1057,6 @@
|
|||
836F6E2918BDC2180095E648 /* 2dx9.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = 2dx9.c; sourceTree = "<group>"; };
|
||||
836F6E2A18BDC2180095E648 /* aax.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aax.c; sourceTree = "<group>"; };
|
||||
836F6E2B18BDC2180095E648 /* acm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = acm.c; sourceTree = "<group>"; };
|
||||
836F6E2C18BDC2180095E648 /* ads.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ads.c; sourceTree = "<group>"; };
|
||||
836F6E2F18BDC2180095E648 /* agsc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = agsc.c; sourceTree = "<group>"; };
|
||||
836F6E3018BDC2180095E648 /* ahx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ahx.c; sourceTree = "<group>"; };
|
||||
836F6E3118BDC2180095E648 /* aifc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aifc.c; sourceTree = "<group>"; };
|
||||
|
@ -1127,7 +1123,6 @@
|
|||
836F6E7B18BDC2180095E648 /* ngc_ssm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_ssm.c; sourceTree = "<group>"; };
|
||||
836F6E7C18BDC2180095E648 /* ngc_tydsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_tydsp.c; sourceTree = "<group>"; };
|
||||
836F6E7E18BDC2180095E648 /* ngc_ymf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_ymf.c; sourceTree = "<group>"; };
|
||||
836F6E7F18BDC2180095E648 /* ngca.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngca.c; sourceTree = "<group>"; };
|
||||
836F6E8118BDC2180095E648 /* nwa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nwa.c; sourceTree = "<group>"; };
|
||||
836F6E8318BDC2180095E648 /* otm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = otm.c; sourceTree = "<group>"; };
|
||||
836F6E8418BDC2180095E648 /* p3d.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = p3d.c; sourceTree = "<group>"; };
|
||||
|
@ -1241,7 +1236,6 @@
|
|||
83709DFF1ECBC1A4005C03D3 /* gtd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gtd.c; sourceTree = "<group>"; };
|
||||
83709E001ECBC1A4005C03D3 /* mc3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mc3.c; sourceTree = "<group>"; };
|
||||
83709E011ECBC1A4005C03D3 /* mss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mss.c; sourceTree = "<group>"; };
|
||||
83709E021ECBC1A4005C03D3 /* ps2_rxws.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rxws.c; sourceTree = "<group>"; };
|
||||
83709E031ECBC1A4005C03D3 /* ta_aac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ta_aac.c; sourceTree = "<group>"; };
|
||||
83709E0B1ECBC1C3005C03D3 /* mc3_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mc3_decoder.c; sourceTree = "<group>"; };
|
||||
83709E0C1ECBC1C3005C03D3 /* psv_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = psv_decoder.c; sourceTree = "<group>"; };
|
||||
|
@ -1291,6 +1285,8 @@
|
|||
837CEAEF23487F2C00E62A4A /* jstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jstm.c; sourceTree = "<group>"; };
|
||||
837CEAF023487F2C00E62A4A /* sqex_sead_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqex_sead_streamfile.h; sourceTree = "<group>"; };
|
||||
837CEB062348809400E62A4A /* seb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = seb.c; sourceTree = "<group>"; };
|
||||
83852B092680247900378854 /* rxws.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rxws.c; sourceTree = "<group>"; };
|
||||
83852B0A2680247900378854 /* ads_midway.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ads_midway.c; sourceTree = "<group>"; };
|
||||
8385D4E2245174C600FF8E67 /* diva.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = diva.c; sourceTree = "<group>"; };
|
||||
838BDB671D3AF70D0022CA6F /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
838BDB691D3AF7140022CA6F /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; };
|
||||
|
@ -1772,7 +1768,7 @@
|
|||
83F2CCE125A5B41600F46FA8 /* acx.c */,
|
||||
83AA7F7A2519C042004C5298 /* adp_konami.c */,
|
||||
834FE0CF215C79E8000A5D3D /* adpcm_capcom.c */,
|
||||
836F6E2C18BDC2180095E648 /* ads.c */,
|
||||
83852B0A2680247900378854 /* ads_midway.c */,
|
||||
8349A9021FE6258100E26435 /* adx_keys.h */,
|
||||
831BA60E1EAC61A500CF89B0 /* adx.c */,
|
||||
8349A9001FE6258000E26435 /* afc.c */,
|
||||
|
@ -1965,7 +1961,6 @@
|
|||
836F6E7C18BDC2180095E648 /* ngc_tydsp.c */,
|
||||
831BD11F1EEE1CF200198540 /* ngc_ulw.c */,
|
||||
836F6E7E18BDC2180095E648 /* ngc_ymf.c */,
|
||||
836F6E7F18BDC2180095E648 /* ngca.c */,
|
||||
83C727FC22BC893900678B4A /* nps.c */,
|
||||
837CEAE223487F2A00E62A4A /* nub.c */,
|
||||
832BF81B21E0514B006F50F1 /* nus3audio.c */,
|
||||
|
@ -2028,7 +2023,6 @@
|
|||
836F6EB318BDC2180095E648 /* ps2_pnb.c */,
|
||||
836F6EB618BDC2180095E648 /* ps2_rnd.c */,
|
||||
836F6EB718BDC2180095E648 /* ps2_rstm.c */,
|
||||
83709E021ECBC1A4005C03D3 /* ps2_rxws.c */,
|
||||
836F6EBA18BDC2180095E648 /* ps2_sfs.c */,
|
||||
836F6EBB18BDC2180095E648 /* ps2_sl3.c */,
|
||||
836F6EBC18BDC2180095E648 /* ps2_smpl.c */,
|
||||
|
@ -2072,6 +2066,7 @@
|
|||
836F6EB818BDC2180095E648 /* rws.c */,
|
||||
836F6EE818BDC2190095E648 /* rwsd.c */,
|
||||
836F6EE918BDC2190095E648 /* rwx.c */,
|
||||
83852B092680247900378854 /* rxws.c */,
|
||||
836F6EEA18BDC2190095E648 /* s14_sss.c */,
|
||||
83AA7F772519C042004C5298 /* sab_streamfile.h */,
|
||||
8349A8F11FE6257D00E26435 /* sab.c */,
|
||||
|
@ -2101,7 +2096,6 @@
|
|||
83A21F82201D8981000F04B9 /* sps_n1.c */,
|
||||
836F6EF318BDC2190095E648 /* spt_spd.c */,
|
||||
834FE0D6215C79E9000A5D3D /* sqex_scd_sscf.c */,
|
||||
8349A8F31FE6257D00E26435 /* sqex_scd_streamfile.h */,
|
||||
836F6EF418BDC2190095E648 /* sqex_scd.c */,
|
||||
837CEAF023487F2C00E62A4A /* sqex_sead_streamfile.h */,
|
||||
83A21F84201D8981000F04B9 /* sqex_sead.c */,
|
||||
|
@ -2333,7 +2327,6 @@
|
|||
83031EDA243C510500C3F3E0 /* mul_streamfile.h in Headers */,
|
||||
83C7281822BC893D00678B4A /* sfh_streamfile.h in Headers */,
|
||||
834FE0EF215C79ED000A5D3D /* xvag_streamfile.h in Headers */,
|
||||
8349A90C1FE6258200E26435 /* sqex_scd_streamfile.h in Headers */,
|
||||
83031EC4243C50A800C3F3E0 /* circus_decoder_miniz.h in Headers */,
|
||||
8349A91B1FE6258200E26435 /* adx_keys.h in Headers */,
|
||||
836F6F4D18BDC2190095E648 /* layout.h in Headers */,
|
||||
|
@ -2601,7 +2594,6 @@
|
|||
83E7FD6525EF2B2400683FD2 /* tac.c in Sources */,
|
||||
83C7281322BC893D00678B4A /* mta2.c in Sources */,
|
||||
8306B0EF20984590000302D4 /* ubi_bao.c in Sources */,
|
||||
836F6FBB18BDC2190095E648 /* ngca.c in Sources */,
|
||||
83AF2CCA26226BA500538240 /* exst.c in Sources */,
|
||||
8306B0E220984590000302D4 /* smv.c in Sources */,
|
||||
8349A91E1FE6258200E26435 /* bar.c in Sources */,
|
||||
|
@ -2622,7 +2614,6 @@
|
|||
835C883622CC17BE001B4B3F /* bwav.c in Sources */,
|
||||
8349A90A1FE6258200E26435 /* sab.c in Sources */,
|
||||
83AF2CC926226BA500538240 /* gcub.c in Sources */,
|
||||
836F6F6818BDC2190095E648 /* ads.c in Sources */,
|
||||
8306B08620984518000302D4 /* fadpcm_decoder.c in Sources */,
|
||||
83AB8C761E8072A100086084 /* x360_ast.c in Sources */,
|
||||
834FE105215C79ED000A5D3D /* xmd.c in Sources */,
|
||||
|
@ -2738,6 +2729,7 @@
|
|||
837CEB0423487F2C00E62A4A /* jstm.c in Sources */,
|
||||
83C7282022BC893D00678B4A /* dcs_wav.c in Sources */,
|
||||
8306B0F220984590000302D4 /* ubi_jade.c in Sources */,
|
||||
83852B0C2680247900378854 /* ads_midway.c in Sources */,
|
||||
836F6FF918BDC2190095E648 /* ps2_snd.c in Sources */,
|
||||
836F6F2918BDC2190095E648 /* l5_555_decoder.c in Sources */,
|
||||
836F6FF318BDC2190095E648 /* ps2_rstm.c in Sources */,
|
||||
|
@ -2794,7 +2786,6 @@
|
|||
836F704418BDC2190095E648 /* ws_aud.c in Sources */,
|
||||
83031ED2243C50DF00C3F3E0 /* bkhd.c in Sources */,
|
||||
8373342F23F60D4100DE14DC /* tgc.c in Sources */,
|
||||
83709E081ECBC1A4005C03D3 /* ps2_rxws.c in Sources */,
|
||||
8373342823F60CDC00DE14DC /* fda.c in Sources */,
|
||||
836F6F6D18BDC2190095E648 /* aifc.c in Sources */,
|
||||
836F702218BDC2190095E648 /* rsd.c in Sources */,
|
||||
|
@ -2954,6 +2945,7 @@
|
|||
832BF82621E0514B006F50F1 /* nwav.c in Sources */,
|
||||
836F6F3018BDC2190095E648 /* nds_procyon_decoder.c in Sources */,
|
||||
8349A8E81FE6253900E26435 /* blocked_dec.c in Sources */,
|
||||
83852B0B2680247900378854 /* rxws.c in Sources */,
|
||||
831BA6181EAC61A500CF89B0 /* adx.c in Sources */,
|
||||
832BF82321E0514B006F50F1 /* imc.c in Sources */,
|
||||
836F6FB118BDC2190095E648 /* ngc_ffcc_str.c in Sources */,
|
||||
|
|
|
@ -90,7 +90,9 @@ void decode_ulaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing,
|
|||
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);
|
||||
int32_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
|
||||
int32_t pcm16_bytes_to_samples(size_t bytes, int channels);
|
||||
int32_t pcm8_bytes_to_samples(size_t bytes, int channels);
|
||||
|
||||
|
||||
/* psx_decoder */
|
||||
|
@ -159,7 +161,7 @@ STREAMFILE* nwa_get_streamfile(nwa_codec_data* data);
|
|||
#define MSADPCM_MAX_BLOCK_SIZE 0x800 /* known max and RIFF spec seems to concur, while MS's encoders may be lower (typical stereo: 0x8c, 0x2C, 0x48, 0x400) */
|
||||
|
||||
void decode_msadpcm_stereo(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_msadpcm_mono(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_msadpcm_mono(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int config);
|
||||
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);
|
||||
int msadpcm_check_coefs(STREAMFILE* sf, off_t offset);
|
||||
|
|
|
@ -22,14 +22,64 @@ static const int16_t msadpcm_coefs[7][2] = {
|
|||
{ 392, -232 }
|
||||
};
|
||||
|
||||
|
||||
/* Decodes MSADPCM as explained in the spec (RIFFNEW / msadpcm.c).
|
||||
* Though RIFFNEW spec uses "predictor / 256", msadpcm.c uses "predictor >> 8" = diffs on negs (silly MS).
|
||||
* SHR is also true in Windows msadp32.acm decoders (up to Win10), that seem to use same code.
|
||||
* Some non-Windows implementations or engines (like UE4) use DIV though (more accurate).
|
||||
/* Decodes MSADPCM as explained in the spec (RIFFNEW doc + msadpcm.c).
|
||||
* Though RIFFNEW writes "predictor / 256" (DIV), msadpcm.c uses "predictor >> 8" (SHR). They may seem the
|
||||
* same but on negative values SHR gets different results (-128 / 256 = 0; -128 >> 8 = -1) = some output diffs.
|
||||
* SHR is true in Windows msadp32.acm decoders (up to Win10), while some non-Windows implementations or
|
||||
* engines (like UE4) may use DIV.
|
||||
*
|
||||
* On invalid coef index, msadpcm.c returns 0 decoded samples but here we clamp and keep on trucking.
|
||||
* In theory blocks may be 0-padded and should use samples_per_frame from header, in practice seems to
|
||||
* decode up to block length or available data. */
|
||||
|
||||
static int16_t msadpcm_adpcm_expand_nibble_shr(VGMSTREAMCHANNEL* stream, uint8_t byte, int shift) {
|
||||
int32_t hist1, hist2, predicted;
|
||||
int code = (shift) ?
|
||||
get_high_nibble_signed(byte) :
|
||||
get_low_nibble_signed (byte);
|
||||
|
||||
hist1 = stream->adpcm_history1_16;
|
||||
hist2 = stream->adpcm_history2_16;
|
||||
predicted = hist1 * stream->adpcm_coef[0] + hist2 * stream->adpcm_coef[1];
|
||||
predicted = predicted >> 8; /* 256 = FIXED_POINT_COEF_BASE (uses SHR instead) */
|
||||
predicted = predicted + (code * stream->adpcm_scale);
|
||||
predicted = clamp16(predicted); /* lNewSample */
|
||||
|
||||
stream->adpcm_history2_16 = stream->adpcm_history1_16;
|
||||
stream->adpcm_history1_16 = predicted;
|
||||
|
||||
stream->adpcm_scale = (msadpcm_steps[code & 0xf] * stream->adpcm_scale) >> 8; /* not diffs vs DIV here (always >=0) */
|
||||
if (stream->adpcm_scale < 16) /* min delta */
|
||||
stream->adpcm_scale = 16;
|
||||
|
||||
return predicted;
|
||||
}
|
||||
|
||||
static int16_t msadpcm_adpcm_expand_nibble_div(VGMSTREAMCHANNEL* stream, uint8_t byte, int shift) {
|
||||
int32_t hist1, hist2, predicted;
|
||||
|
||||
int code = (shift) ?
|
||||
get_high_nibble_signed(byte) :
|
||||
get_low_nibble_signed (byte);
|
||||
|
||||
hist1 = stream->adpcm_history1_16;
|
||||
hist2 = stream->adpcm_history2_16;
|
||||
predicted = hist1 * stream->adpcm_coef[0] + hist2 * stream->adpcm_coef[1];
|
||||
predicted = predicted / 256; /* 256 = FIXED_POINT_COEF_BASE */
|
||||
predicted = predicted + (code * stream->adpcm_scale);
|
||||
predicted = clamp16(predicted); /* lNewSample */
|
||||
|
||||
stream->adpcm_history2_16 = stream->adpcm_history1_16;
|
||||
stream->adpcm_history1_16 = predicted;
|
||||
|
||||
stream->adpcm_scale = (msadpcm_steps[code & 0xf] * stream->adpcm_scale) / 256; /* 256 = FIXED_POINT_ADAPTION_BASE */
|
||||
if (stream->adpcm_scale < 16) /* min delta */
|
||||
stream->adpcm_scale = 16;
|
||||
|
||||
return predicted;
|
||||
}
|
||||
|
||||
|
||||
void decode_msadpcm_stereo(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t first_sample, int32_t samples_to_do) {
|
||||
VGMSTREAMCHANNEL *stream1, *stream2;
|
||||
uint8_t frame[MSADPCM_MAX_BLOCK_SIZE] = {0};
|
||||
|
@ -81,40 +131,20 @@ void decode_msadpcm_stereo(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t first
|
|||
|
||||
/* decode nibbles */
|
||||
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||
int ch;
|
||||
uint8_t byte = get_u8(frame+0x07*2+(i-2));
|
||||
|
||||
for (ch = 0; ch < 2; ch++) {
|
||||
VGMSTREAMCHANNEL* stream = &vgmstream->ch[ch];
|
||||
int32_t hist1, hist2, predicted;
|
||||
uint8_t byte = get_u8(frame+0x07*2+(i-2));
|
||||
int sample_nibble = (ch == 0) ? /* L = high nibble first (iErrorDelta) */
|
||||
get_high_nibble_signed(byte) :
|
||||
get_low_nibble_signed (byte);
|
||||
|
||||
hist1 = stream->adpcm_history1_16;
|
||||
hist2 = stream->adpcm_history2_16;
|
||||
predicted = hist1 * stream->adpcm_coef[0] + hist2 * stream->adpcm_coef[1];
|
||||
predicted = predicted / 256; /* 256 = FIXED_POINT_COEF_BASE (though MS code uses SHR) */
|
||||
predicted = predicted + (sample_nibble * stream->adpcm_scale);
|
||||
outbuf[0] = clamp16(predicted); /* lNewSample */
|
||||
|
||||
stream->adpcm_history2_16 = stream->adpcm_history1_16;
|
||||
stream->adpcm_history1_16 = outbuf[0];
|
||||
stream->adpcm_scale = (msadpcm_steps[sample_nibble & 0xf] * stream->adpcm_scale) / 256; /* 256 = FIXED_POINT_ADAPTION_BASE */
|
||||
if (stream->adpcm_scale < 16) /* min delta */
|
||||
stream->adpcm_scale = 16;
|
||||
|
||||
outbuf++;
|
||||
}
|
||||
*outbuf++ = msadpcm_adpcm_expand_nibble_shr(&vgmstream->ch[0], byte, 1); /* L */
|
||||
*outbuf++ = msadpcm_adpcm_expand_nibble_shr(&vgmstream->ch[1], byte, 0); /* R */
|
||||
}
|
||||
}
|
||||
|
||||
void decode_msadpcm_mono(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_msadpcm_mono(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int config) {
|
||||
VGMSTREAMCHANNEL* stream = &vgmstream->ch[channel];
|
||||
uint8_t frame[MSADPCM_MAX_BLOCK_SIZE] = {0};
|
||||
int i, frames_in;
|
||||
size_t bytes_per_frame, samples_per_frame;
|
||||
off_t frame_offset;
|
||||
int is_shr = (config == 0);
|
||||
|
||||
/* external interleave (variable size), mono */
|
||||
bytes_per_frame = vgmstream->frame_size;
|
||||
|
@ -150,25 +180,12 @@ void decode_msadpcm_mono(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspac
|
|||
|
||||
/* decode nibbles */
|
||||
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||
int32_t hist1, hist2, predicted;
|
||||
uint8_t byte = get_u8(frame+0x07+(i-2)/2);
|
||||
int sample_nibble = (i & 1) ? /* high nibble first */
|
||||
get_low_nibble_signed (byte) :
|
||||
get_high_nibble_signed(byte);
|
||||
|
||||
hist1 = stream->adpcm_history1_16;
|
||||
hist2 = stream->adpcm_history2_16;
|
||||
predicted = hist1 * stream->adpcm_coef[0] + hist2 * stream->adpcm_coef[1];
|
||||
predicted = predicted / 256;
|
||||
predicted = predicted + (sample_nibble * stream->adpcm_scale);
|
||||
outbuf[0] = clamp16(predicted);
|
||||
|
||||
stream->adpcm_history2_16 = stream->adpcm_history1_16;
|
||||
stream->adpcm_history1_16 = outbuf[0];
|
||||
stream->adpcm_scale = (msadpcm_steps[sample_nibble & 0xf] * stream->adpcm_scale) / 256;
|
||||
if (stream->adpcm_scale < 16) /* min delta */
|
||||
stream->adpcm_scale = 16;
|
||||
int shift = !(i & 1); /* high nibble first */
|
||||
|
||||
outbuf[0] = is_shr ?
|
||||
msadpcm_adpcm_expand_nibble_shr(stream, byte, shift) :
|
||||
msadpcm_adpcm_expand_nibble_div(stream, byte, shift);
|
||||
outbuf += channelspacing;
|
||||
}
|
||||
}
|
||||
|
@ -215,26 +232,11 @@ void decode_msadpcm_ck(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacin
|
|||
}
|
||||
|
||||
/* decode nibbles */
|
||||
for (i = first_sample; i < first_sample+samples_to_do; i++) {
|
||||
int32_t hist1,hist2, predicted;
|
||||
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||
uint8_t byte = get_u8(frame+0x07+(i-2)/2);
|
||||
int sample_nibble = (i & 1) ? /* low nibble first, unlike normal MSADPCM */
|
||||
get_high_nibble_signed(byte) :
|
||||
get_low_nibble_signed (byte);
|
||||
|
||||
hist1 = stream->adpcm_history1_16;
|
||||
hist2 = stream->adpcm_history2_16;
|
||||
predicted = hist1 * stream->adpcm_coef[0] + hist2 *stream->adpcm_coef[1];
|
||||
predicted = predicted >> 8; /* not DIV unlike spec */
|
||||
predicted = predicted + (sample_nibble * stream->adpcm_scale);
|
||||
outbuf[0] = clamp16(predicted);
|
||||
|
||||
stream->adpcm_history2_16 = stream->adpcm_history1_16;
|
||||
stream->adpcm_history1_16 = outbuf[0];
|
||||
stream->adpcm_scale = (msadpcm_steps[sample_nibble & 0xf] * stream->adpcm_scale) >> 8; /* not DIV but same here (always >=0) */
|
||||
if (stream->adpcm_scale < 16)
|
||||
stream->adpcm_scale = 16;
|
||||
int shift = (i & 1); /* low nibble first, unlike normal MSADPCM */
|
||||
|
||||
outbuf[0] = msadpcm_adpcm_expand_nibble_shr(stream, byte, shift);
|
||||
outbuf += channelspacing;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,7 +216,15 @@ void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelsp
|
|||
}
|
||||
}
|
||||
|
||||
size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample) {
|
||||
int32_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample) {
|
||||
if (channels <= 0 || bits_per_sample <= 0) return 0;
|
||||
return ((int64_t)bytes * 8) / channels / bits_per_sample;
|
||||
}
|
||||
|
||||
int32_t pcm16_bytes_to_samples(size_t bytes, int channels) {
|
||||
return pcm_bytes_to_samples(bytes, channels, 16);
|
||||
}
|
||||
|
||||
int32_t pcm8_bytes_to_samples(size_t bytes, int channels) {
|
||||
return pcm_bytes_to_samples(bytes, channels, 8);
|
||||
}
|
||||
|
|
|
@ -358,7 +358,7 @@ size_t ps_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_s
|
|||
size_t interleave_consumed = 0;
|
||||
|
||||
|
||||
if (data_size == 0 || channels == 0 || (channels > 0 && interleave == 0))
|
||||
if (data_size == 0 || channels == 0 || (channels > 1 && interleave == 0))
|
||||
return 0;
|
||||
|
||||
offset = start_offset + data_size;
|
||||
|
@ -405,7 +405,7 @@ size_t ps_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_s
|
|||
interleave_consumed += 0x10;
|
||||
if (interleave_consumed == interleave) {
|
||||
interleave_consumed = 0;
|
||||
offset -= interleave*(channels - 1);
|
||||
offset -= interleave * (channels - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1290,7 +1290,8 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
|
|||
if (vgmstream->channels == 1 || vgmstream->coding_type == coding_MSADPCM_int) {
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_msadpcm_mono(vgmstream,buffer+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block, samples_to_do, ch);
|
||||
vgmstream->channels,vgmstream->samples_into_block, samples_to_do, ch,
|
||||
vgmstream->codec_config);
|
||||
}
|
||||
}
|
||||
else if (vgmstream->channels == 2) {
|
||||
|
|
|
@ -311,7 +311,7 @@ static const char* extension_list[] = {
|
|||
"mdsp",
|
||||
"med",
|
||||
"mjb",
|
||||
"mi4",
|
||||
"mi4", //fake extension for .mib (renamed, to be removed)
|
||||
"mib",
|
||||
"mic",
|
||||
"mihb",
|
||||
|
@ -353,7 +353,6 @@ static const char* extension_list[] = {
|
|||
"naac",
|
||||
"nds",
|
||||
"ndp", //fake extension/header id for .nds
|
||||
"ngca",
|
||||
"nlsd",
|
||||
"nop",
|
||||
"nps",
|
||||
|
@ -581,7 +580,6 @@ static const char* extension_list[] = {
|
|||
"wii",
|
||||
"wip", //txth/reserved [Colin McRae DiRT (PC)]
|
||||
"wlv", //txth/reserved [ToeJam & Earl III: Mission to Earth (DC)]
|
||||
"wma", //common
|
||||
"wmus",
|
||||
"wp2",
|
||||
"wpd",
|
||||
|
@ -658,6 +656,7 @@ static const char* common_extension_list[] = {
|
|||
"ogg", //common
|
||||
"opus", //common
|
||||
"wav", //common
|
||||
"wma", //common
|
||||
};
|
||||
|
||||
|
||||
|
@ -921,7 +920,7 @@ static const meta_info meta_info_list[] = {
|
|||
{meta_DSP_STD, "Nintendo DSP header"},
|
||||
{meta_DSP_CSTR, "Namco Cstr header"},
|
||||
{meta_GCSW, "MileStone GCSW header"},
|
||||
{meta_PS2_SShd, "Sony ADS header"},
|
||||
{meta_ADS, "Sony ADS header"},
|
||||
{meta_NPS, "Namco NPSF header"},
|
||||
{meta_RWSD, "Nintendo RWSD header (single stream)"},
|
||||
{meta_RWAR, "Nintendo RWAR header (single RWAV stream)"},
|
||||
|
@ -929,7 +928,7 @@ static const meta_info meta_info_list[] = {
|
|||
{meta_CWAV, "Nintendo CWAV header"},
|
||||
{meta_FWAV, "Nintendo FWAV header"},
|
||||
{meta_XA, "Sony XA header"},
|
||||
{meta_PS2_RXWS, "Sony RXWS header"},
|
||||
{meta_RXWS, "Sony RXWS header"},
|
||||
{meta_RAW_INT, "PS2 .int raw header"},
|
||||
{meta_PS2_OMU, "Alter Echo OMU Header"},
|
||||
{meta_DSP_STM, "Intelligent Systems STM header"},
|
||||
|
@ -1080,7 +1079,7 @@ static const meta_info meta_info_list[] = {
|
|||
{meta_PS2_TK5, "Tekken 5 Stream Header"},
|
||||
{meta_PS2_SND, "Might and Magic SSND Header"},
|
||||
{meta_PS2_VSF_TTA, "VSF with SMSS Header"},
|
||||
{meta_ADS, "dhSS Header"},
|
||||
{meta_ADS_MIDWAY, "Midway ADS header"},
|
||||
{meta_PS2_MCG, "Gunvari MCG Header"},
|
||||
{meta_ZSD, "ZSD Header"},
|
||||
{meta_REDSPARK, "RedSpark Header"},
|
||||
|
@ -1151,7 +1150,6 @@ static const meta_info meta_info_list[] = {
|
|||
{meta_MSF, "Sony MSF header"},
|
||||
{meta_PS3_PAST, "SNDP header"},
|
||||
{meta_SGXD, "Sony SGXD header"},
|
||||
{meta_NGCA, "NGCA header"},
|
||||
{meta_WII_RAS, "RAS header"},
|
||||
{meta_PS2_SPM, "SPM header"},
|
||||
{meta_X360_TRA, "Terminal Reality .TRA raw header"},
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void block_update_thp(off_t block_offset, VGMSTREAM *vgmstream) {
|
||||
void block_update_thp(off_t block_offset, VGMSTREAM* vgmstream) {
|
||||
int i, j;
|
||||
STREAMFILE *streamFile = vgmstream->ch[0].streamfile;
|
||||
STREAMFILE* sf = vgmstream->ch[0].streamfile;
|
||||
off_t audio_offset;
|
||||
size_t next_block_size, video_size;
|
||||
|
||||
next_block_size = read_32bitBE(block_offset + 0x00, streamFile);
|
||||
next_block_size = read_u32be(block_offset + 0x00, sf);
|
||||
/* 0x04: frame size previous */
|
||||
video_size = read_32bitBE(block_offset + 0x08,streamFile);
|
||||
video_size = read_u32be(block_offset + 0x08,sf);
|
||||
/* 0x0c: audio size */
|
||||
|
||||
audio_offset = block_offset + 0x10 + video_size;
|
||||
|
@ -21,21 +21,21 @@ void block_update_thp(off_t block_offset, VGMSTREAM *vgmstream) {
|
|||
|
||||
/* block samples can be smaller than block size, normally in the last block,
|
||||
* but num_samples already takes that into account, so there is no real difference */
|
||||
vgmstream->current_block_size = read_32bitBE(audio_offset + 0x00, streamFile);
|
||||
vgmstream->current_block_samples = read_32bitBE(audio_offset + 0x04, streamFile);
|
||||
vgmstream->current_block_size = read_u32be(audio_offset + 0x00, sf);
|
||||
vgmstream->current_block_samples = read_u32be(audio_offset + 0x04, sf);
|
||||
|
||||
audio_offset += 0x08;
|
||||
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
off_t coef_offset = audio_offset + i*0x20;
|
||||
off_t hist_offset = audio_offset + vgmstream->channels*0x20 + i*0x04;
|
||||
off_t data_offset = audio_offset + vgmstream->channels*0x24 + i*vgmstream->current_block_size;
|
||||
off_t data_offset = audio_offset + 2*0x24 + i*vgmstream->current_block_size; /* reserved for 2 even in mono [WarioWare Inc. (GC)] */
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
vgmstream->ch[i].adpcm_coef[j] = read_16bitBE(coef_offset + (j*0x02),streamFile);
|
||||
vgmstream->ch[i].adpcm_coef[j] = read_s16be(coef_offset + (j*0x02),sf);
|
||||
}
|
||||
vgmstream->ch[i].adpcm_history1_16 = read_16bitBE(hist_offset + 0x00,streamFile);
|
||||
vgmstream->ch[i].adpcm_history2_16 = read_16bitBE(hist_offset + 0x02,streamFile);
|
||||
vgmstream->ch[i].adpcm_history1_16 = read_s16be(hist_offset + 0x00,sf);
|
||||
vgmstream->ch[i].adpcm_history2_16 = read_s16be(hist_offset + 0x02,sf);
|
||||
vgmstream->ch[i].offset = data_offset;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ VGMSTREAM * init_vgmstream_cstr(STREAMFILE* sf) {
|
|||
loop_flag = (loop_start >= 0);
|
||||
start_offset = 0x20 + 0x60 * channels + first_skip;
|
||||
|
||||
#if 1
|
||||
/* nonlooped tracks may not set first skip for no reason, but can be tested with initial p/s */
|
||||
if (!loop_flag && channels == 2 && first_skip == 0) {
|
||||
while (first_skip < 0x800) {
|
||||
|
@ -61,7 +60,7 @@ VGMSTREAM * init_vgmstream_cstr(STREAMFILE* sf) {
|
|||
}
|
||||
if (first_skip > 0 && loop_start >= (interleave - first_skip))
|
||||
loop_start = loop_start - (interleave - first_skip);
|
||||
#endif
|
||||
|
||||
loop_start = loop_start * 2;
|
||||
|
||||
/* Mr. Driller oddity, unreliable loop flag */
|
||||
|
@ -97,7 +96,7 @@ VGMSTREAM * init_vgmstream_cstr(STREAMFILE* sf) {
|
|||
vgmstream->interleave_first_block_size = interleave - first_skip;
|
||||
vgmstream->interleave_first_skip = first_skip;
|
||||
vgmstream->meta_type = meta_DSP_CSTR;
|
||||
VGM_LOG("1=%x, =%x\n",vgmstream->interleave_first_block_size, vgmstream->interleave_first_skip);
|
||||
|
||||
dsp_read_coefs_be(vgmstream, sf, 0x3c, 0x60);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
|
|
|
@ -132,6 +132,7 @@ typedef struct {
|
|||
/* config */
|
||||
int is_memory;
|
||||
int target_waveid;
|
||||
int target_port;
|
||||
int has_TrackEventTable;
|
||||
int has_CommandTable;
|
||||
|
||||
|
@ -221,7 +222,7 @@ static void add_acb_name(acb_header* acb, int8_t Streaming) {
|
|||
/* OBJECT HANDLERS */
|
||||
|
||||
static int load_acb_waveform(acb_header* acb, int16_t Index) {
|
||||
uint16_t Id;
|
||||
uint16_t Id, PortNo;
|
||||
uint8_t Streaming;
|
||||
|
||||
/* read Waveform[Index] */
|
||||
|
@ -231,18 +232,30 @@ static int load_acb_waveform(acb_header* acb, int16_t Index) {
|
|||
if (acb->is_memory) {
|
||||
if (!utf_query_u16(acb->WaveformTable, Index, "MemoryAwbId", &Id))
|
||||
goto fail;
|
||||
PortNo = 0xFFFF;
|
||||
} else {
|
||||
if (!utf_query_u16(acb->WaveformTable, Index, "StreamAwbId", &Id))
|
||||
goto fail;
|
||||
if (!utf_query_u16(acb->WaveformTable, Index, "StreamAwbPortNo", &PortNo))
|
||||
PortNo = 0; /* assumed */
|
||||
}
|
||||
}
|
||||
else {
|
||||
PortNo = 0xFFFF;
|
||||
}
|
||||
|
||||
if (!utf_query_u8(acb->WaveformTable, Index, "Streaming", &Streaming))
|
||||
goto fail;
|
||||
//;VGM_LOG("ACB: Waveform[%i]: Id=%i, Streaming=%i\n", Index, Id, Streaming);
|
||||
//;VGM_LOG("ACB: Waveform[%i]: Id=%i, PortNo=%i, Streaming=%i\n", Index, Id, PortNo, Streaming);
|
||||
|
||||
/* not found but valid */
|
||||
if (Id != acb->target_waveid)
|
||||
return 1;
|
||||
|
||||
/* correct AWB port (check ignored if set to -1) */
|
||||
if (acb->target_port >= 0 && PortNo != 0xFFFF && PortNo != acb->target_port)
|
||||
return 1;
|
||||
|
||||
/* must match our target's (0=memory, 1=streaming, 2=memory (prefetch)+stream) */
|
||||
if ((acb->is_memory && Streaming == 1) || (!acb->is_memory && Streaming == 0))
|
||||
return 1;
|
||||
|
@ -694,7 +707,7 @@ fail:
|
|||
}
|
||||
|
||||
|
||||
void load_acb_wave_name(STREAMFILE* sf, VGMSTREAM* vgmstream, int waveid, int is_memory) {
|
||||
void load_acb_wave_name(STREAMFILE* sf, VGMSTREAM* vgmstream, int waveid, int port, int is_memory) {
|
||||
acb_header acb = {0};
|
||||
int i, CueName_rows;
|
||||
|
||||
|
@ -722,9 +735,12 @@ void load_acb_wave_name(STREAMFILE* sf, VGMSTREAM* vgmstream, int waveid, int is
|
|||
* Atom Craft may only target certain .acb versions so some links are later removed
|
||||
* Not all cues to point to Waveforms, some are just config events/commands.
|
||||
* .acb link to .awb by name (loaded manually), though they have a checksum/hash/header to validate.
|
||||
*
|
||||
* .acb can contain info for multiple .awb, that are loaded sequentially and assigned "port numbers" (0 to N).
|
||||
* Both Wave ID and port number must be passed externally to find appropriate song name.
|
||||
*/
|
||||
|
||||
//;VGM_LOG("ACB: find waveid=%i\n", waveid);
|
||||
//;VGM_LOG("ACB: find waveid=%i, port=%i\n", waveid, port);
|
||||
|
||||
acb.acbFile = sf;
|
||||
|
||||
|
@ -732,6 +748,7 @@ void load_acb_wave_name(STREAMFILE* sf, VGMSTREAM* vgmstream, int waveid, int is
|
|||
if (!acb.Header) goto fail;
|
||||
|
||||
acb.target_waveid = waveid;
|
||||
acb.target_port = port;
|
||||
acb.is_memory = is_memory;
|
||||
acb.has_TrackEventTable = utf_query_data(acb.Header, 0, "TrackEventTable", NULL,NULL);
|
||||
acb.has_CommandTable = utf_query_data(acb.Header, 0, "CommandTable", NULL,NULL);
|
||||
|
|
|
@ -1,78 +1,80 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* ADS - from Gauntlet Dark Legacy (GC/Xbox) */
|
||||
VGMSTREAM * init_vgmstream_ads(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count, codec;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if (!check_extensions(streamFile,"ads")) goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) != 0x64685353) /* "dhSS" */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x20,streamFile) != 0x64625353) /* "dbSS" */
|
||||
goto fail;
|
||||
|
||||
loop_flag = 1;
|
||||
channel_count = read_32bitBE(0x10,streamFile);
|
||||
|
||||
if (channel_count > 2)
|
||||
goto fail;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitBE(0x0c,streamFile);
|
||||
|
||||
codec = read_32bitBE(0x08,streamFile);
|
||||
switch (codec) {
|
||||
case 0x00000020: /* GC */
|
||||
start_offset = 0x28 + 0x60 * channel_count;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->num_samples = read_32bitBE(0x28,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
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(0x14,streamFile);
|
||||
}
|
||||
|
||||
dsp_read_coefs_be(vgmstream, streamFile, 0x44,0x60);
|
||||
break;
|
||||
|
||||
case 0x00000021: /* Xbox */
|
||||
start_offset = 0x28;
|
||||
vgmstream->coding_type = coding_XBOX_IMA_int;
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bitBE(0x24,streamFile), vgmstream->channels);
|
||||
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x24;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_ADS;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .ADS - from Gauntlet Dark Legacy (GC/Xbox) */
|
||||
VGMSTREAM* init_vgmstream_ads_midway(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channels, codec;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf,"ads"))
|
||||
goto fail;
|
||||
|
||||
/* fake PS2 .ads but BE */
|
||||
if (!is_id32be(0x00,sf, "dhSS"))
|
||||
goto fail;
|
||||
if (!is_id32be(0x20,sf, "dbSS"))
|
||||
goto fail;
|
||||
|
||||
loop_flag = 1;
|
||||
channels = read_32bitBE(0x10,sf);
|
||||
if (channels > 2)
|
||||
goto fail;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitBE(0x0c,sf);
|
||||
|
||||
codec = read_32bitBE(0x08,sf);
|
||||
switch (codec) {
|
||||
case 0x00000020: /* GC */
|
||||
start_offset = 0x28 + 0x60 * channels;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->num_samples = read_32bitBE(0x28,sf);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
if (channels == 1) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else if (channels == 2) {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitBE(0x14,sf);
|
||||
}
|
||||
|
||||
dsp_read_coefs_be(vgmstream, sf, 0x44,0x60);
|
||||
break;
|
||||
|
||||
case 0x00000021: /* Xbox */
|
||||
start_offset = 0x28;
|
||||
vgmstream->coding_type = coding_XBOX_IMA_int;
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bitBE(0x24,sf), vgmstream->channels);
|
||||
vgmstream->layout_type = channels == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x24;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_ADS_MIDWAY;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -190,6 +190,7 @@ fail:
|
|||
|
||||
static void load_awb_name(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstream, int waveid) {
|
||||
int is_memory = (sf_acb != NULL);
|
||||
int port = 0;
|
||||
|
||||
/* .acb is passed when loading memory .awb inside .acb */
|
||||
if (!is_memory) {
|
||||
|
@ -198,7 +199,7 @@ static void load_awb_name(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstre
|
|||
int len_name, len_cmp;
|
||||
|
||||
/* try parsing TXTM if present */
|
||||
sf_acb = read_filemap_file(sf, 0);
|
||||
sf_acb = read_filemap_file_pos(sf, 0, &port);
|
||||
|
||||
/* try (name).awb + (name).awb */
|
||||
if (!sf_acb) {
|
||||
|
@ -233,27 +234,12 @@ static void load_awb_name(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstre
|
|||
}
|
||||
}
|
||||
|
||||
/* try (name)_(name)_R001.awb + (name).acb [Sengoku Basara Battle Party (Mobile)] */
|
||||
if (!sf_acb) {
|
||||
char *cmp = "_R001";
|
||||
get_streamfile_basename(sf, filename, sizeof(filename));
|
||||
len_name = strlen(filename);
|
||||
len_cmp = strlen(cmp);
|
||||
|
||||
if (len_name > len_cmp && strcmp(filename + len_name - len_cmp, cmp) == 0) {
|
||||
filename[(len_name - len_cmp) / 2] = '\0';
|
||||
strcat(filename, ".acb");
|
||||
VGM_LOG("%s\n", filename);
|
||||
sf_acb = open_streamfile_by_filename(sf, filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* probably loaded */
|
||||
load_acb_wave_name(sf_acb, vgmstream, waveid, is_memory);
|
||||
load_acb_wave_name(sf_acb, vgmstream, waveid, port, is_memory);
|
||||
|
||||
close_streamfile(sf_acb);
|
||||
}
|
||||
else {
|
||||
load_acb_wave_name(sf_acb, vgmstream, waveid, is_memory);
|
||||
load_acb_wave_name(sf_acb, vgmstream, waveid, port, is_memory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -222,6 +222,7 @@ fail:
|
|||
|
||||
static void load_cpk_name(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstream, int waveid) {
|
||||
int is_memory = (sf_acb != NULL);
|
||||
int port = -1; /* cpk has no port numbers */
|
||||
|
||||
/* .acb is passed when loading memory .awb inside .acb */
|
||||
if (!is_memory) {
|
||||
|
@ -238,11 +239,11 @@ static void load_cpk_name(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstre
|
|||
return;
|
||||
|
||||
/* companion .acb probably loaded */
|
||||
load_acb_wave_name(sf_acb, vgmstream, waveid, is_memory);
|
||||
load_acb_wave_name(sf_acb, vgmstream, waveid, port, is_memory);
|
||||
|
||||
close_streamfile(sf_acb);
|
||||
}
|
||||
else {
|
||||
load_acb_wave_name(sf_acb, vgmstream, waveid, is_memory);
|
||||
load_acb_wave_name(sf_acb, vgmstream, waveid, port, is_memory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,55 +1,55 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* CSMP - Retro Studios sample [Metroid Prime 3 (Wii), Donkey Kong Country Returns (Wii)] */
|
||||
VGMSTREAM * init_vgmstream_csmp(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, first_offset = 0x08, chunk_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "csmp"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00, streamFile) != 0x43534D50) /* "CSMP" */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x04, streamFile) != 1) /* version? */
|
||||
goto fail;
|
||||
|
||||
if (!find_chunk(streamFile, 0x44415441,first_offset,0, &chunk_offset,NULL, 1, 0)) /*"DATA"*/
|
||||
goto fail;
|
||||
|
||||
/* contains standard DSP header, but somehow some validations (start/loop ps)
|
||||
* don't seem to work, so no point to handle as standard DSP */
|
||||
|
||||
channel_count = 1;
|
||||
loop_flag = read_16bitBE(chunk_offset+0x0c,streamFile);
|
||||
start_offset = chunk_offset + 0x60;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_CSMP;
|
||||
vgmstream->sample_rate = read_32bitBE(chunk_offset+0x08,streamFile);
|
||||
vgmstream->num_samples = read_32bitBE(chunk_offset+0x00,streamFile);
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bitBE(chunk_offset+0x10,streamFile));
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(read_32bitBE(chunk_offset+0x14,streamFile))+1;
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_none;
|
||||
dsp_read_coefs_be(vgmstream, streamFile, chunk_offset+0x1c, 0x00);
|
||||
dsp_read_hist_be(vgmstream, streamFile, chunk_offset+0x40, 0x00);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* CSMP - Retro Studios sample [Metroid Prime 3 (Wii), Donkey Kong Country Returns (Wii)] */
|
||||
VGMSTREAM* init_vgmstream_csmp(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset, first_offset = 0x08, chunk_offset;
|
||||
int loop_flag, channels;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "csmp"))
|
||||
goto fail;
|
||||
if (!is_id32be(0x00, sf, "CSMP"))
|
||||
goto fail;
|
||||
if (read_u32be(0x04, sf) != 1)
|
||||
goto fail;
|
||||
|
||||
if (!find_chunk(sf, 0x44415441,first_offset,0, &chunk_offset,NULL, 1, 0)) /*"DATA"*/
|
||||
goto fail;
|
||||
|
||||
/* contains standard DSP header, but somehow some validations (start/loop ps)
|
||||
* don't seem to work, so no point to handle as standard DSP */
|
||||
|
||||
channels = 1;
|
||||
loop_flag = read_s16be(chunk_offset+0x0c,sf);
|
||||
start_offset = chunk_offset + 0x60;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_CSMP;
|
||||
vgmstream->sample_rate = read_s32be(chunk_offset+0x08,sf);
|
||||
vgmstream->num_samples = read_s32be(chunk_offset+0x00,sf);
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_u32be(chunk_offset+0x10,sf));
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(read_u32be(chunk_offset+0x14,sf)) + 1;
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_none;
|
||||
dsp_read_coefs_be(vgmstream, sf, chunk_offset+0x1c, 0x00);
|
||||
dsp_read_hist_be(vgmstream, sf, chunk_offset+0x40, 0x00);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,10 @@ VGMSTREAM* init_vgmstream_ffmpeg(STREAMFILE* sf) {
|
|||
if (get_streamfile_size(sf) <= 0x1000)
|
||||
goto fail;
|
||||
|
||||
/* reject some formats handled elsewhere (better fail and check there than let buggy FFmpeg take over) */
|
||||
if (check_extensions(sf, "at3"))
|
||||
goto fail;
|
||||
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
|
||||
/* init ffmpeg */
|
||||
|
|
|
@ -53,7 +53,7 @@ VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) {
|
|||
* This accepts ktsl2asbin with internal data, or opening external streams as subsongs.
|
||||
* Some info from KTSR.bt */
|
||||
|
||||
if (read_u32be(0x00, sf) != 0x4B545352) /* "KTSR" */
|
||||
if (!is_id32be(0x00, sf, "KTSR"))
|
||||
goto fail;
|
||||
if (read_u32be(0x04, sf) != 0x777B481A) /* hash(?) id: 0x777B481A=as, 0x0294DDFC=st, 0xC638E69E=gc */
|
||||
goto fail;
|
||||
|
@ -482,6 +482,7 @@ static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) {
|
|||
case 0xBD888C36: /* config (floats, stream id, etc, may have extended name) */
|
||||
case 0xC9C48EC1: /* unknown (has some string inside like "boss") */
|
||||
case 0xA9D23BF1: /* "state container", some kind of config/floats, witgh names like 'State_bgm01'..N */
|
||||
case 0x836FBECA: /* unknown (~0x300, encrypted? table + data) */
|
||||
break;
|
||||
|
||||
case 0xC5CCCB70: /* sound (internal data or external stream) */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
typedef enum { PCM16, MSADPCM, DSP_HEAD, DSP_BODY, AT9, MSF } kwb_codec;
|
||||
typedef enum { PCM16, MSADPCM, DSP_HEAD, DSP_BODY, AT9, MSF, XMA2 } kwb_codec;
|
||||
|
||||
typedef struct {
|
||||
int big_endian;
|
||||
|
@ -187,6 +187,27 @@ static VGMSTREAM* init_vgmstream_koei_wavebank(kwb_header* kwb, STREAMFILE* sf_h
|
|||
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case XMA2: {
|
||||
uint8_t buf[0x100];
|
||||
size_t bytes, block_size, block_count;
|
||||
|
||||
if (kwb->channels > 1) goto fail;
|
||||
|
||||
block_size = 0x800; /* ? */
|
||||
block_count = kwb->stream_size / block_size;
|
||||
|
||||
bytes = ffmpeg_make_riff_xma2(buf, sizeof(buf), vgmstream->num_samples, kwb->stream_size, kwb->channels, kwb->sample_rate, block_count, block_size);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(sf_b, buf,bytes, kwb->stream_offset, kwb->stream_size);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
xma_fix_raw_samples(vgmstream, sf_b, kwb->stream_offset, kwb->stream_size, 0, 0,0); /* assumed */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VGM_USE_ATRAC9
|
||||
case AT9: {
|
||||
atrac9_config cfg = {0};
|
||||
|
@ -357,7 +378,7 @@ static int parse_type_k4hd(kwb_header* kwb, off_t offset, off_t body_offset, STR
|
|||
ppva_offset += offset;
|
||||
|
||||
/* PPVA table: */
|
||||
if (read_u32be(ppva_offset + 0x00, sf_h) != 0x50505641) /* "PPVA" */
|
||||
if (!is_id32be(ppva_offset + 0x00, sf_h, "PPVA"))
|
||||
goto fail;
|
||||
|
||||
entry_size = read_u32le(ppva_offset + 0x08, sf_h);
|
||||
|
@ -403,8 +424,57 @@ fail:
|
|||
}
|
||||
|
||||
static int parse_type_sdsd(kwb_header* kwb, off_t offset, off_t body_offset, STREAMFILE* sf_h) {
|
||||
/* has Vers, Head, Prog, Smpl sections (like Sony VABs)
|
||||
unknown codec, blocked with some common start, variable sized */
|
||||
off_t smpl_offset, header_offset;
|
||||
int entries, current_subsongs, relative_subsong;
|
||||
size_t entry_size;
|
||||
|
||||
|
||||
/* format somewhat similar to Sony VABs */
|
||||
/* 00: SDsdVers */
|
||||
/* 08: chunk size */
|
||||
/* 0c: null */
|
||||
/* 10: SDsdHead */
|
||||
/* 18: chunk size */
|
||||
/* 1c: ? size */
|
||||
/* 20: null */
|
||||
/* 24: SDsdProg offset ('program'? cues?) */
|
||||
/* 28: SDsdSmpl offset ('samples'? waves?) */
|
||||
/* rest: ? */
|
||||
smpl_offset = read_u32le(offset + 0x28, sf_h);
|
||||
smpl_offset += offset;
|
||||
|
||||
/* Smpl table: */
|
||||
if (!is_id64be(smpl_offset + 0x00, sf_h, "SDsdSmpl"))
|
||||
goto fail;
|
||||
|
||||
/* 0x08: ? */
|
||||
entries = read_u32le(smpl_offset + 0x0c, sf_h);
|
||||
entry_size = 0x9c;
|
||||
|
||||
current_subsongs = kwb->total_subsongs;
|
||||
kwb->total_subsongs += entries;
|
||||
if (kwb->target_subsong - 1 < current_subsongs || kwb->target_subsong > kwb->total_subsongs)
|
||||
return 1;
|
||||
kwb->found = 1;
|
||||
|
||||
relative_subsong = kwb->target_subsong - current_subsongs;
|
||||
header_offset = smpl_offset + 0x10 + (relative_subsong-1) * entry_size;
|
||||
|
||||
kwb->stream_offset = read_u32le(header_offset + 0x00, sf_h);
|
||||
/* 08: ? + channels? */
|
||||
/* 0c: bps? */
|
||||
kwb->sample_rate = read_u32le(header_offset + 0x0c, sf_h);
|
||||
kwb->num_samples = read_u32le(header_offset + 0x10, sf_h) / sizeof(int16_t); /* PCM */
|
||||
/* rest: ? (flags, etc) */
|
||||
kwb->stream_size = read_u32le(header_offset + 0x44, sf_h);
|
||||
|
||||
kwb->codec = XMA2;
|
||||
kwb->channels = 1;
|
||||
|
||||
kwb->stream_offset += body_offset;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -429,8 +499,7 @@ static int parse_type_sdwi(kwb_header* kwb, off_t offset, off_t body_offset, STR
|
|||
smpl_offset += offset;
|
||||
|
||||
/* Smpl table: */
|
||||
if (read_u32be(smpl_offset + 0x00, sf_h) != 0x53447364 && /* "SDsd" */
|
||||
read_u32be(smpl_offset + 0x04, sf_h) != 0x536D706C) /* "Smpl" */
|
||||
if (!is_id64be(smpl_offset + 0x00, sf_h, "SDsdSmpl"))
|
||||
goto fail;
|
||||
|
||||
/* 0x08: ? */
|
||||
|
@ -534,7 +603,7 @@ static int parse_kwb(kwb_header* kwb, STREAMFILE* sf_h, STREAMFILE* sf_b) {
|
|||
goto fail;
|
||||
break;
|
||||
|
||||
case 0x53447364: /* "SDsd" (PS3? leftover files) */
|
||||
case 0x53447364: /* "SDsd" [Bladestorm Nightmare (PC)-X360 leftover files] */
|
||||
if (!parse_type_sdsd(kwb, head_offset, body_offset, sf_h))
|
||||
goto fail;
|
||||
break;
|
||||
|
|
|
@ -66,8 +66,8 @@ VGMSTREAM * init_vgmstream_csmp(STREAMFILE *streamFile);
|
|||
|
||||
VGMSTREAM * init_vgmstream_rfrm(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile);
|
||||
VGMSTREAM * init_vgmstream_ps2_ads_container(STREAMFILE *streamFile);
|
||||
VGMSTREAM* init_vgmstream_ads(STREAMFILE* sf);
|
||||
VGMSTREAM* init_vgmstream_ads_container(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM * init_vgmstream_nps(STREAMFILE *streamFile);
|
||||
|
||||
|
@ -79,8 +79,8 @@ VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile);
|
|||
|
||||
VGMSTREAM * init_vgmstream_xa(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile);
|
||||
VGMSTREAM * init_vgmstream_ps2_rxw(STREAMFILE *streamFile);
|
||||
VGMSTREAM * init_vgmstream_rxws(STREAMFILE* sf);
|
||||
VGMSTREAM * init_vgmstream_rxws_badrip(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM * init_vgmstream_raw_int(STREAMFILE *streamFile);
|
||||
|
||||
|
@ -384,7 +384,7 @@ VGMSTREAM * init_vgmstream_ps2_tk1(STREAMFILE* streamFile);
|
|||
|
||||
VGMSTREAM * init_vgmstream_ps2_vsf_tta(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ads(STREAMFILE *streamFile);
|
||||
VGMSTREAM* init_vgmstream_ads_midway(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_mcg(STREAMFILE *streamFile);
|
||||
|
||||
|
@ -508,8 +508,6 @@ VGMSTREAM * init_vgmstream_ps3_past(STREAMFILE* streamFile);
|
|||
|
||||
VGMSTREAM * init_vgmstream_sgxd(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngca(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_wii_ras(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_spm(STREAMFILE* streamFile);
|
||||
|
@ -848,7 +846,7 @@ VGMSTREAM * init_vgmstream_awb(STREAMFILE * streamFile);
|
|||
VGMSTREAM * init_vgmstream_awb_memory(STREAMFILE * streamFile, STREAMFILE *acbFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_acb(STREAMFILE * streamFile);
|
||||
void load_acb_wave_name(STREAMFILE *acbFile, VGMSTREAM* vgmstream, int waveid, int is_memory);
|
||||
void load_acb_wave_name(STREAMFILE *acbFile, VGMSTREAM* vgmstream, int waveid, int port, int is_memory);
|
||||
|
||||
VGMSTREAM * init_vgmstream_rad(STREAMFILE * streamFile);
|
||||
|
||||
|
|
|
@ -8,7 +8,9 @@ VGMSTREAM* init_vgmstream_msb_msh(STREAMFILE* sf) {
|
|||
off_t start_offset, header_offset = 0;
|
||||
size_t stream_size;
|
||||
int loop_flag, channels, sample_rate;
|
||||
int32_t loop_start, loop_end;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
uint32_t config;
|
||||
|
||||
|
||||
/* checks */
|
||||
|
@ -20,12 +22,12 @@ VGMSTREAM* init_vgmstream_msb_msh(STREAMFILE* sf) {
|
|||
|
||||
if (read_u32le(0x00,sh) != get_streamfile_size(sh))
|
||||
goto fail;
|
||||
/* 0x04: unknown */
|
||||
/* 0x04: flags? (0x04/34*/
|
||||
|
||||
/* parse entries */
|
||||
{
|
||||
int i;
|
||||
int entries = read_s32le(0x08,sh);
|
||||
int entries = read_s32le(0x08,sh); /* may be less than file size, or include dummies (all dummies is possible too) */
|
||||
|
||||
total_subsongs = 0;
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
|
@ -45,15 +47,20 @@ VGMSTREAM* init_vgmstream_msb_msh(STREAMFILE* sf) {
|
|||
}
|
||||
|
||||
|
||||
loop_flag = 0;
|
||||
channels = 1;
|
||||
|
||||
stream_size = read_u32le(header_offset+0x00, sh);
|
||||
if (read_u32le(header_offset+0x04, sh) != 0) /* stereo flag? */
|
||||
goto fail;
|
||||
config = read_u32le(header_offset+0x04, sh); /* volume (0~100), null, null, loop (0/1) */
|
||||
start_offset = read_u32le(header_offset+0x08, sh);
|
||||
sample_rate = read_u32le(header_offset+0x0c, sh); /* Ace Combat 2 seems to set wrong values but probably their bug */
|
||||
|
||||
loop_flag = (config & 1);
|
||||
channels = 1;
|
||||
|
||||
/* rare [Dr. Seuss Cat in the Hat (PS2)] */
|
||||
if (loop_flag) {
|
||||
/* when loop is set ADPCM has loop flags, but rarely appear too without loop set */
|
||||
loop_flag = ps_find_loop_offsets(sf, start_offset, stream_size, channels, 0, &loop_start, &loop_end);
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
|
@ -62,6 +69,8 @@ VGMSTREAM* init_vgmstream_msb_msh(STREAMFILE* sf) {
|
|||
vgmstream->meta_type = meta_MSB_MSH;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = ps_bytes_to_samples(stream_size, channels);
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = stream_size;
|
||||
|
|
|
@ -1,62 +1,62 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* WMSF - Banpresto MSFx wrapper [Dai-2-Ji Super Robot Taisen OG: The Moon Dwellers (PS3)] */
|
||||
VGMSTREAM * init_vgmstream_msf_banpresto_wmsf(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
off_t subfile_offset = 0x10;
|
||||
size_t subfile_size = get_streamfile_size(streamFile) - subfile_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
if ( !check_extensions(streamFile,"msf"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x574D5346) /* "WMSF" */
|
||||
goto fail;
|
||||
/* 0x04: size, 0x08: flags? 0x0c: null? */
|
||||
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_msf(temp_streamFile);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 2MSF - Banpresto RIFF wrapper [Dai-2-Ji Super Robot Taisen OG: The Moon Dwellers (PS4)] */
|
||||
VGMSTREAM * init_vgmstream_msf_banpresto_2msf(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
off_t subfile_offset = 0x14;
|
||||
size_t subfile_size = get_streamfile_size(streamFile) - subfile_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
if ( !check_extensions(streamFile,"at9"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x324D5346) /* "2MSF" */
|
||||
goto fail;
|
||||
/* 0x04: size, 0x08: flags? 0x0c: null?, 0x10: 0x01? (BE values even though RIFF is LE) */
|
||||
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
|
||||
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;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* WMSF - Banpresto MSFx wrapper [Dai-2-Ji Super Robot Taisen OG: The Moon Dwellers (PS3)] */
|
||||
VGMSTREAM* init_vgmstream_msf_banpresto_wmsf(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
off_t subfile_offset = 0x10;
|
||||
size_t subfile_size = get_streamfile_size(sf) - subfile_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf,"msf"))
|
||||
goto fail;
|
||||
if (!is_id32be(0x00,sf,"WMSF"))
|
||||
goto fail;
|
||||
/* 0x04: size, 0x08: flags? 0x0c: null? */
|
||||
|
||||
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, NULL);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_msf(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_sf);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 2MSF - Banpresto RIFF wrapper [Dai-2-Ji Super Robot Taisen OG: The Moon Dwellers (PS4)] */
|
||||
VGMSTREAM* init_vgmstream_msf_banpresto_2msf(STREAMFILE *sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE*temp_sf = NULL;
|
||||
off_t subfile_offset = 0x14;
|
||||
size_t subfile_size = get_streamfile_size(sf) - subfile_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
if ( !check_extensions(sf,"at9"))
|
||||
goto fail;
|
||||
if (!is_id32be(0x00,sf,"2MSF"))
|
||||
goto fail;
|
||||
/* 0x04: size, 0x08: flags? 0x0c: null?, 0x10: 0x01? (BE values even though RIFF is LE) */
|
||||
|
||||
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, NULL);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_riff(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_sf);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1,58 +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;
|
||||
}
|
||||
#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* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
uint32_t codec;
|
||||
int loop_flag, channels, sample_rate;
|
||||
size_t data_size;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf,"msf"))
|
||||
goto fail;
|
||||
if (!is_id32be(0x00,sf,"MSFC"))
|
||||
goto fail;
|
||||
|
||||
start_offset = 0x20;
|
||||
|
||||
codec = read_u32be(0x04,sf);
|
||||
channels = read_s32be(0x08,sf);
|
||||
sample_rate = read_s32be(0x0c,sf);
|
||||
data_size = read_u32be(0x10,sf); /* without header */
|
||||
if (data_size + start_offset != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
loop_flag = 0;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels,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, channels);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* NGCA (from GoldenEye 007) */
|
||||
VGMSTREAM * init_vgmstream_ngca(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("ngca",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x4E474341) /* "NGCA" */
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = 1;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x40;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = 32000;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->num_samples = (((read_32bitBE(0x4,streamFile))/2) - 1) / 8 * 14;
|
||||
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_NGCA;
|
||||
vgmstream->allow_dual_stereo = 1;
|
||||
|
||||
if (vgmstream->coding_type == coding_NGC_DSP) {
|
||||
int i;
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0xC+i*2,streamFile);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -1,368 +1,368 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* .ADS - Sony's "Audio Stream" format [Edit Racing (PS2), Evergrace II (PS2), Pri-Saga! Portable (PSP)] */
|
||||
VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count, sample_rate, interleave, is_loop_samples = 0;
|
||||
size_t body_size, stream_size, file_size;
|
||||
uint32_t codec, loop_start_sample = 0, loop_end_sample = 0, loop_start_offset = 0, loop_end_offset = 0;
|
||||
coding_t coding_type;
|
||||
int ignore_silent_frame_cavia = 0, ignore_silent_frame_capcom = 0;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .ads: actual extension
|
||||
* .ss2: demuxed videos (fake?)
|
||||
* .pcm: Taisho Mononoke Ibunroku (PS2)
|
||||
* .adx: Armored Core 3 (PS2)
|
||||
* [no actual extension]: MotoGP (PS2)
|
||||
* .800: Mobile Suit Gundam: The One Year War (PS2) */
|
||||
if (!check_extensions(streamFile, "ads,ss2,pcm,adx,,800"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) != 0x53536864 && /* "SShd" */
|
||||
read_32bitBE(0x20,streamFile) != 0x53536264) /* "SSbd" */
|
||||
goto fail;
|
||||
if (read_32bitLE(0x04,streamFile) != 0x18 && /* standard header size */
|
||||
read_32bitLE(0x04,streamFile) != 0x20) /* True Fortune (PS2) */
|
||||
goto fail;
|
||||
|
||||
|
||||
/* base values (a bit unorderly since devs hack ADS too much and detection is messy) */
|
||||
{
|
||||
codec = read_32bitLE(0x08,streamFile);
|
||||
sample_rate = read_32bitLE(0x0C,streamFile);
|
||||
channel_count = read_32bitLE(0x10,streamFile); /* up to 4 [Eve of Extinction (PS2)] */
|
||||
interleave = read_32bitLE(0x14,streamFile); /* set even when mono */
|
||||
|
||||
|
||||
switch(codec) {
|
||||
case 0x01: /* official definition */
|
||||
case 0x80000001: /* [Evergrace II (PS2), but not other From Soft games] */
|
||||
coding_type = coding_PCM16LE;
|
||||
|
||||
/* Angel Studios/Rockstar San Diego videos codec hijack [Red Dead Revolver (PS2), Spy Hunter 2 (PS2)] */
|
||||
if (sample_rate == 12000 && interleave == 0x200) {
|
||||
sample_rate = 48000;
|
||||
interleave = 0x40;
|
||||
coding_type = coding_DVI_IMA_int;
|
||||
/* should try to detect IMA data but it's not so easy, this works ok since
|
||||
* no known games use these settings, videos normally are 48000/24000hz */
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10: /* official definition */
|
||||
case 0x02: /* Capcom games extension, stereo only [Megaman X7 (PS2), Breath of Fire V (PS2), Clock Tower 3 (PS2)] */
|
||||
coding_type = coding_PSX;
|
||||
break;
|
||||
|
||||
case 0x00: /* PCM16BE from official docs, probably never used */
|
||||
default:
|
||||
VGM_LOG("ADS: unknown codec\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* sizes */
|
||||
{
|
||||
file_size = get_streamfile_size(streamFile);
|
||||
body_size = read_32bitLE(0x24,streamFile);
|
||||
|
||||
/* bigger than file_size in rare cases, even if containing all data (ex. Megaman X7's SY04.ADS) */
|
||||
if (body_size + 0x28 > file_size) {
|
||||
body_size = file_size - 0x28;
|
||||
}
|
||||
|
||||
/* True Fortune: weird stream size */
|
||||
if (body_size * 2 == file_size - 0x18) {
|
||||
body_size = (body_size * 2) - 0x10;
|
||||
}
|
||||
|
||||
stream_size = body_size;
|
||||
}
|
||||
|
||||
|
||||
/* offset */
|
||||
{
|
||||
start_offset = 0x28;
|
||||
|
||||
/* start padding (body size is ok, may have end padding) [Evergrace II (PS2), Armored Core 3 (PS2)] */
|
||||
/* detection depends on files being properly ripped, so broken/cut files won't play ok */
|
||||
if (file_size - body_size >= 0x800) {
|
||||
start_offset = 0x800; /* aligned to sector */
|
||||
|
||||
/* too much end padding, happens in Super Galdelic Hour's SEL.ADS, maybe in bad rips too */
|
||||
VGM_ASSERT(file_size - body_size > 0x8000, "ADS: big end padding %x\n", file_size - body_size);
|
||||
}
|
||||
|
||||
/* "ADSC" container */
|
||||
if (coding_type == coding_PSX
|
||||
&& read_32bitLE(0x28,streamFile) == 0x1000 /* real start */
|
||||
&& read_32bitLE(0x2c,streamFile) == 0
|
||||
&& read_32bitLE(0x1008,streamFile) != 0) {
|
||||
int i;
|
||||
int is_adsc = 1;
|
||||
|
||||
/* should be empty up to data start */
|
||||
for (i = 0; i < 0xFDC/4; i++) {
|
||||
if (read_32bitLE(0x2c+(i*4),streamFile) != 0) {
|
||||
is_adsc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_adsc) {
|
||||
start_offset = 0x1000 - 0x08; /* remove "ADSC" alignment */
|
||||
/* stream_size doesn't count start offset padding */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* loops */
|
||||
{
|
||||
uint32_t loop_start, loop_end;
|
||||
|
||||
loop_start = read_32bitLE(0x18,streamFile);
|
||||
loop_end = read_32bitLE(0x1C,streamFile);
|
||||
|
||||
loop_flag = 0;
|
||||
|
||||
/* detect loops the best we can; docs say those are loop block addresses,
|
||||
* but each maker does whatever (no games seem to use PS-ADPCM loop flags though) */
|
||||
|
||||
|
||||
if (loop_start != 0xFFFFFFFF && loop_end == 0xFFFFFFFF) {
|
||||
|
||||
if (codec == 0x02) { /* Capcom codec */
|
||||
/* Capcom games: loop_start is address * 0x10 [Mega Man X7, Breath of Fire V, Clock Tower 3] */
|
||||
loop_flag = ((loop_start * 0x10) + 0x200 < body_size); /* near the end (+0x20~80) means no loop */
|
||||
loop_start_offset = loop_start * 0x10;
|
||||
ignore_silent_frame_capcom = 1;
|
||||
}
|
||||
else if (read_32bitBE(0x28,streamFile) == 0x50414421) { /* "PAD!" padding until 0x800 */
|
||||
/* Super Galdelic Hour: loop_start is PCM bytes */
|
||||
loop_flag = 1;
|
||||
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 */
|
||||
/* 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;
|
||||
loop_start_offset = loop_start - 0x800;
|
||||
ignore_silent_frame_cavia = 1;
|
||||
}
|
||||
else if (loop_start % 0x800 != 0 || loop_start == 0) { /* not sector aligned */
|
||||
/* Katakamuna: loop_start is address * 0x10 */
|
||||
loop_flag = 1;
|
||||
loop_start_offset = loop_start * 0x10;
|
||||
}
|
||||
}
|
||||
else if (loop_start != 0xFFFFFFFF && loop_end != 0xFFFFFFFF
|
||||
&& loop_end > 0) { /* ignore Kamen Rider Blade and others */
|
||||
#if 0
|
||||
//todo improve detection to avoid clashing with address*0x20
|
||||
if (loop_end == body_size / 0x10) { /* always body_size? but not all files should loop */
|
||||
/* Akane Iro ni Somaru Saka - Parallel: loops is address * 0x10 */
|
||||
loop_flag = 1;
|
||||
loop_start_offset = loop_start * 0x10;
|
||||
loop_end_offset = loop_end * 0x10;
|
||||
}
|
||||
#endif
|
||||
if (loop_end <= body_size / 0x200 && coding_type == coding_PCM16LE) { /* close to body_size */
|
||||
/* Gofun-go no Sekai: loops is address * 0x200 */
|
||||
loop_flag = 1;
|
||||
loop_start_offset = loop_start * 0x200;
|
||||
loop_end_offset = loop_end * 0x200;
|
||||
}
|
||||
else if (loop_end <= body_size / 0x70 && coding_type == coding_PCM16LE) { /* close to body_size */
|
||||
/* Armored Core - Nexus: loops is address * 0x70 */
|
||||
loop_flag = 1;
|
||||
loop_start_offset = loop_start * 0x70;
|
||||
loop_end_offset = loop_end * 0x70;
|
||||
}
|
||||
else if (loop_end <= body_size / 0x20 && coding_type == coding_PCM16LE) { /* close to body_size */
|
||||
/* Armored Core - Nine Breaker: loops is address * 0x20 */
|
||||
loop_flag = 1;
|
||||
loop_start_offset = loop_start * 0x20;
|
||||
loop_end_offset = loop_end * 0x20;
|
||||
}
|
||||
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] */
|
||||
loop_flag = 1;
|
||||
loop_start_sample = loop_start;
|
||||
loop_end_sample = loop_end;
|
||||
is_loop_samples = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//todo Jet Ion Grand Prix seems to have some loop-like values at 0x28
|
||||
//todo Yoake mae yori Ruriiro na has loops in unknown format
|
||||
}
|
||||
|
||||
|
||||
/* most games have empty PS-ADPCM frames in the last interleave block that should be skipped for smooth looping */
|
||||
if (coding_type == coding_PSX) {
|
||||
off_t offset, min_offset;
|
||||
|
||||
offset = start_offset + stream_size;
|
||||
min_offset = offset - interleave;
|
||||
|
||||
do {
|
||||
offset -= 0x10;
|
||||
|
||||
if (read_8bit(offset+0x01,streamFile) == 0x07) {
|
||||
stream_size -= 0x10*channel_count;/* ignore don't decode flag/padding frame (most common) [ex. Capcom games] */
|
||||
}
|
||||
else if (read_32bitBE(offset+0x00,streamFile) == 0x00000000 && read_32bitBE(offset+0x04,streamFile) == 0x00000000 &&
|
||||
read_32bitBE(offset+0x08,streamFile) == 0x00000000 && read_32bitBE(offset+0x0c,streamFile) == 0x00000000) {
|
||||
stream_size -= 0x10*channel_count; /* ignore null frame [ex. A.C.E. Another Century Episode 1/2/3] */
|
||||
}
|
||||
else if (read_32bitBE(offset+0x00,streamFile) == 0x00007777 && read_32bitBE(offset+0x04,streamFile) == 0x77777777 &&
|
||||
read_32bitBE(offset+0x08,streamFile) == 0x77777777 && read_32bitBE(offset+0x0c,streamFile) == 0x77777777) {
|
||||
stream_size -= 0x10*channel_count; /* ignore padding frame [ex. Akane Iro ni Somaru Saka - Parallel] */
|
||||
}
|
||||
else if (read_32bitBE(offset+0x00,streamFile) == 0x0C020000 && read_32bitBE(offset+0x04,streamFile) == 0x00000000 &&
|
||||
read_32bitBE(offset+0x08,streamFile) == 0x00000000 && read_32bitBE(offset+0x0c,streamFile) == 0x00000000 &&
|
||||
ignore_silent_frame_cavia) {
|
||||
stream_size -= 0x10*channel_count; /* ignore silent frame [ex. cavia games] */
|
||||
}
|
||||
else if (read_32bitBE(offset+0x00,streamFile) == 0x0C010000 && read_32bitBE(offset+0x04,streamFile) == 0x00000000 &&
|
||||
read_32bitBE(offset+0x08,streamFile) == 0x00000000 && read_32bitBE(offset+0x0c,streamFile) == 0x00000000 &&
|
||||
ignore_silent_frame_capcom) {
|
||||
stream_size -= 0x10*channel_count; /* ignore silent frame [ex. Capcom games] */
|
||||
}
|
||||
else {
|
||||
break; /* standard frame */
|
||||
}
|
||||
}
|
||||
while(offset > min_offset);
|
||||
|
||||
/* don't bother fixing loop_end_offset since will be adjusted to num_samples later, if needed */
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->coding_type = coding_type;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->meta_type = meta_PS2_SShd;
|
||||
|
||||
switch(coding_type) {
|
||||
case coding_PCM16LE:
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16);
|
||||
break;
|
||||
case coding_PSX:
|
||||
vgmstream->num_samples = ps_bytes_to_samples(stream_size, channel_count);
|
||||
break;
|
||||
case coding_DVI_IMA_int:
|
||||
vgmstream->num_samples = ima_bytes_to_samples(stream_size, channel_count);
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (vgmstream->loop_flag) {
|
||||
if (is_loop_samples) {
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
}
|
||||
else {
|
||||
switch(vgmstream->coding_type) {
|
||||
case coding_PCM16LE:
|
||||
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start_offset,channel_count,16);
|
||||
vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_end_offset,channel_count,16);
|
||||
break;
|
||||
case coding_PSX:
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start_offset,channel_count);
|
||||
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end_offset,channel_count);
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* when loop_end = 0xFFFFFFFF */
|
||||
if (vgmstream->loop_end_sample == 0)
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
/* happens even when loops are directly samples, loops sound fine (ex. Culdcept) */
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples)
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ****************************************************************************** */
|
||||
|
||||
/* ADS in containers */
|
||||
VGMSTREAM * init_vgmstream_ps2_ads_container(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
off_t subfile_offset;
|
||||
size_t subfile_size;
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "ads"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) == 0x41445343 && /* "ADSC" */
|
||||
read_32bitBE(0x04,streamFile) == 0x01000000) {
|
||||
/* Kenka Bancho 2, Kamen Rider Hibiki/Kabuto, Shinjuku no Okami */
|
||||
subfile_offset = 0x08;
|
||||
}
|
||||
else if (read_32bitBE(0x00,streamFile) == 0x63617669 && /* "cavi" */
|
||||
read_32bitBE(0x04,streamFile) == 0x61207374 && /* "a st" */
|
||||
read_32bitBE(0x08,streamFile) == 0x7265616D) { /* "ream" */
|
||||
/* cavia games: Drakengard 1/2, Dragon Quest Yangus, GITS: Stand Alone Complex */
|
||||
subfile_offset = 0x7d8;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
subfile_size = get_streamfile_size(streamFile) - subfile_offset;
|
||||
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_ps2_ads(temp_streamFile);
|
||||
close_streamfile(temp_streamFile);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* .ADS - Sony's "Audio Stream" format [Edit Racing (PS2), Evergrace II (PS2), Pri-Saga! Portable (PSP)] */
|
||||
VGMSTREAM* init_vgmstream_ads(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channels, sample_rate, interleave, is_loop_samples = 0;
|
||||
size_t body_size, stream_size, file_size;
|
||||
uint32_t codec, loop_start_sample = 0, loop_end_sample = 0, loop_start_offset = 0, loop_end_offset = 0;
|
||||
coding_t coding_type;
|
||||
int ignore_silent_frame_cavia = 0, ignore_silent_frame_capcom = 0;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .ads: actual extension
|
||||
* .ss2: demuxed videos (fake?)
|
||||
* .pcm: Taisho Mononoke Ibunroku (PS2)
|
||||
* .adx: Armored Core 3 (PS2)
|
||||
* (extensionless): MotoGP (PS2)
|
||||
* .800: Mobile Suit Gundam: The One Year War (PS2) */
|
||||
if (!check_extensions(sf, "ads,ss2,pcm,adx,,800"))
|
||||
goto fail;
|
||||
|
||||
if (!is_id32be(0x00,sf,"SShd") &&
|
||||
!is_id32be(0x20,sf,"SSbd"))
|
||||
goto fail;
|
||||
if (read_32bitLE(0x04,sf) != 0x18 && /* standard header size */
|
||||
read_32bitLE(0x04,sf) != 0x20) /* True Fortune (PS2) */
|
||||
goto fail;
|
||||
|
||||
|
||||
/* base values (a bit unorderly since devs hack ADS too much and detection is messy) */
|
||||
{
|
||||
codec = read_32bitLE(0x08,sf);
|
||||
sample_rate = read_32bitLE(0x0C,sf);
|
||||
channels = read_32bitLE(0x10,sf); /* up to 4 [Eve of Extinction (PS2)] */
|
||||
interleave = read_32bitLE(0x14,sf); /* set even when mono */
|
||||
|
||||
|
||||
switch(codec) {
|
||||
case 0x01: /* official definition */
|
||||
case 0x80000001: /* [Evergrace II (PS2), but not other From Soft games] */
|
||||
coding_type = coding_PCM16LE;
|
||||
|
||||
/* Angel Studios/Rockstar San Diego videos codec hijack [Red Dead Revolver (PS2), Spy Hunter 2 (PS2)] */
|
||||
if (sample_rate == 12000 && interleave == 0x200) {
|
||||
sample_rate = 48000;
|
||||
interleave = 0x40;
|
||||
coding_type = coding_DVI_IMA_int;
|
||||
/* should try to detect IMA data but it's not so easy, this works ok since
|
||||
* no known games use these settings, videos normally are 48000/24000hz */
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10: /* official definition */
|
||||
case 0x02: /* Capcom games extension, stereo only [Megaman X7 (PS2), Breath of Fire V (PS2), Clock Tower 3 (PS2)] */
|
||||
coding_type = coding_PSX;
|
||||
break;
|
||||
|
||||
case 0x00: /* PCM16BE from official docs, probably never used */
|
||||
default:
|
||||
VGM_LOG("ADS: unknown codec\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* sizes */
|
||||
{
|
||||
file_size = get_streamfile_size(sf);
|
||||
body_size = read_32bitLE(0x24,sf);
|
||||
|
||||
/* bigger than file_size in rare cases, even if containing all data (ex. Megaman X7's SY04.ADS) */
|
||||
if (body_size + 0x28 > file_size) {
|
||||
body_size = file_size - 0x28;
|
||||
}
|
||||
|
||||
/* True Fortune: weird stream size */
|
||||
if (body_size * 2 == file_size - 0x18) {
|
||||
body_size = (body_size * 2) - 0x10;
|
||||
}
|
||||
|
||||
stream_size = body_size;
|
||||
}
|
||||
|
||||
|
||||
/* offset */
|
||||
{
|
||||
start_offset = 0x28;
|
||||
|
||||
/* start padding (body size is ok, may have end padding) [Evergrace II (PS2), Armored Core 3 (PS2)] */
|
||||
/* detection depends on files being properly ripped, so broken/cut files won't play ok */
|
||||
if (file_size - body_size >= 0x800) {
|
||||
start_offset = 0x800; /* aligned to sector */
|
||||
|
||||
/* too much end padding, happens in Super Galdelic Hour's SEL.ADS, maybe in bad rips too */
|
||||
VGM_ASSERT(file_size - body_size > 0x8000, "ADS: big end padding %x\n", file_size - body_size);
|
||||
}
|
||||
|
||||
/* "ADSC" container */
|
||||
if (coding_type == coding_PSX
|
||||
&& read_32bitLE(0x28,sf) == 0x1000 /* real start */
|
||||
&& read_32bitLE(0x2c,sf) == 0
|
||||
&& read_32bitLE(0x1008,sf) != 0) {
|
||||
int i;
|
||||
int is_adsc = 1;
|
||||
|
||||
/* should be empty up to data start */
|
||||
for (i = 0; i < 0xFDC/4; i++) {
|
||||
if (read_32bitLE(0x2c+(i*4),sf) != 0) {
|
||||
is_adsc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_adsc) {
|
||||
start_offset = 0x1000 - 0x08; /* remove "ADSC" alignment */
|
||||
/* stream_size doesn't count start offset padding */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* loops */
|
||||
{
|
||||
uint32_t loop_start, loop_end;
|
||||
|
||||
loop_start = read_32bitLE(0x18,sf);
|
||||
loop_end = read_32bitLE(0x1C,sf);
|
||||
|
||||
loop_flag = 0;
|
||||
|
||||
/* detect loops the best we can; docs say those are loop block addresses,
|
||||
* but each maker does whatever (no games seem to use PS-ADPCM loop flags though) */
|
||||
|
||||
|
||||
if (loop_start != 0xFFFFFFFF && loop_end == 0xFFFFFFFF) {
|
||||
|
||||
if (codec == 0x02) { /* Capcom codec */
|
||||
/* Capcom games: loop_start is address * 0x10 [Mega Man X7, Breath of Fire V, Clock Tower 3] */
|
||||
loop_flag = ((loop_start * 0x10) + 0x200 < body_size); /* near the end (+0x20~80) means no loop */
|
||||
loop_start_offset = loop_start * 0x10;
|
||||
ignore_silent_frame_capcom = 1;
|
||||
}
|
||||
else if (read_32bitBE(0x28,sf) == 0x50414421) { /* "PAD!" padding until 0x800 */
|
||||
/* Super Galdelic Hour: loop_start is PCM bytes */
|
||||
loop_flag = 1;
|
||||
loop_start_sample = loop_start / 2 / channels;
|
||||
is_loop_samples = 1;
|
||||
}
|
||||
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;
|
||||
loop_start_offset = loop_start - 0x800;
|
||||
ignore_silent_frame_cavia = 1;
|
||||
}
|
||||
else if (loop_start % 0x800 != 0 || loop_start == 0) { /* not sector aligned */
|
||||
/* Katakamuna: loop_start is address * 0x10 */
|
||||
loop_flag = 1;
|
||||
loop_start_offset = loop_start * 0x10;
|
||||
}
|
||||
}
|
||||
else if (loop_start != 0xFFFFFFFF && loop_end != 0xFFFFFFFF
|
||||
&& loop_end > 0) { /* ignore Kamen Rider Blade and others */
|
||||
#if 0
|
||||
//todo improve detection to avoid clashing with address*0x20
|
||||
if (loop_end == body_size / 0x10) { /* always body_size? but not all files should loop */
|
||||
/* Akane Iro ni Somaru Saka - Parallel: loops is address * 0x10 */
|
||||
loop_flag = 1;
|
||||
loop_start_offset = loop_start * 0x10;
|
||||
loop_end_offset = loop_end * 0x10;
|
||||
}
|
||||
#endif
|
||||
if (loop_end <= body_size / 0x200 && coding_type == coding_PCM16LE) { /* close to body_size */
|
||||
/* Gofun-go no Sekai: loops is address * 0x200 */
|
||||
loop_flag = 1;
|
||||
loop_start_offset = loop_start * 0x200;
|
||||
loop_end_offset = loop_end * 0x200;
|
||||
}
|
||||
else if (loop_end <= body_size / 0x70 && coding_type == coding_PCM16LE) { /* close to body_size */
|
||||
/* Armored Core - Nexus: loops is address * 0x70 */
|
||||
loop_flag = 1;
|
||||
loop_start_offset = loop_start * 0x70;
|
||||
loop_end_offset = loop_end * 0x70;
|
||||
}
|
||||
else if (loop_end <= body_size / 0x20 && coding_type == coding_PCM16LE) { /* close to body_size */
|
||||
/* Armored Core - Nine Breaker: loops is address * 0x20 */
|
||||
loop_flag = 1;
|
||||
loop_start_offset = loop_start * 0x20;
|
||||
loop_end_offset = loop_end * 0x20;
|
||||
}
|
||||
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, sf) == 0x00077777 ||
|
||||
read_32bitBE(0x28 + loop_end*0x10 + 0x20 + 0x00, sf) == 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] */
|
||||
loop_flag = 1;
|
||||
loop_start_sample = loop_start;
|
||||
loop_end_sample = loop_end;
|
||||
is_loop_samples = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//todo Jet Ion Grand Prix seems to have some loop-like values at 0x28
|
||||
//todo Yoake mae yori Ruriiro na has loops in unknown format
|
||||
}
|
||||
|
||||
|
||||
/* most games have empty PS-ADPCM frames in the last interleave block that should be skipped for smooth looping */
|
||||
if (coding_type == coding_PSX) {
|
||||
off_t offset, min_offset;
|
||||
|
||||
offset = start_offset + stream_size;
|
||||
min_offset = offset - interleave;
|
||||
|
||||
do {
|
||||
offset -= 0x10;
|
||||
|
||||
if (read_8bit(offset+0x01,sf) == 0x07) {
|
||||
stream_size -= 0x10*channels;/* ignore don't decode flag/padding frame (most common) [ex. Capcom games] */
|
||||
}
|
||||
else if (read_32bitBE(offset+0x00,sf) == 0x00000000 && read_32bitBE(offset+0x04,sf) == 0x00000000 &&
|
||||
read_32bitBE(offset+0x08,sf) == 0x00000000 && read_32bitBE(offset+0x0c,sf) == 0x00000000) {
|
||||
stream_size -= 0x10*channels; /* ignore null frame [ex. A.C.E. Another Century Episode 1/2/3] */
|
||||
}
|
||||
else if (read_32bitBE(offset+0x00,sf) == 0x00007777 && read_32bitBE(offset+0x04,sf) == 0x77777777 &&
|
||||
read_32bitBE(offset+0x08,sf) == 0x77777777 && read_32bitBE(offset+0x0c,sf) == 0x77777777) {
|
||||
stream_size -= 0x10*channels; /* ignore padding frame [ex. Akane Iro ni Somaru Saka - Parallel] */
|
||||
}
|
||||
else if (read_32bitBE(offset+0x00,sf) == 0x0C020000 && read_32bitBE(offset+0x04,sf) == 0x00000000 &&
|
||||
read_32bitBE(offset+0x08,sf) == 0x00000000 && read_32bitBE(offset+0x0c,sf) == 0x00000000 &&
|
||||
ignore_silent_frame_cavia) {
|
||||
stream_size -= 0x10*channels; /* ignore silent frame [ex. cavia games] */
|
||||
}
|
||||
else if (read_32bitBE(offset+0x00,sf) == 0x0C010000 && read_32bitBE(offset+0x04,sf) == 0x00000000 &&
|
||||
read_32bitBE(offset+0x08,sf) == 0x00000000 && read_32bitBE(offset+0x0c,sf) == 0x00000000 &&
|
||||
ignore_silent_frame_capcom) {
|
||||
stream_size -= 0x10*channels; /* ignore silent frame [ex. Capcom games] */
|
||||
}
|
||||
else {
|
||||
break; /* standard frame */
|
||||
}
|
||||
}
|
||||
while(offset > min_offset);
|
||||
|
||||
/* don't bother fixing loop_end_offset since will be adjusted to num_samples later, if needed */
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->coding_type = coding_type;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->meta_type = meta_ADS;
|
||||
|
||||
switch(coding_type) {
|
||||
case coding_PCM16LE:
|
||||
vgmstream->num_samples = pcm16_bytes_to_samples(stream_size, channels);
|
||||
break;
|
||||
case coding_PSX:
|
||||
vgmstream->num_samples = ps_bytes_to_samples(stream_size, channels);
|
||||
break;
|
||||
case coding_DVI_IMA_int:
|
||||
vgmstream->num_samples = ima_bytes_to_samples(stream_size, channels);
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (vgmstream->loop_flag) {
|
||||
if (is_loop_samples) {
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
}
|
||||
else {
|
||||
switch(vgmstream->coding_type) {
|
||||
case coding_PCM16LE:
|
||||
vgmstream->loop_start_sample = pcm16_bytes_to_samples(loop_start_offset, channels);
|
||||
vgmstream->loop_end_sample = pcm16_bytes_to_samples(loop_end_offset, channels);
|
||||
break;
|
||||
case coding_PSX:
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start_offset, channels);
|
||||
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end_offset, channels);
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* when loop_end = 0xFFFFFFFF */
|
||||
if (vgmstream->loop_end_sample == 0)
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
/* happens even when loops are directly samples, loops sound fine (ex. Culdcept) */
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples)
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ****************************************************************************** */
|
||||
|
||||
/* ADS in containers */
|
||||
VGMSTREAM* init_vgmstream_ads_container(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
off_t subfile_offset;
|
||||
size_t subfile_size;
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "ads"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,sf) == 0x41445343 && /* "ADSC" */
|
||||
read_32bitBE(0x04,sf) == 0x01000000) {
|
||||
/* Kenka Bancho 2, Kamen Rider Hibiki/Kabuto, Shinjuku no Okami */
|
||||
subfile_offset = 0x08;
|
||||
}
|
||||
else if (read_32bitBE(0x00,sf) == 0x63617669 && /* "cavi" */
|
||||
read_32bitBE(0x04,sf) == 0x61207374 && /* "a st" */
|
||||
read_32bitBE(0x08,sf) == 0x7265616D) { /* "ream" */
|
||||
/* cavia games: Drakengard 1/2, Dragon Quest Yangus, GITS: Stand Alone Complex */
|
||||
subfile_offset = 0x7d8;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
subfile_size = get_streamfile_size(sf) - subfile_offset;
|
||||
|
||||
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, NULL);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_ads(temp_sf);
|
||||
close_streamfile(temp_sf);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_sf);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -794,6 +794,7 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
|||
/* UE4 uses interleaved mono MSADPCM, try to autodetect without breaking normal MSADPCM */
|
||||
if (fmt.coding_type == coding_MSADPCM && is_ue4_msadpcm(vgmstream, sf, &fmt, fact_sample_count, start_offset)) {
|
||||
vgmstream->coding_type = coding_MSADPCM_int;
|
||||
vgmstream->codec_config = 1; /* mark as UE4 MSADPCM */
|
||||
vgmstream->frame_size = fmt.block_size;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = get_ue4_msadpcm_interleave(sf, &fmt, start_offset, data_size);
|
||||
|
|
|
@ -3,52 +3,53 @@
|
|||
#include "../coding/coding.h"
|
||||
|
||||
/* RXWS - from Sony SCEI PS2 games (Okage: Shadow King, Genji, Bokura no Kazoku) */
|
||||
VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamHeader = NULL;
|
||||
VGMSTREAM* init_vgmstream_rxws(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* sh = NULL;
|
||||
off_t start_offset, chunk_offset, name_offset = 0;
|
||||
size_t stream_size, chunk_size;
|
||||
int loop_flag = 0, channel_count, is_separate = 0, type, sample_rate;
|
||||
int loop_flag = 0, channels, is_separate = 0, type, sample_rate;
|
||||
int32_t num_samples, loop_start;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
|
||||
/* checks */
|
||||
/* .xws: header and data
|
||||
* .xwh+xwb: header + data (.bin+dat are also found in Wild Arms 4/5) */
|
||||
if (!check_extensions(streamFile,"xws,xwb"))
|
||||
if (!check_extensions(sf,"xws,xwb"))
|
||||
goto fail;
|
||||
is_separate = check_extensions(streamFile,"xwb");
|
||||
is_separate = check_extensions(sf,"xwb");
|
||||
|
||||
/* xwh+xwb: use xwh as header; otherwise use the current file */
|
||||
if (is_separate) {
|
||||
/* extra check to reject Microsoft's XWB faster */
|
||||
if ((read_32bitBE(0x00,streamFile) == 0x57424E44) || /* "WBND" (LE) */
|
||||
(read_32bitBE(0x00,streamFile) == 0x444E4257)) /* "DNBW" (BE) */
|
||||
if (is_id32be(0x00,sf,"WBND") || /* (LE) */
|
||||
is_id32be(0x00,sf,"DNBW")) /* (BE) */
|
||||
goto fail;
|
||||
|
||||
streamHeader = open_streamfile_by_ext(streamFile, "xwh");
|
||||
if (!streamHeader) goto fail;
|
||||
sh = open_streamfile_by_ext(sf, "xwh");
|
||||
if (!sh) goto fail;
|
||||
} else {
|
||||
streamHeader = streamFile;
|
||||
sh = sf;
|
||||
}
|
||||
if (read_32bitBE(0x00,streamHeader) != 0x52585753) /* "RXWS" */
|
||||
if (!is_id32be(0x00,sh,"RXWS"))
|
||||
goto fail;
|
||||
|
||||
/* file size (just the .xwh/xws) */
|
||||
if (read_32bitLE(0x04,streamHeader)+0x10 != get_streamfile_size(streamHeader))
|
||||
if (read_u32le(0x04,sh) + 0x10 != get_streamfile_size(sh))
|
||||
goto fail;
|
||||
/* 0x08(4): version (0x100/0x200), 0x0C: null */
|
||||
/* 0x08: version (0x100/0x200)
|
||||
* 0x0C: null */
|
||||
|
||||
/* typical chunks: FORM, FTXT, MARK, BODY (for .xws) */
|
||||
if (read_32bitBE(0x10,streamHeader) != 0x464F524D) /* "FORM", main header (always first) */
|
||||
if (!is_id32be(0x10,sh,"FORM")) /* main header (always first) */
|
||||
goto fail;
|
||||
chunk_size = read_32bitLE(0x10+0x04,streamHeader); /* size - 0x10 */
|
||||
chunk_size = read_u32le(0x10+0x04,sh); /* size - 0x10 */
|
||||
/* 0x08 version (0x100), 0x0c: null */
|
||||
chunk_offset = 0x20;
|
||||
|
||||
|
||||
/* check multi-streams */
|
||||
total_subsongs = read_32bitLE(chunk_offset+0x00,streamHeader);
|
||||
total_subsongs = read_s32le(chunk_offset+0x00,sh);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
|
@ -58,15 +59,18 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
|||
off_t header_offset = chunk_offset + 0x4 + 0x1c * (target_subsong-1); /* position in FORM */
|
||||
off_t stream_offset, next_stream_offset, data_offset = 0;
|
||||
|
||||
type = read_8bit(header_offset+0x00, streamHeader);
|
||||
/* 0x01(1): unknown (always 0x1c), 0x02(2): flags? (usually 8002/0002, & 0x01 if looped) */
|
||||
/* 0x04(4): vol/pan stuff? (0x00007F7F), 0x08(1): null?, 0x0c(4): null? */
|
||||
channel_count = read_8bit(header_offset+0x09, streamHeader);
|
||||
sample_rate = (uint16_t)read_16bitLE(header_offset+0x0a,streamHeader);
|
||||
stream_offset = read_32bitLE(header_offset+0x10,streamHeader);
|
||||
num_samples = read_32bitLE(header_offset+0x14,streamHeader);
|
||||
loop_start = read_32bitLE(header_offset+0x18,streamHeader);
|
||||
loop_flag = (loop_start != 0xFFFFFFFF);
|
||||
type = read_u8(header_offset+0x00, sh);
|
||||
/* 0x01: unknown (always 0x1c) */
|
||||
/* 0x02: flags? (usually 8002/0002, & 0x01 if looped) */
|
||||
/* 0x04: vol/pan stuff? (0x00007F7F) */
|
||||
/* 0x08: null? */
|
||||
channels = read_u8(header_offset+0x09, sh);
|
||||
/* 0x0c: null? */
|
||||
sample_rate = read_u16le(header_offset+0x0a,sh);
|
||||
stream_offset = read_u32le(header_offset+0x10,sh);
|
||||
num_samples = read_s32le(header_offset+0x14,sh);
|
||||
loop_start = read_s32le(header_offset+0x18,sh);
|
||||
loop_flag = (loop_start >= 0);
|
||||
|
||||
/* find data start and size */
|
||||
if (is_separate) {
|
||||
|
@ -75,21 +79,21 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
|||
else {
|
||||
off_t current_chunk = 0x10;
|
||||
/* note the extra 0x10 in chunk_size/offsets */
|
||||
while (current_chunk < get_streamfile_size(streamFile)) {
|
||||
if (read_32bitBE(current_chunk,streamFile) == 0x424F4459) { /* "BODY" chunk_type */
|
||||
while (current_chunk < get_streamfile_size(sf)) {
|
||||
if (is_id32be(current_chunk,sf, "BODY")) {
|
||||
data_offset = 0x10 + current_chunk;
|
||||
break;
|
||||
}
|
||||
current_chunk += 0x10 + read_32bitLE(current_chunk+4,streamFile);
|
||||
current_chunk += 0x10 + read_u32le(current_chunk+4,sf);
|
||||
}
|
||||
if (!data_offset) goto fail;
|
||||
}
|
||||
|
||||
if (target_subsong == total_subsongs) {
|
||||
next_stream_offset = get_streamfile_size(is_separate ? streamFile : streamHeader) - data_offset;
|
||||
next_stream_offset = get_streamfile_size(is_separate ? sf : sh) - data_offset;
|
||||
} else {
|
||||
off_t next_header_offset = chunk_offset + 0x4 + 0x1c * (target_subsong);
|
||||
next_stream_offset = read_32bitLE(next_header_offset+0x10,streamHeader);
|
||||
next_stream_offset = read_u32le(next_header_offset+0x10,sh);
|
||||
}
|
||||
|
||||
stream_size = next_stream_offset - stream_offset;
|
||||
|
@ -97,24 +101,24 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
|||
}
|
||||
|
||||
/* get stream name (always follows FORM) */
|
||||
if (read_32bitBE(0x10+0x10 + chunk_size,streamHeader) == 0x46545854) { /* "FTXT" */
|
||||
if (is_id32be(0x10+0x10 + chunk_size,sh, "FTXT")) {
|
||||
chunk_offset = 0x10+0x10 + chunk_size + 0x10;
|
||||
if (read_32bitLE(chunk_offset+0x00,streamHeader) == total_subsongs) {
|
||||
name_offset = chunk_offset + read_32bitLE(chunk_offset+0x04 + (target_subsong-1)*0x04,streamHeader);
|
||||
if (read_s32le(chunk_offset+0x00,sh) == total_subsongs) {
|
||||
name_offset = chunk_offset + read_u32le(chunk_offset+0x04 + (target_subsong-1)*0x04,sh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_RXWS;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = stream_size;
|
||||
vgmstream->meta_type = meta_PS2_RXWS;
|
||||
if (name_offset)
|
||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamHeader);
|
||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,sh);
|
||||
|
||||
switch (type) {
|
||||
case 0x00: /* PS-ADPCM */
|
||||
|
@ -122,8 +126,8 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
|||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
|
||||
vgmstream->num_samples = ps_bytes_to_samples(num_samples, channel_count);
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channel_count);
|
||||
vgmstream->num_samples = ps_bytes_to_samples(num_samples, channels);
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channels);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
break;
|
||||
|
||||
|
@ -132,8 +136,8 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
|||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x2;
|
||||
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(num_samples, channel_count, 16);
|
||||
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, channel_count, 16);
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(num_samples, channels, 16);
|
||||
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, channels, 16);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
break;
|
||||
|
||||
|
@ -141,11 +145,11 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
|||
case 0x02: { /* ATRAC3 */
|
||||
int block_align, encoder_delay;
|
||||
|
||||
block_align = 0xc0 * channel_count;
|
||||
block_align = 0xc0 * channels;
|
||||
encoder_delay = 1024 + 69*2; /* observed default */
|
||||
vgmstream->num_samples = num_samples - encoder_delay;
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamFile, start_offset,stream_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(sf, start_offset,stream_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
@ -160,57 +164,58 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
|||
}
|
||||
|
||||
/* open the file for reading */
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
|
||||
if (is_separate && streamHeader) close_streamfile(streamHeader);
|
||||
if (is_separate && sh) close_streamfile(sh);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
if (is_separate && streamHeader) close_streamfile(streamHeader);
|
||||
if (is_separate && sh) close_streamfile(sh);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* .RXW - legacy fake ext/header for poorly split XWH+XWB files generated by old tools (incorrect header/chunk sizes) */
|
||||
VGMSTREAM * init_vgmstream_ps2_rxw(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
int loop_flag=0, channel_count;
|
||||
VGMSTREAM* init_vgmstream_rxws_badrip(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
int loop_flag=0, channels;
|
||||
off_t start_offset;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if (!check_extensions(streamFile,"rxw")) goto fail;
|
||||
|
||||
/* check RXWS/FORM Header */
|
||||
if (!((read_32bitBE(0x00,streamFile) == 0x52585753) &&
|
||||
(read_32bitBE(0x10,streamFile) == 0x464F524D)))
|
||||
if (!check_extensions(sf,"rxw"))
|
||||
goto fail;
|
||||
|
||||
loop_flag = (read_32bitLE(0x3C,streamFile)!=0xFFFFFFFF);
|
||||
channel_count=2; /* Always stereo files */
|
||||
/* check RXWS/FORM Header */
|
||||
if (!((read_32bitBE(0x00,sf) == 0x52585753) &&
|
||||
(read_32bitBE(0x10,sf) == 0x464F524D)))
|
||||
goto fail;
|
||||
|
||||
loop_flag = (read_32bitLE(0x3C,sf)!=0xFFFFFFFF);
|
||||
channels=2; /* Always stereo files */
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitLE(0x2E,streamFile);
|
||||
vgmstream->num_samples = (read_32bitLE(0x38,streamFile)*28/16)/2;
|
||||
vgmstream->sample_rate = read_32bitLE(0x2E,sf);
|
||||
vgmstream->num_samples = (read_32bitLE(0x38,sf)*28/16)/2;
|
||||
|
||||
/* Get loop point values */
|
||||
if(vgmstream->loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x3C,streamFile)/16*14;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x38,streamFile)/16*14;
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x3C,sf)/16*14;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x38,sf)/16*14;
|
||||
}
|
||||
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x1c,streamFile)+0x10;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x1c,sf)+0x10;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->meta_type = meta_PS2_RXWS;
|
||||
vgmstream->meta_type = meta_RXWS;
|
||||
start_offset = 0x40;
|
||||
|
||||
/* open the file for reading */
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
|
@ -1,38 +1,39 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "sqex_scd_streamfile.h"
|
||||
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
static void scd_ogg_v2_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource);
|
||||
static void scd_ogg_v3_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource);
|
||||
static void scd_ogg_v2_decryption_callback(void* ptr, size_t size, size_t nmemb, void* datasource);
|
||||
static void scd_ogg_v3_decryption_callback(void* ptr, size_t size, size_t nmemb, void* datasource);
|
||||
#endif
|
||||
|
||||
/* SCD - Square-Enix games (FF XIII, XIV) */
|
||||
VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
VGMSTREAM* init_vgmstream_sqex_scd(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset, tables_offset, meta_offset, extradata_offset, name_offset = 0;
|
||||
int32_t stream_size, extradata_size, loop_start, loop_end;
|
||||
|
||||
int loop_flag = 0, channel_count, codec, sample_rate;
|
||||
int loop_flag = 0, channels, codec, sample_rate;
|
||||
int version, target_entry, aux_chunk_count;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
int big_endian;
|
||||
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if ( !check_extensions(streamFile, "scd") )
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "scd"))
|
||||
goto fail;
|
||||
|
||||
/** main header **/
|
||||
if (read_32bitBE(0x00,streamFile) != 0x53454442 && /* "SEDB" */
|
||||
read_32bitBE(0x04,streamFile) != 0x53534346) /* "SSCF" */
|
||||
if (!is_id32be(0x00,sf, "SEDB") &&
|
||||
!is_id32be(0x04,sf, "SSCF"))
|
||||
goto fail;
|
||||
|
||||
if (read_8bit(0x0c,streamFile) == 0x01) { /* big endian flag */
|
||||
big_endian = read_u8(0x0c,sf) == 0x01;
|
||||
if (big_endian) { /* big endian flag */
|
||||
//size_offset = 0x14;
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
|
@ -42,21 +43,20 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
read_16bit = read_16bitLE;
|
||||
}
|
||||
|
||||
/* SSCF version? (older SSCFs from Crisis Core/FFXI X360 seem to be V3/2) */
|
||||
if (read_8bit(0x0d,streamFile) != 0x04)
|
||||
goto fail;
|
||||
|
||||
/* v2: FFXIII demo (PS3), FFT0 test files (PC); v3: common; v4: Kingdom Hearts 2.8 (PS4) */
|
||||
version = read_32bit(0x08,streamFile);
|
||||
version = read_32bit(0x08,sf);
|
||||
if (version != 2 && version != 3 && version != 4)
|
||||
goto fail;
|
||||
|
||||
tables_offset = read_16bit(0x0e,streamFile); /* usually 0x30 or 0x20 */
|
||||
/* SSCF version? (older SSCFs from Crisis Core/FFXI X360 seem to be V3/2) */
|
||||
if (read_u8(0x0d,sf) != 0x04)
|
||||
goto fail;
|
||||
|
||||
tables_offset = read_16bit(0x0e,sf); /* usually 0x30 or 0x20 */
|
||||
|
||||
#if 0
|
||||
/* never mind, FFXIII music_68tak.ps3.scd is 0x80 shorter */
|
||||
/* check file size with header value */
|
||||
if (read_32bit(size_offset,streamFile) != get_streamfile_size(streamFile))
|
||||
/* FFXIII music_68tak.ps3.scd is 0x80 shorter? */
|
||||
if (read_32bit(size_offset,sf) != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
|
@ -80,8 +80,8 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
/* find meta_offset in table3 (headers) and total subsongs */
|
||||
{
|
||||
int i;
|
||||
int headers_entries = read_16bit(tables_offset+0x04,streamFile);
|
||||
off_t headers_offset = read_32bit(tables_offset+0x0c,streamFile);
|
||||
int headers_entries = read_16bit(tables_offset+0x04,sf);
|
||||
off_t headers_offset = read_32bit(tables_offset+0x0c,sf);
|
||||
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
total_subsongs = 0;
|
||||
|
@ -89,9 +89,9 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
|
||||
/* manually find subsongs as entries can be dummy (ex. sfx banks in FF XIV or FF Type-0) */
|
||||
for (i = 0; i < headers_entries; i++) {
|
||||
off_t entry_offset = read_32bit(headers_offset + i*0x04,streamFile);
|
||||
off_t entry_offset = read_32bit(headers_offset + i*0x04,sf);
|
||||
|
||||
if (read_32bit(entry_offset+0x0c,streamFile) == -1)
|
||||
if (read_32bit(entry_offset+0x0c,sf) == -1)
|
||||
continue; /* codec -1 when dummy */
|
||||
|
||||
total_subsongs++;
|
||||
|
@ -105,15 +105,15 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
}
|
||||
|
||||
/** stream header **/
|
||||
stream_size = read_32bit(meta_offset+0x00,streamFile);
|
||||
channel_count = read_32bit(meta_offset+0x04,streamFile);
|
||||
sample_rate = read_32bit(meta_offset+0x08,streamFile);
|
||||
codec = read_32bit(meta_offset+0x0c,streamFile);
|
||||
stream_size = read_32bit(meta_offset+0x00,sf);
|
||||
channels = read_32bit(meta_offset+0x04,sf);
|
||||
sample_rate = read_32bit(meta_offset+0x08,sf);
|
||||
codec = read_32bit(meta_offset+0x0c,sf);
|
||||
|
||||
loop_start = read_32bit(meta_offset+0x10,streamFile);
|
||||
loop_end = read_32bit(meta_offset+0x14,streamFile);
|
||||
extradata_size = read_32bit(meta_offset+0x18,streamFile);
|
||||
aux_chunk_count = read_32bit(meta_offset+0x1c,streamFile);
|
||||
loop_start = read_32bit(meta_offset+0x10,sf);
|
||||
loop_end = read_32bit(meta_offset+0x14,sf);
|
||||
extradata_size = read_32bit(meta_offset+0x18,sf);
|
||||
aux_chunk_count = read_32bit(meta_offset+0x1c,sf);
|
||||
/* 0x01e(2): unknown, seen in some FF XIV sfx (MSADPCM) */
|
||||
|
||||
loop_flag = (loop_end > 0);
|
||||
|
@ -127,19 +127,19 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
}
|
||||
|
||||
/* skips aux chunks, sometimes needed (Lightning Returns X360, FF XIV PC) */
|
||||
if (aux_chunk_count && read_32bitBE(extradata_offset, streamFile) == 0x4D41524B) { /* "MARK" */
|
||||
extradata_offset += read_32bit(extradata_offset+0x04, streamFile);
|
||||
if (aux_chunk_count && is_id32be(extradata_offset, sf, "MARK")) {
|
||||
extradata_offset += read_32bit(extradata_offset+0x04, sf);
|
||||
}
|
||||
|
||||
/* find name if possible */
|
||||
if (version == 4) {
|
||||
int info_entries = read_16bit(tables_offset+0x00,streamFile);
|
||||
int headers_entries = read_16bit(tables_offset+0x04,streamFile);
|
||||
int info_entries = read_16bit(tables_offset+0x00,sf);
|
||||
int headers_entries = read_16bit(tables_offset+0x04,sf);
|
||||
off_t info_offset = tables_offset+0x20;
|
||||
|
||||
/* not very exact as table1 and table3 entries may differ in V3, not sure about V4 */
|
||||
if (info_entries == headers_entries) {
|
||||
off_t entry_offset = read_16bit(info_offset + 0x04*target_entry,streamFile);
|
||||
off_t entry_offset = read_16bit(info_offset + 0x04*target_entry,sf);
|
||||
name_offset = entry_offset+0x30;
|
||||
}
|
||||
}
|
||||
|
@ -157,17 +157,17 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
ovmi.disable_reordering = 1; /* already ordered */
|
||||
/* loop values are in bytes, let init_vgmstream_ogg_vorbis find loop comments instead */
|
||||
|
||||
ogg_version = read_8bit(extradata_offset + 0x00, streamFile);
|
||||
ogg_version = read_u8(extradata_offset + 0x00, sf);
|
||||
/* 0x01(1): 0x20 in v2/3, this ogg miniheader size? */
|
||||
ogg_byte = read_8bit(extradata_offset + 0x02, streamFile);
|
||||
ogg_byte = read_u8(extradata_offset + 0x02, sf);
|
||||
/* 0x03(1): ? in v3 */
|
||||
|
||||
if (ogg_version == 0) { /* 0x10? header, then custom Vorbis header before regular Ogg (FF XIV PC v1) */
|
||||
ovmi.stream_size = stream_size;
|
||||
}
|
||||
else { /* 0x20 header, then seek table */
|
||||
size_t seek_table_size = read_32bit(extradata_offset+0x10, streamFile);
|
||||
size_t vorb_header_size = read_32bit(extradata_offset+0x14, streamFile);
|
||||
size_t seek_table_size = read_32bit(extradata_offset+0x10, sf);
|
||||
size_t vorb_header_size = read_32bit(extradata_offset+0x14, sf);
|
||||
/* 0x18(4): ? (can be 0) */
|
||||
|
||||
if ((extradata_offset-meta_offset) + seek_table_size + vorb_header_size != extradata_size)
|
||||
|
@ -192,16 +192,16 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
}
|
||||
|
||||
/* actual Ogg init */
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, start_offset, &ovmi);
|
||||
if (ogg_vgmstream && name_offset)
|
||||
read_string(ogg_vgmstream->stream_name, PATH_LIMIT, name_offset, streamFile);
|
||||
read_string(ogg_vgmstream->stream_name, PATH_LIMIT, name_offset, sf);
|
||||
return ogg_vgmstream;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
@ -209,7 +209,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
vgmstream->stream_size = stream_size;
|
||||
vgmstream->meta_type = meta_SQEX_SCD;
|
||||
if (name_offset)
|
||||
read_string(vgmstream->stream_name, PATH_LIMIT, name_offset, streamFile);
|
||||
read_string(vgmstream->stream_name, STREAM_NAME_SIZE, name_offset, sf);
|
||||
|
||||
switch (codec) {
|
||||
case 0x01: /* PCM */
|
||||
|
@ -217,10 +217,10 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16);
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channels, 16);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, channel_count, 16);
|
||||
vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_end, channel_count, 16);
|
||||
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, channels, 16);
|
||||
vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_end, channels, 16);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -229,10 +229,10 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
|
||||
vgmstream->num_samples = ps_bytes_to_samples(stream_size, channel_count);
|
||||
vgmstream->num_samples = ps_bytes_to_samples(stream_size, channels);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channel_count);
|
||||
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, channel_count);
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channels);
|
||||
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, channels);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -246,7 +246,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
cfg.interleave = 0x800; /* for multistream [Final Fantasy XIII-2 (PS3)], otherwise ignored */
|
||||
cfg.data_size = stream_size;
|
||||
|
||||
vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_SCD, &cfg);
|
||||
vgmstream->codec_data = init_mpeg_custom(sf, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_SCD, &cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
|
@ -268,9 +268,9 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
case 0x0C: /* MS ADPCM [Final Fantasy XIV (PC) sfx] */
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->frame_size = read_16bit(extradata_offset + 0x0c, streamFile);
|
||||
vgmstream->frame_size = read_16bit(extradata_offset + 0x0c, sf);
|
||||
/* WAVEFORMATEX in extradata_offset */
|
||||
if (!msadpcm_check_coefs(streamFile, extradata_offset + 0x14))
|
||||
if (!msadpcm_check_coefs(sf, extradata_offset + 0x14))
|
||||
goto fail;
|
||||
|
||||
vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, vgmstream->frame_size, vgmstream->channels);
|
||||
|
@ -282,83 +282,53 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
|
||||
case 0x0A: /* DSP ADPCM [Dragon Quest X (Wii)] */
|
||||
case 0x15: { /* DSP ADPCM [Dragon Quest X (Wii U)] (no apparent differences except higher sample rate) */
|
||||
const off_t interleave_size = 0x800;
|
||||
const off_t stride_size = interleave_size * channel_count;
|
||||
int i;
|
||||
size_t total_size;
|
||||
layered_layout_data * data = NULL;
|
||||
|
||||
/* interleaved DSPs including the header (so the first 0x800 is 0x60 header + 0x740 data)
|
||||
* so interleave layout can't used; we'll setup de-interleaving streamfiles as layers/channels instead */
|
||||
//todo this could be simplified using a block layout or adding interleave_first_block
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_layered;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x800;
|
||||
vgmstream->interleave_first_skip = 0x60;
|
||||
vgmstream->interleave_first_block_size = vgmstream->interleave_block_size - vgmstream->interleave_first_skip;
|
||||
|
||||
/* read from the first DSP header and verify other channel headers */
|
||||
{
|
||||
total_size = (read_32bitBE(start_offset+0x04,streamFile)+1)/2; /* rounded nibbles / 2 */
|
||||
vgmstream->num_samples = read_32bitBE(start_offset+0x00,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end + 1;
|
||||
}
|
||||
/* standard dsp header at start_offset */
|
||||
dsp_read_coefs_be(vgmstream, sf, start_offset+0x1c, vgmstream->interleave_block_size);
|
||||
dsp_read_hist_be(vgmstream, sf, start_offset+0x40, vgmstream->interleave_block_size);
|
||||
|
||||
for (i = 1; i < channel_count; i++) {
|
||||
if ((read_32bitBE(start_offset+4,streamFile)+1)/2 != total_size ||
|
||||
read_32bitBE(start_offset+interleave_size*i+0x00,streamFile) != vgmstream->num_samples) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
vgmstream->num_samples = read_32bit(start_offset+0x00,sf);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end + 1;
|
||||
}
|
||||
|
||||
/* init layout */
|
||||
data = init_layout_layered(channel_count);
|
||||
if (!data) goto fail;
|
||||
vgmstream->layout_data = data;
|
||||
|
||||
/* open each layer subfile */
|
||||
for (i = 0; i < channel_count; i++) {
|
||||
STREAMFILE* temp_streamFile = setup_scd_dsp_streamfile(streamFile, start_offset+interleave_size*i, interleave_size, stride_size, total_size);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
data->layers[i] = init_vgmstream_ngc_dsp_std(temp_streamFile);
|
||||
close_streamfile(temp_streamFile);
|
||||
if (!data->layers[i]) goto fail;
|
||||
}
|
||||
|
||||
/* setup layered VGMSTREAMs */
|
||||
if (!setup_layout_layered(data))
|
||||
goto fail;
|
||||
|
||||
|
||||
start_offset += vgmstream->interleave_first_skip;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x0B: { /* XMA2 [Final Fantasy (X360), Lightning Returns (X360) sfx, Kingdom Hearts 2.8 (X1)] */
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
uint8_t buf[200];
|
||||
uint8_t buf[0x100];
|
||||
int32_t bytes;
|
||||
|
||||
/* extradata_offset+0x00: fmt0x166 header (BE), extradata_offset+0x34: seek table */
|
||||
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, extradata_offset,0x34, stream_size, streamFile, 1);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,stream_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
/* extradata:
|
||||
* 0x00: fmt0x166 header (BE X360, LE XBone)
|
||||
* 0x34: seek table */
|
||||
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, extradata_offset,0x34, stream_size, sf, big_endian);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf, bytes, start_offset, stream_size);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = ffmpeg_data->totalSamples;
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end; //todo +1?
|
||||
xma2_parse_fmt_chunk_extra(sf, extradata_offset, NULL, &vgmstream->num_samples, NULL, NULL, big_endian);
|
||||
vgmstream->loop_start_sample = loop_start; /* same loops in chunk */
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
|
||||
xma_fix_raw_samples(vgmstream, streamFile, start_offset,stream_size, 0, 0,0); /* samples are ok, loops? */
|
||||
xma_fix_raw_samples(vgmstream, sf, start_offset, stream_size, extradata_offset, 1,1);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0E: { /* ATRAC3/ATRAC3plus [Lord of Arcana (PSP), Final Fantasy Type-0] */
|
||||
int fact_samples = 0;
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_riff(streamFile, start_offset, &fact_samples);
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_riff(sf, start_offset, &fact_samples);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
@ -377,17 +347,17 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
|
||||
/* post header has various typical ATRAC9 values */
|
||||
cfg.channels = vgmstream->channels;
|
||||
cfg.config_data = read_32bit(extradata_offset+0x0c,streamFile);
|
||||
cfg.encoder_delay = read_32bit(extradata_offset+0x18,streamFile);
|
||||
cfg.config_data = read_32bit(extradata_offset+0x0c,sf);
|
||||
cfg.encoder_delay = read_32bit(extradata_offset+0x18,sf);
|
||||
|
||||
vgmstream->codec_data = init_atrac9(&cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_ATRAC9;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = read_32bit(extradata_offset+0x10,streamFile); /* loop values above are also weird and ignored */
|
||||
vgmstream->loop_start_sample = read_32bit(extradata_offset+0x20, streamFile);
|
||||
vgmstream->loop_end_sample = read_32bit(extradata_offset+0x24, streamFile) + 1;
|
||||
vgmstream->num_samples = read_32bit(extradata_offset+0x10,sf); /* loop values above are also weird and ignored */
|
||||
vgmstream->loop_start_sample = read_32bit(extradata_offset+0x20, sf);
|
||||
vgmstream->loop_end_sample = read_32bit(extradata_offset+0x24, sf) + 1;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample -= cfg.encoder_delay;
|
||||
vgmstream->loop_end_sample -= cfg.encoder_delay;
|
||||
|
@ -403,7 +373,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||
}
|
||||
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
@ -415,7 +385,7 @@ fail:
|
|||
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
static void scd_ogg_v2_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
|
||||
static void scd_ogg_v2_decryption_callback(void* ptr, size_t size, size_t nmemb, void* datasource) {
|
||||
uint8_t *ptr8 = ptr;
|
||||
size_t bytes_read = size * nmemb;
|
||||
ogg_vorbis_io *io = datasource;
|
||||
|
@ -438,7 +408,7 @@ static void scd_ogg_v2_decryption_callback(void *ptr, size_t size, size_t nmemb,
|
|||
}
|
||||
}
|
||||
|
||||
static void scd_ogg_v3_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
|
||||
static void scd_ogg_v3_decryption_callback(void* ptr, size_t size, size_t nmemb, void* datasource) {
|
||||
/* V3 decryption table found in the .exe of FF XIV Heavensward */
|
||||
static const uint8_t scd_ogg_v3_lookuptable[256] = {
|
||||
0x3A, 0x32, 0x32, 0x32, 0x03, 0x7E, 0x12, 0xF7, 0xB2, 0xE2, 0xA2, 0x67, 0x32, 0x32, 0x22, 0x32, // 00-0F
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
#ifndef _SQEX_SCD_STREAMFILE_H_
|
||||
#define _SQEX_SCD_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
off_t start_physical_offset; /* interleaved data start, for this substream */
|
||||
size_t interleave_block_size; /* max size that can be read before encountering other substreams */
|
||||
size_t stride_size; /* step size between interleave blocks (interleave*channels) */
|
||||
size_t total_size; /* final size of the deinterleaved substream */
|
||||
} scd_dsp_io_data;
|
||||
|
||||
|
||||
/* Handles deinterleaving of complete files, skipping portions or other substreams. */
|
||||
static size_t scd_dsp_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, scd_dsp_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
while (length > 0) {
|
||||
size_t to_read;
|
||||
size_t length_available;
|
||||
off_t block_num;
|
||||
off_t intrablock_offset;
|
||||
off_t physical_offset;
|
||||
|
||||
block_num = offset / data->interleave_block_size;
|
||||
intrablock_offset = offset % data->interleave_block_size;
|
||||
physical_offset = data->start_physical_offset + block_num*data->stride_size + intrablock_offset;
|
||||
length_available = data->interleave_block_size - intrablock_offset;
|
||||
|
||||
if (length < length_available) {
|
||||
to_read = length;
|
||||
}
|
||||
else {
|
||||
to_read = length_available;
|
||||
}
|
||||
|
||||
if (to_read > 0) {
|
||||
size_t bytes_read;
|
||||
|
||||
bytes_read = read_streamfile(dest, physical_offset, to_read, streamfile);
|
||||
total_read += bytes_read;
|
||||
|
||||
if (bytes_read != to_read) {
|
||||
return total_read;
|
||||
}
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t scd_dsp_io_size(STREAMFILE *streamfile, scd_dsp_io_data* data) {
|
||||
return data->total_size;
|
||||
}
|
||||
|
||||
|
||||
static STREAMFILE* setup_scd_dsp_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t interleave_block_size, size_t stride_size, size_t total_size) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
scd_dsp_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(scd_dsp_io_data);
|
||||
|
||||
io_data.start_physical_offset = start_offset;
|
||||
io_data.interleave_block_size = interleave_block_size;
|
||||
io_data.stride_size = stride_size;
|
||||
io_data.total_size = total_size;
|
||||
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, scd_dsp_io_read,scd_dsp_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"dsp");
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _SCD_STREAMFILE_H_ */
|
|
@ -2,12 +2,12 @@
|
|||
#include "../layout/layout.h"
|
||||
|
||||
/* THP - Nintendo movie format found in GC/Wii games */
|
||||
VGMSTREAM* init_vgmstream_thp(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
VGMSTREAM* init_vgmstream_thp(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset, component_type_offset, component_data_offset;
|
||||
uint32_t version, max_audio_size;
|
||||
int num_components;
|
||||
int loop_flag, channel_count;
|
||||
int loop_flag, channels;
|
||||
int i;
|
||||
|
||||
|
||||
|
@ -15,14 +15,14 @@ VGMSTREAM* init_vgmstream_thp(STREAMFILE *streamFile) {
|
|||
/* .thp: actual extension
|
||||
* .dsp: fake extension?
|
||||
* (extensionless): Fragile (Wii) */
|
||||
if (!check_extensions(streamFile, "thp,dsp,"))
|
||||
if (!check_extensions(sf, "thp,dsp,"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x54485000) /* "THP\0" */
|
||||
if (!is_id32be(0x00,sf, "THP\0"))
|
||||
goto fail;
|
||||
|
||||
version = read_32bitBE(0x04,streamFile); /* 16b+16b major/minor */
|
||||
version = read_u32be(0x04,sf); /* 16b+16b major/minor */
|
||||
/* 0x08: max buffer size */
|
||||
max_audio_size = read_32bitBE(0x0C,streamFile);
|
||||
max_audio_size = read_u32be(0x0C,sf);
|
||||
/* 0x10: fps in float */
|
||||
/* 0x14: block count */
|
||||
/* 0x18: first block size */
|
||||
|
@ -33,19 +33,19 @@ VGMSTREAM* init_vgmstream_thp(STREAMFILE *streamFile) {
|
|||
if (max_audio_size == 0) /* no sound */
|
||||
goto fail;
|
||||
|
||||
component_type_offset = read_32bitBE(0x20,streamFile);
|
||||
component_type_offset = read_u32be(0x20,sf);
|
||||
/* 0x24: block offsets table offset (optional, for seeking) */
|
||||
start_offset = read_32bitBE(0x28,streamFile);
|
||||
start_offset = read_u32be(0x28,sf);
|
||||
/* 0x2c: last block offset */
|
||||
|
||||
/* first component "type" x16 then component headers */
|
||||
num_components = read_32bitBE(component_type_offset,streamFile);
|
||||
num_components = read_u32be(component_type_offset,sf);
|
||||
component_type_offset += 0x04;
|
||||
component_data_offset = component_type_offset + 0x10;
|
||||
|
||||
/* parse "component" (data that goes into blocks) */
|
||||
for (i = 0; i < num_components; i++) {
|
||||
int type = read_8bit(component_type_offset + i,streamFile);
|
||||
int type = read_u8(component_type_offset + i,sf);
|
||||
|
||||
if (type == 0x00) { /* video */
|
||||
if (version == 0x00010000)
|
||||
|
@ -73,24 +73,24 @@ VGMSTREAM* init_vgmstream_thp(STREAMFILE *streamFile) {
|
|||
* adjusted, but we can't detect Wii (non adjusted) .thp tho */
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = read_32bitBE(component_data_offset + 0x00,streamFile);
|
||||
channels = read_u32be(component_data_offset + 0x00,sf);
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitBE(component_data_offset + 0x04,streamFile);
|
||||
vgmstream->num_samples = read_32bitBE(component_data_offset + 0x08,streamFile);
|
||||
vgmstream->sample_rate = read_u32be(component_data_offset + 0x04,sf);
|
||||
vgmstream->num_samples = read_u32be(component_data_offset + 0x08,sf);
|
||||
|
||||
vgmstream->meta_type = meta_THP;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_blocked_thp;
|
||||
/* coefs are in every block */
|
||||
|
||||
vgmstream->full_block_size = read_32bitBE(0x18,streamFile); /* next block size */
|
||||
vgmstream->full_block_size = read_u32be(0x18,sf); /* next block size */
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
|
|
|
@ -599,75 +599,32 @@ fail:
|
|||
}
|
||||
|
||||
|
||||
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* sf) {
|
||||
STREAMFILE* temp_sf = NULL, *new_sf = NULL;
|
||||
|
||||
/* setup custom streamfile */
|
||||
new_sf = open_wrap_streamfile(sf);
|
||||
if (!new_sf) goto fail;
|
||||
temp_sf = new_sf;
|
||||
|
||||
new_sf = open_io_streamfile(temp_sf, NULL,0, silence_io_read,silence_io_size);
|
||||
if (!new_sf) goto fail;
|
||||
temp_sf = new_sf;
|
||||
|
||||
return temp_sf;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_sf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static VGMSTREAM* init_vgmstream_ubi_bao_silence(ubi_bao_header* bao, STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
int channel_count, sample_rate;
|
||||
int channels, sample_rate;
|
||||
int32_t num_samples;
|
||||
|
||||
channel_count = bao->channels;
|
||||
/* by default silences don't have settings */
|
||||
channels = bao->channels;
|
||||
if (channels == 0)
|
||||
channels = 2;
|
||||
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;
|
||||
num_samples = bao->duration * sample_rate;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, 0);
|
||||
/* init the VGMSTREAM */
|
||||
vgmstream = init_vgmstream_silence(channels, sample_rate, num_samples);
|
||||
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_sf = setup_silence_streamfile(sf);
|
||||
if ( !vgmstream_open_stream(vgmstream, temp_sf, 0x00) )
|
||||
goto fail;
|
||||
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
}
|
||||
|
||||
|
|
|
@ -1526,74 +1526,33 @@ fail:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static size_t silence_io_read(STREAMFILE* sf, 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* sf, void* data) {
|
||||
return 0x7FFFFFF; /* whatevs */
|
||||
}
|
||||
static STREAMFILE* setup_silence_streamfile(STREAMFILE* sf) {
|
||||
STREAMFILE *temp_sf = NULL, *new_sf = NULL;
|
||||
|
||||
/* setup custom streamfile */
|
||||
new_sf = open_wrap_streamfile(sf);
|
||||
if (!new_sf) goto fail;
|
||||
temp_sf = new_sf;
|
||||
|
||||
new_sf = open_io_streamfile(temp_sf, NULL,0, silence_io_read,silence_io_size);
|
||||
if (!new_sf) goto fail;
|
||||
temp_sf = new_sf;
|
||||
|
||||
return temp_sf;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_sf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static VGMSTREAM* init_vgmstream_ubi_sb_silence(ubi_sb_header* sb, STREAMFILE* sf_index, STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
int channel_count, sample_rate;
|
||||
int channels, sample_rate;
|
||||
int32_t num_samples;
|
||||
|
||||
channel_count = sb->channels;
|
||||
/* by default silences don't have settings */
|
||||
channels = sb->channels;
|
||||
if (channels == 0)
|
||||
channels = 2;
|
||||
sample_rate = sb->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;
|
||||
num_samples = sb->duration * sample_rate;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, 0);
|
||||
/* init the VGMSTREAM */
|
||||
vgmstream = init_vgmstream_silence(channels, sample_rate, num_samples);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_UBI_SB;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
vgmstream->num_samples = (int32_t)(sb->duration * (float)sample_rate);
|
||||
vgmstream->num_streams = sb->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_sf = setup_silence_streamfile(sf);
|
||||
if ( !vgmstream_open_stream(vgmstream, temp_sf, 0x00) )
|
||||
goto fail;
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,62 +1,61 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* UE4OPUS - from Unreal Engine 4 games [ARK: Survival Evolved (PC), Fortnite (PC)] */
|
||||
VGMSTREAM * init_vgmstream_ue4opus(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag = 0, channel_count, sample_rate, num_samples, skip;
|
||||
size_t data_size;
|
||||
|
||||
|
||||
/* checks*/
|
||||
/* .opus/lopus: possible real extension
|
||||
* .ue4opus: header id */
|
||||
if (!check_extensions(streamFile, "opus,lopus,ue4opus"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00, streamFile) != 0x5545344F && /* "UE4O" */
|
||||
read_32bitBE(0x00, streamFile) != 0x50555300) /* "PUS\0" */
|
||||
goto fail;
|
||||
|
||||
|
||||
sample_rate = (uint16_t)read_16bitLE(0x08, streamFile);
|
||||
num_samples = read_32bitLE(0x0a, streamFile); /* may be less or equal to file num_samples */
|
||||
channel_count = read_8bit(0x0e, streamFile);
|
||||
/* 0x0f(2): frame count */
|
||||
loop_flag = 0;
|
||||
|
||||
start_offset = 0x11;
|
||||
data_size = get_streamfile_size(streamFile) - start_offset;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_UE4OPUS;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
{
|
||||
/* usually uses 60ms for music (delay of 360 samples) */
|
||||
skip = ue4_opus_get_encoder_delay(start_offset, streamFile);
|
||||
vgmstream->num_samples = num_samples - skip;
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_ue4_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;
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* UE4OPUS - from Unreal Engine 4 games [ARK: Survival Evolved (PC), Fortnite (PC)] */
|
||||
VGMSTREAM * init_vgmstream_ue4opus(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag = 0, channels, sample_rate, num_samples, skip;
|
||||
size_t data_size;
|
||||
|
||||
|
||||
/* checks*/
|
||||
/* .opus/lopus: possible real extension
|
||||
* .ue4opus: header id */
|
||||
if (!check_extensions(sf, "opus,lopus,ue4opus"))
|
||||
goto fail;
|
||||
if (!is_id64be(0x00, sf, "UE4OPUS\0"))
|
||||
goto fail;
|
||||
|
||||
|
||||
sample_rate = read_u16le(0x08, sf);
|
||||
num_samples = read_s32le(0x0a, sf); /* may be less or equal to file num_samples */
|
||||
channels = read_u8(0x0e, sf);
|
||||
/* 0x0f(2): frame count */
|
||||
loop_flag = 0;
|
||||
|
||||
start_offset = 0x11;
|
||||
data_size = get_streamfile_size(sf) - start_offset;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_UE4OPUS;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
{
|
||||
/* usually uses 60ms for music (delay of 360 samples) */
|
||||
skip = ue4_opus_get_encoder_delay(start_offset, sf);
|
||||
vgmstream->num_samples = num_samples - skip;
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_ue4_opus(sf, 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;
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -532,3 +532,17 @@ void vgmstream_mixing_autodownmix(VGMSTREAM *vgmstream, int max_channels) {
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
void vgmstream_mixing_stereo_only(VGMSTREAM *vgmstream, int start) {
|
||||
if (start < 0)
|
||||
return;
|
||||
/* could check to avoid making mono files in edge cases but meh */
|
||||
|
||||
/* remove channels before start */
|
||||
while (start) {
|
||||
mixing_push_downmix(vgmstream, 0);
|
||||
start--;
|
||||
}
|
||||
/* remove channels after stereo */
|
||||
mixing_push_killmix(vgmstream, start + 2);
|
||||
}
|
||||
|
|
|
@ -215,7 +215,10 @@ void vgmstream_tags_close(VGMSTREAM_TAGS* tags);
|
|||
void vgmstream_mixing_enable(VGMSTREAM* vgmstream, int32_t max_sample_count, int *input_channels, int *output_channels);
|
||||
|
||||
/* sets automatic downmixing if vgmstream's channels are higher than max_channels */
|
||||
void vgmstream_mixing_autodownmix(VGMSTREAM *vgmstream, int max_channels);
|
||||
void vgmstream_mixing_autodownmix(VGMSTREAM* vgmstream, int max_channels);
|
||||
|
||||
/* downmixes to get stereo from start channel */
|
||||
void vgmstream_mixing_stereo_only(VGMSTREAM* vgmstream, int start);
|
||||
|
||||
/* sets a fadeout */
|
||||
//void vgmstream_mixing_fadeout(VGMSTREAM *vgmstream, float start_second, float duration_seconds);
|
||||
|
|
|
@ -1123,9 +1123,14 @@ fail:
|
|||
}
|
||||
|
||||
STREAMFILE* read_filemap_file(STREAMFILE* sf, int file_num) {
|
||||
return read_filemap_file_pos(sf, file_num, NULL);
|
||||
}
|
||||
|
||||
STREAMFILE* read_filemap_file_pos(STREAMFILE* sf, int file_num, int* p_pos) {
|
||||
char filename[PATH_LIMIT];
|
||||
off_t txt_offset, file_size;
|
||||
STREAMFILE* sf_map = NULL;
|
||||
int file_pos = 0;
|
||||
|
||||
sf_map = open_streamfile_by_filename(sf, ".txtm");
|
||||
if (!sf_map) goto fail;
|
||||
|
@ -1136,10 +1141,10 @@ STREAMFILE* read_filemap_file(STREAMFILE* sf, int file_num) {
|
|||
file_size = get_streamfile_size(sf_map);
|
||||
|
||||
/* skip BOM if needed */
|
||||
if ((uint16_t)read_16bitLE(0x00, sf_map) == 0xFFFE ||
|
||||
(uint16_t)read_16bitLE(0x00, sf_map) == 0xFEFF) {
|
||||
if (read_u16le(0x00, sf_map) == 0xFFFE ||
|
||||
read_u16le(0x00, sf_map) == 0xFEFF) {
|
||||
txt_offset = 0x02;
|
||||
} else if (((uint32_t)read_32bitBE(0x00, sf_map) & 0xFFFFFF00) == 0xEFBBBF00) {
|
||||
} else if ((read_u32be(0x00, sf_map) & 0xFFFFFF00) == 0xEFBBBF00) {
|
||||
txt_offset = 0x03;
|
||||
}
|
||||
|
||||
|
@ -1174,8 +1179,9 @@ STREAMFILE* read_filemap_file(STREAMFILE* sf, int file_num) {
|
|||
if (ok != 1)
|
||||
goto fail;
|
||||
|
||||
if (i == file_num)
|
||||
{
|
||||
if (i == file_num) {
|
||||
if (p_pos) *p_pos = file_pos;
|
||||
|
||||
close_streamfile(sf_map);
|
||||
return open_streamfile_by_filename(sf, subval);
|
||||
}
|
||||
|
@ -1185,6 +1191,7 @@ STREAMFILE* read_filemap_file(STREAMFILE* sf, int file_num) {
|
|||
current++;
|
||||
}
|
||||
}
|
||||
file_pos++;
|
||||
}
|
||||
|
||||
fail:
|
||||
|
|
|
@ -361,7 +361,9 @@ size_t read_key_file(uint8_t* buf, size_t buf_size, STREAMFILE* sf);
|
|||
|
||||
/* Opens .txtm file containing file:companion file(-s) mappings and tries to see if there's a match
|
||||
* then loads the associated companion file if one is found */
|
||||
STREAMFILE *read_filemap_file(STREAMFILE *sf, int file_num);
|
||||
STREAMFILE* read_filemap_file(STREAMFILE *sf, int file_num);
|
||||
STREAMFILE* read_filemap_file_pos(STREAMFILE *sf, int file_num, int* p_pos);
|
||||
|
||||
|
||||
/* hack to allow relative paths in various OSs */
|
||||
void fix_dir_separators(char* filename);
|
||||
|
|
|
@ -40,12 +40,11 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
|||
init_vgmstream_rfrm,
|
||||
init_vgmstream_cstr,
|
||||
init_vgmstream_gcsw,
|
||||
init_vgmstream_ps2_ads,
|
||||
init_vgmstream_ads,
|
||||
init_vgmstream_nps,
|
||||
init_vgmstream_rwsd,
|
||||
init_vgmstream_xa,
|
||||
init_vgmstream_ps2_rxws,
|
||||
init_vgmstream_ps2_rxw,
|
||||
init_vgmstream_rxws,
|
||||
init_vgmstream_ngc_dsp_stm,
|
||||
init_vgmstream_exst,
|
||||
init_vgmstream_svag_kcet,
|
||||
|
@ -194,7 +193,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
|||
init_vgmstream_nds_rrds,
|
||||
init_vgmstream_ps2_tk5,
|
||||
init_vgmstream_ps2_vsf_tta,
|
||||
init_vgmstream_ads,
|
||||
init_vgmstream_ads_midway,
|
||||
init_vgmstream_ps2_mcg,
|
||||
init_vgmstream_zsd,
|
||||
init_vgmstream_ps2_vgs,
|
||||
|
@ -262,11 +261,9 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
|||
init_vgmstream_sqex_scd,
|
||||
init_vgmstream_ngc_nst_dsp,
|
||||
init_vgmstream_baf,
|
||||
init_vgmstream_baf_badrip,
|
||||
init_vgmstream_msf,
|
||||
init_vgmstream_ps3_past,
|
||||
init_vgmstream_sgxd,
|
||||
init_vgmstream_ngca,
|
||||
init_vgmstream_wii_ras,
|
||||
init_vgmstream_ps2_spm,
|
||||
init_vgmstream_x360_tra,
|
||||
|
@ -395,7 +392,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
|||
init_vgmstream_dsp_switch_audio,
|
||||
init_vgmstream_sadf,
|
||||
init_vgmstream_h4m,
|
||||
init_vgmstream_ps2_ads_container,
|
||||
init_vgmstream_ads_container,
|
||||
init_vgmstream_asf,
|
||||
init_vgmstream_xmd,
|
||||
init_vgmstream_cks,
|
||||
|
@ -539,6 +536,8 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
|||
init_vgmstream_s14_sss, /* .s14/sss raw siren14 */
|
||||
init_vgmstream_raw_al, /* .al/al2 raw A-LAW */
|
||||
init_vgmstream_zwdsp, /* fake format */
|
||||
init_vgmstream_baf_badrip, /* crap, to be removed */
|
||||
init_vgmstream_rxws_badrip, /* crap, to be removed */
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
init_vgmstream_ffmpeg, /* may play anything incorrectly, since FFmpeg doesn't check extensions */
|
||||
#endif
|
||||
|
@ -1409,7 +1408,7 @@ static int get_vgmstream_file_bitrate_from_streamfile(STREAMFILE* sf, int sample
|
|||
return get_vgmstream_file_bitrate_from_size(get_streamfile_size(sf), sample_rate, length_samples);
|
||||
}
|
||||
|
||||
static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t* br) {
|
||||
static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t* br, int* p_uniques) {
|
||||
int i, ch;
|
||||
int bitrate = 0;
|
||||
|
||||
|
@ -1423,15 +1422,18 @@ static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t*
|
|||
* become a bit high since its hard to detect only part of the file is needed. */
|
||||
|
||||
if (vgmstream->layout_type == layout_segmented) {
|
||||
int uniques = 0;
|
||||
segmented_layout_data *data = (segmented_layout_data *) vgmstream->layout_data;
|
||||
for (i = 0; i < data->segment_count; i++) {
|
||||
bitrate += get_vgmstream_file_bitrate_main(data->segments[i], br);
|
||||
bitrate += get_vgmstream_file_bitrate_main(data->segments[i], br, &uniques);
|
||||
}
|
||||
if (uniques)
|
||||
bitrate /= uniques; /* average */
|
||||
}
|
||||
else if (vgmstream->layout_type == layout_layered) {
|
||||
layered_layout_data *data = vgmstream->layout_data;
|
||||
for (i = 0; i < data->layer_count; i++) {
|
||||
bitrate += get_vgmstream_file_bitrate_main(data->layers[i], br);
|
||||
bitrate += get_vgmstream_file_bitrate_main(data->layers[i], br, NULL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -1467,6 +1469,8 @@ static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t*
|
|||
br->subsong[br->count] = subsong_cur;
|
||||
|
||||
br->count++;
|
||||
if (p_uniques)
|
||||
(*p_uniques)++;
|
||||
|
||||
if (vgmstream->stream_size) {
|
||||
/* stream_size applies to both channels but should add once and detect repeats (for current subsong) */
|
||||
|
@ -1494,7 +1498,7 @@ int get_vgmstream_average_bitrate(VGMSTREAM* vgmstream) {
|
|||
bitrate_info_t br = {0};
|
||||
br.count_max = BITRATE_FILES_MAX;
|
||||
|
||||
return get_vgmstream_file_bitrate_main(vgmstream, &br);
|
||||
return get_vgmstream_file_bitrate_main(vgmstream, &br, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -362,9 +362,9 @@ typedef enum {
|
|||
meta_BNSF, /* Bandai Namco Sound Format */
|
||||
|
||||
meta_XA, /* CD-ROM XA */
|
||||
meta_PS2_SShd, /* .ADS with SShd header */
|
||||
meta_ADS,
|
||||
meta_NPS,
|
||||
meta_PS2_RXWS, /* Sony games (Genji, Okage Shadow King, Arc The Lad Twilight of Spirits) */
|
||||
meta_RXWS,
|
||||
meta_RAW_INT,
|
||||
meta_EXST,
|
||||
meta_SVAG_KCET,
|
||||
|
@ -460,7 +460,7 @@ typedef enum {
|
|||
meta_SAT_BAKA, /* Crypt Killer */
|
||||
meta_VSF,
|
||||
meta_PS2_VSF_TTA, /* Tiny Toon Adventures: Defenders of the Universe */
|
||||
meta_ADS, /* Gauntlet Dark Legends (GC) */
|
||||
meta_ADS_MIDWAY,
|
||||
meta_PS2_SPS, /* Ape Escape 2 */
|
||||
meta_PS2_XA2_RRP, /* RC Revenge Pro */
|
||||
meta_NGC_DSP_KONAMI, /* Konami DSP header, found in various games */
|
||||
|
@ -568,7 +568,6 @@ typedef enum {
|
|||
meta_MSF,
|
||||
meta_PS3_PAST, /* Bakugan Battle Brawlers (PS3) */
|
||||
meta_SGXD, /* Sony: Folklore, Genji, Tokyo Jungle (PS3), Brave Story, Kurohyo (PSP) */
|
||||
meta_NGCA, /* GoldenEye 007 (Wii) */
|
||||
meta_WII_RAS, /* Donkey Kong Country Returns (Wii) */
|
||||
meta_PS2_SPM, /* Lethal Skies Elite Pilot: Team SW */
|
||||
meta_X360_TRA, /* Def Jam Rapstar */
|
||||
|
|
Loading…
Reference in New Issue