VGMStream: Updated libvgmstream code base

Updated VGMStream to r2023-112-g5b92c84e

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2025-08-04 17:47:51 -07:00
parent ecfbee6f53
commit e0be2497c0
33 changed files with 1670 additions and 1250 deletions

View file

@ -60,7 +60,7 @@
8306B0E920984590000302D4 /* opus.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0CE2098458E000302D4 /* opus.c */; };
8306B0EA20984590000302D4 /* caf.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0CF2098458F000302D4 /* caf.c */; };
8306B0EB20984590000302D4 /* wave_segmented.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0D02098458F000302D4 /* wave_segmented.c */; };
8306B0EC20984590000302D4 /* pcm_sre.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0D12098458F000302D4 /* pcm_sre.c */; };
8306B0EC20984590000302D4 /* sre_pcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0D12098458F000302D4 /* sre_pcm.c */; };
8306B0ED20984590000302D4 /* txtp.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0D22098458F000302D4 /* txtp.c */; };
8306B0EE20984590000302D4 /* smh_smc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0D32098458F000302D4 /* smh_smc.c */; };
8306B0EF20984590000302D4 /* ubi_bao.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B0D420984590000302D4 /* ubi_bao.c */; };
@ -537,8 +537,7 @@
836F6FB118BDC2190095E648 /* str_sqex.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7518BDC2180095E648 /* str_sqex.c */; };
836F6FB318BDC2190095E648 /* lps.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7718BDC2180095E648 /* lps.c */; };
836F6FB418BDC2190095E648 /* nst_monster.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7818BDC2180095E648 /* nst_monster.c */; };
836F6FB518BDC2190095E648 /* ngc_pdt.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7918BDC2180095E648 /* ngc_pdt.c */; };
836F6FB618BDC2190095E648 /* ngc_sck_dsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7A18BDC2180095E648 /* ngc_sck_dsp.c */; };
836F6FB518BDC2190095E648 /* pdt.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7918BDC2180095E648 /* pdt.c */; };
836F6FB718BDC2190095E648 /* ngc_ssm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7B18BDC2180095E648 /* ngc_ssm.c */; };
836F6FBA18BDC2190095E648 /* ymf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7E18BDC2180095E648 /* ymf.c */; };
836F6FBD18BDC2190095E648 /* nwa.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8118BDC2180095E648 /* nwa.c */; };
@ -549,7 +548,6 @@
836F6FC918BDC2190095E648 /* 2pfs.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8D18BDC2180095E648 /* 2pfs.c */; };
836F6FCA18BDC2190095E648 /* ps2_adm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8E18BDC2180095E648 /* ps2_adm.c */; };
836F6FCB18BDC2190095E648 /* ads.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8F18BDC2180095E648 /* ads.c */; };
836F6FCD18BDC2190095E648 /* ps2_ass.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9118BDC2180095E648 /* ps2_ass.c */; };
836F6FD018BDC2190095E648 /* ps2_b1s.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9418BDC2180095E648 /* ps2_b1s.c */; };
836F6FD118BDC2190095E648 /* bg00.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9518BDC2180095E648 /* bg00.c */; };
836F6FD218BDC2190095E648 /* ps2_bmdx.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9618BDC2180095E648 /* ps2_bmdx.c */; };
@ -782,6 +780,7 @@
83BB84032DF2D125002077FC /* rwar.c in Sources */ = {isa = PBXBuildFile; fileRef = 83BB84022DF2D125002077FC /* rwar.c */; };
83BB84062DF2D1C2002077FC /* ivb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83BB84042DF2D1C2002077FC /* ivb.c */; };
83BB84072DF2D1C2002077FC /* ivb_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BB84052DF2D1C2002077FC /* ivb_streamfile.h */; };
83BDCD932E418A8F003FC007 /* awb_aac_encryption_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BDCD922E418A8F003FC007 /* awb_aac_encryption_streamfile.h */; };
83C0C75D2AA435C60056AFD8 /* squeak.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C0C75C2AA435C60056AFD8 /* squeak.c */; };
83C0C7602AA436370056AFD8 /* layout_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C0C75E2AA436370056AFD8 /* layout_utils.c */; };
83C0C7612AA436370056AFD8 /* layout_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C0C75F2AA436370056AFD8 /* layout_utils.h */; };
@ -1020,7 +1019,7 @@
8306B0CE2098458E000302D4 /* opus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = opus.c; sourceTree = "<group>"; };
8306B0CF2098458F000302D4 /* caf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = caf.c; sourceTree = "<group>"; };
8306B0D02098458F000302D4 /* wave_segmented.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wave_segmented.c; sourceTree = "<group>"; };
8306B0D12098458F000302D4 /* pcm_sre.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pcm_sre.c; sourceTree = "<group>"; };
8306B0D12098458F000302D4 /* sre_pcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sre_pcm.c; sourceTree = "<group>"; };
8306B0D22098458F000302D4 /* txtp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = txtp.c; sourceTree = "<group>"; };
8306B0D32098458F000302D4 /* smh_smc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = smh_smc.c; sourceTree = "<group>"; };
8306B0D420984590000302D4 /* ubi_bao.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ubi_bao.c; sourceTree = "<group>"; };
@ -1497,8 +1496,7 @@
836F6E7518BDC2180095E648 /* str_sqex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = str_sqex.c; sourceTree = "<group>"; };
836F6E7718BDC2180095E648 /* lps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lps.c; sourceTree = "<group>"; };
836F6E7818BDC2180095E648 /* nst_monster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nst_monster.c; sourceTree = "<group>"; };
836F6E7918BDC2180095E648 /* ngc_pdt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_pdt.c; sourceTree = "<group>"; };
836F6E7A18BDC2180095E648 /* ngc_sck_dsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_sck_dsp.c; sourceTree = "<group>"; };
836F6E7918BDC2180095E648 /* pdt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pdt.c; sourceTree = "<group>"; };
836F6E7B18BDC2180095E648 /* ngc_ssm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_ssm.c; sourceTree = "<group>"; };
836F6E7E18BDC2180095E648 /* ymf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ymf.c; sourceTree = "<group>"; };
836F6E8118BDC2180095E648 /* nwa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nwa.c; sourceTree = "<group>"; };
@ -1509,7 +1507,6 @@
836F6E8D18BDC2180095E648 /* 2pfs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = 2pfs.c; sourceTree = "<group>"; };
836F6E8E18BDC2180095E648 /* ps2_adm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_adm.c; sourceTree = "<group>"; };
836F6E8F18BDC2180095E648 /* ads.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ads.c; sourceTree = "<group>"; };
836F6E9118BDC2180095E648 /* ps2_ass.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_ass.c; sourceTree = "<group>"; };
836F6E9418BDC2180095E648 /* ps2_b1s.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_b1s.c; sourceTree = "<group>"; };
836F6E9518BDC2180095E648 /* bg00.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bg00.c; sourceTree = "<group>"; };
836F6E9618BDC2180095E648 /* ps2_bmdx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_bmdx.c; sourceTree = "<group>"; };
@ -1744,6 +1741,7 @@
83BB84022DF2D125002077FC /* rwar.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = rwar.c; sourceTree = "<group>"; };
83BB84042DF2D1C2002077FC /* ivb.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ivb.c; sourceTree = "<group>"; };
83BB84052DF2D1C2002077FC /* ivb_streamfile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ivb_streamfile.h; sourceTree = "<group>"; };
83BDCD922E418A8F003FC007 /* awb_aac_encryption_streamfile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = awb_aac_encryption_streamfile.h; sourceTree = "<group>"; };
83C0C75C2AA435C60056AFD8 /* squeak.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = squeak.c; sourceTree = "<group>"; };
83C0C75E2AA436370056AFD8 /* layout_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = layout_utils.c; sourceTree = "<group>"; };
83C0C75F2AA436370056AFD8 /* layout_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = layout_utils.h; sourceTree = "<group>"; };
@ -2354,6 +2352,7 @@
838A6FF02DCF0850009CBEE7 /* audiopkg_streamfile.h */,
83EED5D2203A8BC7008BEB45 /* aus.c */,
83A16D2722D2ADE700B90C4C /* awb.c */,
83BDCD922E418A8F003FC007 /* awb_aac_encryption_streamfile.h */,
83AA5D201F6E2F9B0020821C /* awc.c */,
834F7D162C708700003AC386 /* awc_decryption_streamfile.h */,
834F7D172C708701003AC386 /* awc_streamfile.h */,
@ -2557,8 +2556,6 @@
836F6E6D18BDC2180095E648 /* ngc_adpdtk.c */,
834F7D322C70932C003AC386 /* ngc_dsp_asura.c */,
836F6E7318BDC2180095E648 /* ngc_dsp_std.c */,
836F6E7918BDC2180095E648 /* ngc_pdt.c */,
836F6E7A18BDC2180095E648 /* ngc_sck_dsp.c */,
836F6E7B18BDC2180095E648 /* ngc_ssm.c */,
8306B0BE2098458C000302D4 /* ngc_str_cauldron.c */,
83C727FC22BC893900678B4A /* npsf.c */,
@ -2587,8 +2584,8 @@
8349A8FE1FE6257F00E26435 /* pc_adp_otns.c */,
836F6E8618BDC2180095E648 /* pc_mxst.c */,
8349A8F21FE6257D00E26435 /* pcm_kceje.c */,
8306B0D12098458F000302D4 /* pcm_sre.c */,
83D20076248DDB770048BD24 /* pcm_success.c */,
836F6E7918BDC2180095E648 /* pdt.c */,
834FBCE926BBC7E50095647F /* piff_tpcm.c */,
836F6E8B18BDC2180095E648 /* pona.c */,
836F6E8C18BDC2180095E648 /* pos.c */,
@ -2597,7 +2594,6 @@
8306B0C52098458D000302D4 /* ppst_streamfile.h */,
834FE0D5215C79E9000A5D3D /* ps_headerless.c */,
836F6E8E18BDC2180095E648 /* ps2_adm.c */,
836F6E9118BDC2180095E648 /* ps2_ass.c */,
836F6E9418BDC2180095E648 /* ps2_b1s.c */,
836F6E9618BDC2180095E648 /* ps2_bmdx.c */,
836F6E9F18BDC2180095E648 /* ps2_hsf.c */,
@ -2685,6 +2681,7 @@
837CEAF023487F2C00E62A4A /* sqex_streamfile.h */,
83C0C75C2AA435C60056AFD8 /* squeak.c */,
832F9EA52E29047F00D08728 /* srcd.c */,
8306B0D12098458F000302D4 /* sre_pcm.c */,
834FE0D6215C79E9000A5D3D /* sscf.c */,
8396BE792935FC2F00CD0580 /* sscf_encrypted.h */,
8396BE782935FC2F00CD0580 /* sscf_encrypted.c */,
@ -3056,6 +3053,7 @@
8306B0E820984590000302D4 /* opus_interleave_streamfile.h in Headers */,
83031EDD243C510500C3F3E0 /* xnb_streamfile.h in Headers */,
83D2007B248DDB770048BD24 /* mups_streamfile.h in Headers */,
83BDCD932E418A8F003FC007 /* awb_aac_encryption_streamfile.h in Headers */,
834F7E912C70A1AB003AC386 /* vgmstream_init.h in Headers */,
83256CCC28666C620036D9C0 /* init_layer12.h in Headers */,
83AFABBD23795202002F3947 /* ea_eaac_opus_streamfile.h in Headers */,
@ -3301,7 +3299,6 @@
83FF0EBC1E93282100C58054 /* wwise.c in Sources */,
836F46B42820874D005B9B87 /* adm.c in Sources */,
836F6F7018BDC2190095E648 /* apple_caff.c in Sources */,
836F6FB618BDC2190095E648 /* ngc_sck_dsp.c in Sources */,
837CEB072348809400E62A4A /* seb.c in Sources */,
83D26A8126E66DC2001A9475 /* log.c in Sources */,
8306B0DD20984590000302D4 /* waf.c in Sources */,
@ -3428,7 +3425,7 @@
834F7E082C7093EA003AC386 /* vorbis_custom_utils_vid1.c in Sources */,
83F0AA5F21E2028C004BBC04 /* smp.c in Sources */,
833A7A2E1ED11961003EC53E /* xau.c in Sources */,
836F6FB518BDC2190095E648 /* ngc_pdt.c in Sources */,
836F6FB518BDC2190095E648 /* pdt.c in Sources */,
832BF81E21E0514B006F50F1 /* xps.c in Sources */,
837CEAFD23487F2C00E62A4A /* psf.c in Sources */,
836F6F6C18BDC2190095E648 /* ahx.c in Sources */,
@ -3634,7 +3631,6 @@
831BA61F1EAC61A500CF89B0 /* cxs.c in Sources */,
83CBF5432D46339200AA2D75 /* skex.c in Sources */,
834F7E182C709A1D003AC386 /* ea_schl_standard.c in Sources */,
836F6FCD18BDC2190095E648 /* ps2_ass.c in Sources */,
83B73C252D8FEC3A00A57F08 /* oor_helpers.c in Sources */,
83CBF5412D4631F300AA2D75 /* i3ds.c in Sources */,
8349A90B1FE6258200E26435 /* pcm_kceje.c in Sources */,
@ -3672,7 +3668,7 @@
8306B0AB20984552000302D4 /* layered.c in Sources */,
834F7DB62C7093EA003AC386 /* compresswave_lib.c in Sources */,
834F7E042C7093EA003AC386 /* vorbis_custom_utils_awc.c in Sources */,
8306B0EC20984590000302D4 /* pcm_sre.c in Sources */,
8306B0EC20984590000302D4 /* sre_pcm.c in Sources */,
832F9EA62E29047F00D08728 /* srcd.c in Sources */,
836F6FC818BDC2190095E648 /* pos.c in Sources */,
836F6F8918BDC2190095E648 /* gca.c in Sources */,

View file

@ -77,7 +77,6 @@ static const char* extension_list[] = {
"asd",
"asf",
"asr",
"ass",
"ast",
"at3",
"at9",
@ -95,6 +94,7 @@ static const char* extension_list[] = {
"awb",
"awc",
"awd",
"awx",
"b1s", //txth/reserved [7 Wonders of the Ancient World (PS2)]
"baf",
@ -116,6 +116,7 @@ static const char* extension_list[] = {
"binka", //FFmpeg/not parsed (BINK AUDIO)
//"bin", //common
"bk2",
"bkh",
"bkr", //txth/reserved [P.N.03 (GC), Viewtiful Joe (GC)]
"blk",
"bmdx", //fake extension (to be removed?)
@ -149,11 +150,14 @@ static const char* extension_list[] = {
"cnk",
"cpk",
"cps",
"crd",
"csa", //txth/reserved [LEGO Racers 2 (PS2)]
"csb",
"csmp",
"cvs", //txth/reserved [Aladdin in Nasira's Revenge (PS1)]
"cwav",
"cxb",
"cxk", // ,acb+cpk/reserved [Dariusburst: Another Chronicle (AC)]
"cxs",
"d2", //txth/reserved [Dodonpachi Dai-Ou-Jou (PS2)]
@ -170,12 +174,14 @@ static const char* extension_list[] = {
"dic",
"diva",
"dmsg", //fake extension/header id for .sgt (to be removed)
"drm", //txth/reserved [Ben 10 (HyperScan), IWL (HyperScan)]
"ds2", //txth/reserved [Star Wars Bounty Hunter (GC)]
"dsb",
"dsf",
"dsp",
"dspw",
"dtk",
"dty",
"dvi",
"dyx", //txth/reserved [Shrek 4 (iOS)]
@ -347,7 +353,7 @@ static const char* extension_list[] = {
"mds",
"mdsp",
"med",
"mhwk",
"mhk",
"mjb",
"mi4", //fake extension for .mib (renamed, to be removed)
"mib",
@ -356,6 +362,7 @@ static const char* extension_list[] = {
"mogg",
//"m4a", //common
//"m4v", //common
"mon",
//"mov", //common
"move",
//"mp+", //common [Moonshine Runners (PC)]
@ -449,6 +456,7 @@ static const char* extension_list[] = {
"psf",
"psh", //fake extension for .vsv (to be removed)
"psn",
"pth",
"pwb",
"qwv", //txth/reserved [Bishi Bashi Champ Online (AC)]
@ -553,19 +561,22 @@ static const char* extension_list[] = {
"snz", //txth/reserved [Killzone HD (PS3)]
"sod",
"son",
"spd",
"spc",
"sph",
"spt",
"spm",
"sps",
"spsd",
"spw",
"srsa",
"srcd",
"sre",
"srsa",
"ss2",
"ssd", //txth/reserved [Zack & Wiki (Wii)]
"ssf",
"ssm",
"sspr",
"ssp",
"sspr",
"sss",
"ster",
"sth",
@ -686,6 +697,7 @@ static const char* extension_list[] = {
"wvs",
"wvx",
"wxd",
"wxv",
"x",
"x360audio", //fake extension for Unreal Engine 3 XMA (real extension unknown)
@ -1070,7 +1082,7 @@ static const meta_info meta_info_list[] = {
{meta_PWB, "Double Fine WB header"},
{meta_RAW_WAVM, "Xbox .wavm raw header"},
{meta_DSP_STR, "Cauldron .STR header"},
{meta_EA_SCHL, "Electronic Arts SCHl header"},
{meta_EA_SCHL, "Electronic Arts SCHl header (variable)"},
{meta_EA_SCHL_fixed, "Electronic Arts SCHl header (fixed)"},
{meta_CAF, "tri-Crescendo CAF header"},
{meta_VPK, "SCE America VPK header"},
@ -1151,7 +1163,6 @@ static const meta_info meta_info_list[] = {
{meta_SPSD, "Sega Naomi SPSD header"},
{meta_BGW, "Square Enix BGMStream header"},
{meta_SPW, "Square Enix SeWave header"},
{meta_PS2_ASS, "SystemSoft .ASS header"},
{meta_NUB, "Namco NUB header"},
{meta_IDSP_NL, "Next Level IDSP header"},
{meta_IDSP_IE, "Inevitable Entertainment IDSP Header"},
@ -1198,7 +1209,6 @@ static const meta_info meta_info_list[] = {
{meta_DSP_KCEJE, "Konami .DSP Header"},
{meta_VGV, "Human Head .VGV header"},
{meta_GCUB, "Sega GCub header"},
{meta_NGC_SCK_DSP, "The Scorpion King SCK Header"},
{meta_CAFF, "Apple Core Audio Format File header"},
{meta_PC_MXST, "Lego Island MxSt Header"},
{meta_SAB, "Sensaura SAB header"},
@ -1223,7 +1233,7 @@ static const meta_info meta_info_list[] = {
{meta_SMPL, "Skonec SMPL header"},
{meta_MSA, "Success .MSA header"},
{meta_VOI, "Irem .VOI header"},
{meta_NGC_PDT, "Hudson .PDT header"},
{meta_PDT, "Hudson .PDT header"},
{meta_NGC_RKV, "Legacy of Kain - Blood Omen 2 RKV GC header"},
{meta_DSP_DDSP, ".DDSP header"},
{meta_P3D, "Radical P3D header"},
@ -1300,7 +1310,8 @@ static const meta_info meta_info_list[] = {
{meta_XA_XA30, "Reflections XA30 header"},
{meta_XA_04SW, "Reflections 04SW header"},
{meta_TXTH, "TXTH generic header"},
{meta_EA_BNK, "Electronic Arts BNK header"},
{meta_EA_BNK, "Electronic Arts BNK header (variable)"},
{meta_EA_BNK_fixed, "Electronic Arts BNK header (fixed)"},
{meta_SK_AUD, "Silicon Knights AUD header"},
{meta_AHX, "CRI AHX header"},
{meta_STMA, "Angel Studios/Rockstar San Diego STMA header"},
@ -1336,7 +1347,7 @@ static const meta_info meta_info_list[] = {
{meta_EA_WVE_AD10, "Electronic Arts WVE (Ad10) header"},
{meta_STHD, "Dream Factory STHD header"},
{meta_MP4, "MP4/AAC header"},
{meta_PCM_SRE, "Capcom .PCM+SRE header"},
{meta_SRE_PCM, "Capcom .SRE+PCM header"},
{meta_DSP_MCADPCM, "Bethesda .mcadpcm header"},
{meta_UBI_LYN, "Ubisoft LyN RIFF header"},
{meta_MSB_MSH, "Sony MultiStream MSH+MSB header"},

View file

@ -14,13 +14,15 @@ VGMSTREAM* init_vgmstream_acb(STREAMFILE* sf) {
/* checks */
if (!is_id32be(0x00,sf, "@UTF"))
goto fail;
return NULL;
/* mainly for bigger files (utf lib checks smaller) */
if (read_u32be(0x04,sf) + 0x08 != get_streamfile_size(sf))
goto fail;
return NULL;
if (!check_extensions(sf, "acb"))
goto fail;
/* .acb: standard
* .acx: Dariusburst - Chronicle Saviors (multi) */
if (!check_extensions(sf, "acb,acx"))
return NULL;
/* .acb is a cue sheet that uses @UTF (CRI's generic table format) to store row/columns
* with complex info (cues, sequences, spatial info, etc). It can store a memory .awb
@ -53,8 +55,16 @@ VGMSTREAM* init_vgmstream_acb(STREAMFILE* sf) {
//;VGM_LOG("acb: subfile offset=%x + %x\n", subfile_offset, subfile_size);
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, "awb");
if (!temp_sf) goto fail;
// .acb+awb (most common)
if (!temp_sf)
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, "awb");
// .acx+awx [Dariusburst: Chronicle Saviors (multi)]
if (!temp_sf && check_extensions(sf, "acx"))
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, "awx");
if (!temp_sf)
goto fail;
if (is_id32be(0x00, temp_sf, "CPK ")) {
vgmstream = init_vgmstream_cpk_memory(temp_sf, sf); /* older */
@ -1209,19 +1219,17 @@ fail:
*/
void load_acb_wave_info(STREAMFILE* sf, VGMSTREAM* vgmstream, int waveid, int port, int is_memory, int load_loops) {
acb_header acb = {0};
int i;
if (!sf || !vgmstream || waveid < 0)
return;
//;VGM_LOG("acb: find waveid=%i, port=%i\n", waveid, port);
acb_header acb = {0};
acb.acbFile = sf;
acb.Header = utf_open(acb.acbFile, 0x00, NULL, NULL);
if (!acb.Header) goto fail;
if (!acb.Header) return;
acb.target_waveid = waveid;
acb.target_port = port;
@ -1230,7 +1238,7 @@ void load_acb_wave_info(STREAMFILE* sf, VGMSTREAM* vgmstream, int waveid, int po
/* read all possible cue names and find which waveids are referenced by it */
preload_acb_cuename(&acb);
for (i = 0; i < acb.CueName_rows; i++) {
for (int i = 0; i < acb.CueName_rows; i++) {
if (!load_acb_cuename(&acb, i))
goto fail;
}

View file

@ -1,10 +1,20 @@
#include "meta.h"
#include "awb_aac_encryption_streamfile.h"
#include "../coding/coding.h"
#include "../util/companion_files.h"
#include "../util/cri_keys.h"
//typedef enum { ADX, HCA, VAG, RIFF, CWAV, DSP, CWAC, M4A } awb_type_t;
typedef struct {
VGMSTREAM* (*init_vgmstream)(STREAMFILE* sf);
VGMSTREAM* (*init_vgmstream_subkey)(STREAMFILE* sf, uint16_t subkey);
const char* extension;
bool load_loops;
bool use_riff_size;
} meta_info_t;
static void load_acb_info(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstream, int waveid, int load_loops);
static bool load_meta_type(meta_info_t* meta, STREAMFILE* sf, uint32_t subfile_offset);
static void load_acb_info(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstream, int waveid, bool load_loops);
static uint64_t load_keycode(STREAMFILE* sf);
/* AFS2/AWB (Atom Wave Bank) - CRI container of streaming audio, often together with a .acb cue sheet */
VGMSTREAM* init_vgmstream_awb(STREAMFILE* sf) {
@ -19,20 +29,21 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
uint8_t offset_size;
uint16_t waveid_alignment, offset_alignment, subkey;
int waveid;
int load_loops = 0;
bool load_loops = 0;
/* checks */
if (!is_id32be(0x00,sf, "AFS2"))
goto fail;
return NULL;
/* .awb: standard
* .afs2: sometimes [Okami HD (PS4)] */
if (!check_extensions(sf, "awb,afs2"))
goto fail;
* .afs2: sometimes [Okami HD (PS4)]
* .awx: Dariusburst - Chronicle Saviors (multi) */
if (!check_extensions(sf, "awb,afs2,awx"))
return NULL;
/* 0x04(1): version? 0x01=common, 0x02=2018+ (no apparent differences) */
// 0x04(1): version? 0x01=common, 0x02=2018+ (no apparent differences)
offset_size = read_u8 (0x05,sf);
waveid_alignment = read_u16le(0x06,sf); /* usually 0x02, rarely 0x04 [Voice of Cards: The Beasts of Burden (Switch)]*/
waveid_alignment = read_u16le(0x06,sf); // usually 0x02, rarely 0x04 [Voice of Cards: The Beasts of Burden (Switch)]
total_subsongs = read_s32le(0x08,sf);
offset_alignment = read_u16le(0x0c,sf);
subkey = read_u16le(0x0e,sf);
@ -69,7 +80,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
break;
default:
vgm_logi("AWB: unknown offset size (report)\n");
goto fail;
return NULL;
}
/* offset are absolute but sometimes misaligned (specially first that just points to offset table end) */
@ -82,76 +93,49 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
//;VGM_LOG("awb: subfile offset=%x + %x\n", subfile_offset, subfile_size);
/* autodetect as there isn't anything, plus can mix types
* (waveid<>codec info is usually in the companion .acb) */
/* handle subfile */
{
VGMSTREAM* (*init_vgmstream)(STREAMFILE* sf) = NULL;
VGMSTREAM* (*init_vgmstream_subkey)(STREAMFILE* sf, uint16_t subkey) = NULL;
const char* extension = NULL;
meta_info_t meta = {0};
if (read_u16be(subfile_offset, sf) == 0x8000) { /* (type 0=ADX, also 3?) */
init_vgmstream_subkey = init_vgmstream_adx_subkey; /* Okami HD (PS4) */
extension = "adx";
bool meta_ok = load_meta_type(&meta, sf, subfile_offset);
if (!meta_ok) {
// try encrypted meta (loads key after reguylar cases since it's uncommon)
uint64_t keycode = load_keycode(sf);
if (keycode) {
meta.init_vgmstream = init_vgmstream_mp4_aac_ffmpeg; // Final Fantasy Digital Card Game (Browser)
meta.extension = "m4a"; // TODO improve detection (only known to be used for .m4a)
meta_ok = true;
temp_sf = setup_awb_aac_encryption_streamfile(sf, subfile_offset, subfile_size, meta.extension, keycode);
if (!temp_sf) goto fail;
}
}
else if ((read_u32be(subfile_offset,sf) & 0x7f7f7f7f) == get_id32be("HCA\0")) { /* (type 2=HCA, 6=HCA-MX) */
init_vgmstream_subkey = init_vgmstream_hca_subkey; /* most common */
extension = "hca";
}
else if (is_id32be(subfile_offset,sf, "VAGp")) { /* (type 7=VAG, 10=HEVAG) */
init_vgmstream = init_vgmstream_vag; /* Ukiyo no Roushi (Vita) */
extension = "vag";
}
else if (is_id32be(subfile_offset,sf, "RIFF")) { /* (type 8=ATRAC3, 11=ATRAC9, also 18=ATRAC9?) */
init_vgmstream = init_vgmstream_riff; /* Ukiyo no Roushi (Vita) */
extension = "wav";
subfile_size = read_u32le(subfile_offset + 0x04,sf) + 0x08; /* padded size, use RIFF's */
}
else if (is_id32be(subfile_offset,sf, "CWAV")) { /* (type 9=CWAV) */
init_vgmstream = init_vgmstream_bcwav; /* Sonic: Lost World (3DS) */
extension = "bcwav";
}
else if (read_u32be(subfile_offset + 0x08,sf) >= 8000 && read_u32be(subfile_offset + 0x08,sf) <= 48000 &&
read_u16be(subfile_offset + 0x0e,sf) == 0 &&
read_u32be(subfile_offset + 0x18,sf) == 2 &&
read_u32be(subfile_offset + 0x50,sf) == 0) { /* (type 13=DSP, also 4=Wii?, 5=NDS?), probably should call some check function */
init_vgmstream = init_vgmstream_ngc_dsp_std; /* Sonic: Lost World (WiiU) */
extension = "dsp";
}
else if (is_id32be(subfile_offset,sf, "CWAC")) { /* (type 13=DSP, again) */
init_vgmstream = init_vgmstream_dsp_cwac; /* Mario & Sonic at the Rio 2016 Olympic Games (WiiU) */
extension = "dsp";
}
#ifdef VGM_USE_FFMPEG
else if (read_u32be(subfile_offset+0x00,sf) == 0x00000018 && is_id32be(subfile_offset+0x04,sf, "ftyp")) { /* (type 19=M4A) */
init_vgmstream = init_vgmstream_mp4_aac_ffmpeg; /* Imperial SaGa Eclipse (Browser) */
extension = "m4a";
}
#endif
else if (read_u32be(subfile_offset + 0x00,sf) == 0x01000080) { /* (type 24=NXOpus) */
init_vgmstream =init_vgmstream_opus_std; /* Super Mario RPG (Switch) */
extension = "opus";
load_loops = 1; /* loops not in Opus (rare) but in .acb */
}
else { /* 12=XMA? */
if (!meta_ok) {
vgm_logi("AWB: unknown codec (report)\n");
goto fail;
}
if (meta.use_riff_size) {
subfile_size = read_u32le(subfile_offset + 0x04,sf) + 0x08;
}
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, extension);
if (!temp_sf) goto fail;
if (!temp_sf) {
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, meta.extension);
if (!temp_sf) goto fail;
}
if (init_vgmstream_subkey)
vgmstream = init_vgmstream_subkey(temp_sf, subkey);
if (meta.init_vgmstream_subkey)
vgmstream = meta.init_vgmstream_subkey(temp_sf, subkey);
else
vgmstream = init_vgmstream(temp_sf);
vgmstream = meta.init_vgmstream(temp_sf);
if (!vgmstream) goto fail;
vgmstream->num_streams = total_subsongs;
}
/* try to load cue names+etc */
load_acb_info(sf, sf_acb, vgmstream, waveid, load_loops);
load_acb_info(sf, sf_acb, vgmstream, waveid, load_loops);
close_streamfile(temp_sf);
return vgmstream;
@ -163,8 +147,117 @@ fail:
}
static void load_acb_info(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstream, int waveid, int load_loops) {
int is_memory = (sf_acb != NULL);
/* autodetect as waveid<>codec is found in .acb (values/extension from CriAtomCraft decompilations)
* 00: ADX (.adx) [Gunhound EX (PSP), Persona 5 (PS3), Shin Megami Tensei V: Vengeance (PS4)]
* 01: PCM? (.swlpcm?)
* 02: HCA-MX? (.hca) [common]
* 03: alt ADX?
* 04: Wii DSP? (.wiiadpcm?)
* 05: NDS DSP? (.dsadpcm)
* 06: HCA-MX (.hcamx) [common]
* 07: VAG (.vag) [Ukiyo no Roushi (Vita)]
* 08: ATRAC3 (.at3) [Ukiyo no Shishi (PS3)]
* 09: CWAV (.3dsadpcm) [Sonic: Lost World (3DS)]
* 10: HEVAG (.vag) [Ukiyo no Roushi (Vita)]
* 11: ATRAC9 (.at9) [Ukiyo no Roushi (Vita)]
* 12: X360 XMA? (.xma2?)
* 13: DSP (.wiiuadpcm?) [Sonic: Lost World (WiiU)]
* 13: CWAC DSP (.wiiuadpcm?) [Mario & Sonic at the Rio 2016 Olympic Games (WiiU)]
* 14: PS4 HEVAG?
* 18: PS4 ATRAC9 (.at9) [13 Sentinels (PS4)]
* 19: AAC M4A (.m4a) [Imperial SaGa Eclipse (Browser)]
* 24: Switch Opus (.switchopus) [Super Mario RPG (Switch)]
*/
static bool load_meta_type(meta_info_t* meta, STREAMFILE* sf, uint32_t subfile_offset) {
if (read_u16be(subfile_offset, sf) == 0x8000) {
meta->init_vgmstream_subkey = init_vgmstream_adx_subkey;
meta->extension = "adx";
return true;
}
if ((read_u32be(subfile_offset,sf) & 0x7f7f7f7f) == get_id32be("HCA\0")) {
meta->init_vgmstream_subkey = init_vgmstream_hca_subkey;
meta->extension = "hca";
return true;
}
if (is_id32be(subfile_offset,sf, "VAGp")) {
meta->init_vgmstream = init_vgmstream_vag;
meta->extension = "vag";
return true;
}
if (is_id32be(subfile_offset,sf, "RIFF")) {
meta->init_vgmstream = init_vgmstream_riff;
meta->extension = "wav";
meta->use_riff_size = true; // padded size, use RIFF's
return true;
}
if (is_id32be(subfile_offset,sf, "CWAV")) {
meta->init_vgmstream = init_vgmstream_bcwav;
meta->extension = "bcwav";
return true;
}
// TODO: call some check function?
if (read_u32be(subfile_offset + 0x08,sf) >= 8000
&& read_u32be(subfile_offset + 0x08,sf) <= 48000
&& read_u16be(subfile_offset + 0x0e,sf) == 0
&& read_u32be(subfile_offset + 0x18,sf) == 2
&& read_u32be(subfile_offset + 0x50,sf) == 0) {
meta->init_vgmstream = init_vgmstream_ngc_dsp_std;
meta->extension = "dsp";
return true;
}
if (is_id32be(subfile_offset,sf, "CWAC")) {
meta->init_vgmstream = init_vgmstream_dsp_cwac;
meta->extension = "dsp";
return true;
}
#ifdef VGM_USE_FFMPEG
if (read_u32be(subfile_offset + 0x00,sf) == 0x00000018
&& is_id32be(subfile_offset + 0x04,sf, "ftyp")) {
meta->init_vgmstream = init_vgmstream_mp4_aac_ffmpeg;
meta->extension = "m4a";
return true;
}
#endif
if (read_u32be(subfile_offset + 0x00,sf) == 0x01000080) {
meta->init_vgmstream = init_vgmstream_opus_std;
meta->extension = "opus";
meta->load_loops = true; // loops not in Opus but in .acb (rare)
return true;
}
return false;
}
// TODO unify, from HCA
static uint64_t load_keycode(STREAMFILE* sf) {
// fully encrypted data, try to read keyfile (rare)
uint8_t keybuf[20+1] = {0}; /* max keystring 20, +1 extra null */
uint32_t key_size = read_key_file(keybuf, sizeof(keybuf) - 1, sf);
uint64_t keycode = 0;
bool is_keystring = cri_key9_valid_keystring(keybuf, key_size);
if (is_keystring) { /* number */
const char* keystring = (const char*)keybuf;
keycode = strtoull(keystring, NULL, 10);
}
else if (key_size == 0x08) { /* hex */
keycode = get_u64be(keybuf+0x00);
}
return keycode;
}
static void load_acb_info(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstream, int waveid, bool load_loops) {
bool is_memory = (sf_acb != NULL);
int port = 0;
/* .acb is passed when loading memory .awb inside .acb */
@ -176,13 +269,18 @@ static void load_acb_info(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstre
/* try parsing TXTM if present */
sf_acb = read_filemap_file_pos(sf, 0, &port);
/* try (name).awb + (name).acb */
/* try (name).awb + (name).acb (most common) */
if (!sf_acb) {
sf_acb = open_streamfile_by_ext(sf, "acb");
}
/* try (name)_streamfiles.awb + (name).acb */
if (!sf_acb) {
/* try (name).awx + (name).acx, exclusive to Dariusburst console games. */
if (!sf_acb && check_extensions(sf, "awx")) {
sf_acb = open_streamfile_by_ext(sf, "acx");
}
/* try (name)_streamfiles.awb + (name).acb (sometimes) */
if (!sf_acb && check_extensions(sf, "awb")) {
char *cmp = "_streamfiles";
get_streamfile_basename(sf, filename, sizeof(filename));
len_name = strlen(filename);
@ -196,7 +294,7 @@ static void load_acb_info(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstre
}
/* try (name)_STR.awb + (name).acb */
if (!sf_acb) {
if (!sf_acb && check_extensions(sf, "awb")) {
char *cmp = "_STR";
get_streamfile_basename(sf, filename, sizeof(filename));
len_name = strlen(filename);

View file

@ -0,0 +1,132 @@
#ifndef _AWB_AAC_ENCRYPTION_STREAMFILE_H_
#define _AWB_AAC_ENCRYPTION_STREAMFILE_H_
#include "../streamfile.h"
typedef struct {
uint16_t key[4];
uint16_t xor;
uint16_t add;
uint16_t mul;
uint32_t curr_offset;
} cri_aac_io_data;
// see criAacCodec_SetDecryptionKey
static void setup_key(uint64_t keycode, cri_aac_io_data* cridata) {
if (!keycode)
return;
uint16_t k0 = 4 * ((keycode >> 0) & 0x0FFF) | 1;
uint16_t k1 = 2 * ((keycode >> 12) & 0x1FFF) | 1;
uint16_t k2 = 4 * ((keycode >> 25) & 0x1FFF) | 1;
uint16_t k3 = 2 * ((keycode >> 38) & 0x3FFF) | 1;
cridata->key[0] = k0 ^ k1;
cridata->key[1] = k1 ^ k2;
cridata->key[2] = k2 ^ k3;
cridata->key[3] = ~k3;
// criatomexacb_generate_aac_decryption_key is slightly different, unsure if used:
//keydata->key[0] = k0 ^ k3;
//keydata->key[1] = k2 ^ k3;
//keydata->key[2] = k2 ^ k3;
//keydata->key[3] = ~k3;
}
// see criAacCodec_DecryptData
static void decrypt_chunk(cri_aac_io_data* data, uint8_t* dst, uint32_t dst_size) {
uint16_t seed0 = ~data->key[3];
uint16_t seed1 = seed0 ^ data->key[2];
uint16_t seed2 = seed1 ^ data->key[1];
uint16_t seed3 = seed2 ^ data->key[0];
uint16_t xor = data->xor;
uint16_t add = data->add;
uint16_t mul = data->mul;
// use as special flag (original code decrypts whole files so values are always reset)
if (dst == NULL && dst_size == 0) {
xor = 2 * seed0 | 1;
add = 2 * seed0 | 1; // not seed1
mul = 4 * seed2 | 1;
}
for (int i = 0; i < dst_size; i++) {
int curr_i = data->curr_offset + i;
if (!(uint16_t)curr_i) { // every 0x10000, without modulo
mul = ((4 * seed2 + seed3 * (mul & 0xFFFC)) & 0xFFFD) | 1;
add = (2 * seed0 + seed1 * (add & 0xFFFE)) | 1;
}
xor = xor * mul + add;
if (dst != NULL) {
dst[i] ^= (xor >> 8) & 0xFF;
}
}
data->xor = xor;
data->add = add;
data->mul = mul;
data->curr_offset += dst_size;
}
static void reset_keydata(cri_aac_io_data* data) {
decrypt_chunk(data, NULL, 0);
}
static void update_key(cri_aac_io_data* data, STREAMFILE* sf, off_t offset) {
size_t to_skip;
if (offset < data->curr_offset || offset == 0x00) {
reset_keydata(data);
data->curr_offset = 0x00;
to_skip = offset;
}
else {
to_skip = offset - data->curr_offset;
}
if (to_skip == 0)
return;
// update key by reading and decrypt all data between current offset + last known key to requested offset
decrypt_chunk(data, NULL, to_skip);
}
/* XOR depends on decrypted data, meanings having to decrypt linearly to reach some offset. */
static size_t cri_aac_io_read(STREAMFILE* sf, uint8_t* dest, off_t offset, size_t length, cri_aac_io_data* data) {
size_t bytes;
// fix key to current offset
update_key(data, sf, offset);
// read and decrypt current data
bytes = read_streamfile(dest, offset, length, sf);
decrypt_chunk(data, dest, bytes);
return bytes;
}
/* decrypts CRI's AAC encryption, from decompilation [Final Fantasy Digital Card Game (Browser)] */
static STREAMFILE* setup_awb_aac_encryption_streamfile(STREAMFILE* sf, uint32_t subfile_offset, uint32_t subfile_size, const char* extension, uint64_t keycode) {
STREAMFILE* new_sf = NULL;
cri_aac_io_data io_data = {0};
setup_key(keycode, &io_data);
reset_keydata(&io_data);
io_data.curr_offset = 0x00;
new_sf = open_wrap_streamfile(sf);
new_sf = open_clamp_streamfile_f(new_sf, subfile_offset, subfile_size);
new_sf = open_io_streamfile_f(new_sf, &io_data, sizeof(cri_aac_io_data), cri_aac_io_read, NULL);
if (extension) {
new_sf = open_fakename_streamfile_f(new_sf, NULL, extension);
}
return new_sf;
}
#endif

View file

@ -18,7 +18,9 @@ VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) {
/* checks */
if (!is_id32be(0x00,sf, "@UTF"))
goto fail;
if (!check_extensions(sf, "csb"))
/* .csb: standard
* .cxb: Dariusburst - Another Chronicle (AC) */
if (!check_extensions(sf, "csb,cxb"))
goto fail;
/* .csb is an early, simpler version of .acb+awk (see acb.c) used until ~2013?

View file

@ -53,7 +53,7 @@ VGMSTREAM* init_vgmstream_ea_1snh(STREAMFILE* sf) {
if (!is_id32be(offset + 0x00, sf, "1SNh") &&
!is_id32be(offset + 0x00, sf, "SEAD"))
goto fail;
return NULL;
/* .asf/as4: common,
* .lasf: fake for plugins
@ -63,7 +63,7 @@ VGMSTREAM* init_vgmstream_ea_1snh(STREAMFILE* sf) {
* .tgv: videos
* (extensionless): Need for Speed (SAT) videos */
if (!check_extensions(sf, "asf,lasf,sng,as4,cnk,uv,tgq,tgv,"))
goto fail;
return NULL;
/* stream is divided into blocks/chunks: 1SNh=audio header, 1SNd=data xN, 1SNl=loop end, 1SNe=end.
* Video uses various blocks (TGVk/TGVf/MUVf/etc) and sometimes alt audio blocks (SEAD/SNDC/SEND). */
@ -105,13 +105,15 @@ VGMSTREAM* init_vgmstream_ea_eacs(STREAMFILE* sf) {
/* checks */
if (!is_id32be(0x00,sf, "EACS") &&
read_u32be(0x00,sf) != 0 && !is_id32be(0x228,sf, "EACS"))
goto fail;
return NULL;
/* .eas: single bank [Need for Speed (PC)]
* .bnk: multi bank [Need for Speed (PC)]
* .as4: single [NBA Live 96 (PC)] */
if (!check_extensions(sf,"eas,bnk,as4"))
goto fail;
* .as4/sph: single [NBA Live 96 (PC)]
* .dty/mon: single [NBA Live 95 (PC)]
* .spc: single [FIFA Soccer 96 (PC)] */
if (!check_extensions(sf,"eas,bnk,as4,sph,dty,mon,spc"))
return NULL;
/* plain data without blocks, can contain N*(EACS header) + N*(data), or N (EACS header + data) */
ea.is_bank = 1;
@ -128,7 +130,7 @@ VGMSTREAM* init_vgmstream_ea_eacs(STREAMFILE* sf) {
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0) goto fail;
/* offsets to EACSs are scattered in the first 0x200, then 0x28 info + EACS per subsong.
/* offsets to EACSs are scattered in the first 0x200, then 0x28 info + EACS per subsong.
* This looks dumb but seems like the only way. */
eacs_offset = 0;
for (i = 0x00; i < 0x200; i += 0x04) {
@ -163,6 +165,72 @@ fail:
return NULL;
}
/* EA CRDF - crowd banks (later games use CRDl without audio) */
VGMSTREAM* init_vgmstream_ea_crdf(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
eacs_header ea = {0};
off_t eacs_offset;
int total_subsongs, target_subsong = sf->stream_index;
/* checks */
if (!is_id32be(0x00, sf, "CRDF"))
return NULL;
/* .crd: NBA Live 95/96 (PC), FIFA Soccer 96 (PC) */
if (!check_extensions(sf, "crd"))
return NULL;
/* filter out some weird variation [NBA Live 96 (PS1)] */
if (read_u32le(0x04, sf) != 0x02) goto fail;
ea.is_bank = 1;
if (target_subsong == 0) target_subsong = 1;
// TODO: possibly unreliable variant checks
if (read_u32be(0x10, sf) == 0x02 && read_u32be(0x14, sf) == 0x04) {
/* Early variant, header size 0x344 [NBA 95 (PC)] */
total_subsongs = read_u32le(0x18, sf);
/* game does (0xC4 + 0x28) + i * (0x1C * 4) */
eacs_offset = 0xEC + (target_subsong - 1) * 0x70;
}
else if (read_u32le(0x10, sf) + read_u32le(0x14, sf) == 0x10000) {
/* Later variant, header size 0x38C [NBA 96 (PC), FIFA 96 (PC)] */
total_subsongs = read_u32le(0x24, sf);
/* game does (0x7C + 0x28) + i * (0x1D * 4) */
eacs_offset = 0xA4 + (target_subsong - 1) * 0x74;
}
else {
VGM_LOG("EA EACS: unknown CRDF variant\n");
goto fail;
}
/* actual check done by the games, seemingly always 4
* entries with the latter ones dummy if less tracks */
//if (total_subsongs > 4) total_subsongs = 4;
if (total_subsongs < 1 || target_subsong > total_subsongs)
goto fail;
if (!parse_header(sf, &ea, eacs_offset))
goto fail;
vgmstream = init_vgmstream_main(sf, &ea);
if (!vgmstream) goto fail;
vgmstream->num_streams = total_subsongs;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
static VGMSTREAM* init_vgmstream_main(STREAMFILE* sf, eacs_header* ea) {
VGMSTREAM* vgmstream = NULL;

View file

@ -39,7 +39,7 @@
/* CODEC1 values were used early, then they migrated to CODEC2 values */
#define EA_CODEC1_NONE -1
#define EA_CODEC1_PCM 0x00
//#define EA_CODEC1_IMA 0x02 /* not used (sx.exe internal defs) */
#define EA_CODEC1_IMA 0x02 /* very rare [NBA Live 97 (PC)] */
#define EA_CODEC1_N64 0x05
#define EA_CODEC1_VAG 0x06
#define EA_CODEC1_EAXA 0x07
@ -59,7 +59,7 @@
#define EA_CODEC2_EAXA 0x0A
//#define EA_CODEC2_U8_INT 0x0B /* not used (sx.exe internal defs) */
//#define EA_CODEC2_CDXA 0x0C /* not used (sx.exe internal defs) */
//#define EA_CODEC2_IMA_INT 0x0D /* not used (sx.exe internal defs) */
#define EA_CODEC2_IMA_INT 0x0D
//#define EA_CODEC2_LAYER1 0x0E /* not used (sx.exe internal defs) */
#define EA_CODEC2_LAYER2 0x0F
#define EA_CODEC2_LAYER3 0x10 /* not seen so far but may be used somewhere */
@ -142,6 +142,7 @@ static off_t get_ea_stream_mpeg_start_offset(STREAMFILE* sf, off_t start_offset,
static VGMSTREAM* init_vgmstream_ea_variable_header(STREAMFILE* sf, ea_header* ea, off_t start_offset, int is_bnk);
static void update_ea_stream_size(STREAMFILE* sf, off_t start_offset, VGMSTREAM* vgmstream);
VGMSTREAM* load_vgmstream_ea_schl(STREAMFILE* sf, off_t offset) {
return parse_schl_block(sf, offset);
}
@ -150,6 +151,14 @@ VGMSTREAM* load_vgmstream_ea_bnk(STREAMFILE* sf, off_t offset, int target_stream
return parse_bnk_header(sf, offset, target_stream, is_embedded);
}
/* load standalone variable header */
VGMSTREAM* load_vgmstream_ea_pt(STREAMFILE* sf_head, STREAMFILE* sf_body, off_t head_offset, size_t head_size, off_t body_offset) {
ea_header ea = {0};
if (!parse_variable_header(sf_head, &ea, head_offset, head_size, 1))
return NULL;
return init_vgmstream_ea_variable_header(sf_body, &ea, body_offset, 1);
}
/* EA SCHl with variable header - from EA games (roughly 1997~2010); generated by EA Canada's sx.exe/Sound eXchange */
static VGMSTREAM* parse_schl_block(STREAMFILE* sf, off_t offset) {
off_t start_offset, header_offset;
@ -325,6 +334,10 @@ static VGMSTREAM* init_vgmstream_ea_variable_header(STREAMFILE* sf, ea_header* e
}
break;
case EA_CODEC2_IMA_INT: /* DVI IMA */
vgmstream->coding_type = coding_DVI_IMA;
break;
case EA_CODEC2_S8_INT: /* PCM8 (interleaved) */
vgmstream->coding_type = coding_PCM8_int;
break;
@ -518,6 +531,15 @@ static VGMSTREAM* init_vgmstream_ea_variable_header(STREAMFILE* sf, ea_header* e
}
break;
}
case coding_DVI_IMA:
/* 0x00 default all? very rarely used, only found in standalone PTH/PTD
* during the transition period from fixed to variable header format */
//if (start_offset != ea->offsets[0]) goto fail;
for (i = 0; i < vgmstream->channels; i++) {
vgmstream->ch[i].offset = ea->offsets[0];
}
break;
default:
VGM_LOG("EA SCHl: Unknown channel offsets for codec 0x%02x in version %d\n", ea->codec1, ea->version);
goto fail;
@ -867,6 +889,7 @@ static int parse_variable_header(STREAMFILE* sf, ea_header* ea, off_t begin_offs
else
ea->codec2 = ea->bps == 8 ? EA_CODEC2_S8 : (ea->big_endian ? EA_CODEC2_S16BE : EA_CODEC2_S16LE);
break;
case EA_CODEC1_IMA: ea->codec2 = EA_CODEC2_IMA_INT; break;
case EA_CODEC1_N64: ea->codec2 = EA_CODEC2_N64; break;
case EA_CODEC1_VAG: ea->codec2 = EA_CODEC2_VAG; break;
case EA_CODEC1_EAXA:

View file

@ -2,7 +2,7 @@
#include "../layout/layout.h"
#include "../coding/coding.h"
/* Possibly the same as EA_CODEC_x in variable SCHl */
/* Possibly the same as EA_CODEC1_x in variable SCHl */
#define EA_CODEC_PCM 0x00
#define EA_CODEC_IMA 0x02
#define EA_CODEC_PSX 0x06
@ -17,57 +17,188 @@ typedef struct {
int big_endian;
int loop_flag;
int is_bank;
off_t start_offset;
//size_t stream_size;
off_t loop_start;
off_t loop_end;
} ea_fixed_header;
static int parse_fixed_header(STREAMFILE* sf, ea_fixed_header* ea);
static VGMSTREAM* init_vgmstream_ea_fixed_header(STREAMFILE* sf, ea_fixed_header* ea);
static int parse_fixed_header(STREAMFILE* sf, ea_fixed_header* ea, off_t offset);
/* EA SCHl with fixed header - from EA games (~1997?) */
VGMSTREAM* init_vgmstream_ea_schl_fixed(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
size_t header_size;
ea_fixed_header ea = {0};
size_t header_size;
off_t offset;
/* checks */
if (!is_id32be(0x00,sf, "SCHl"))
if (!is_id32be(0x00, sf, "SCHl"))
return NULL;
/* .asf: original [NHK 97 (PC)]
* .lasf: fake for plugins
* .cnk: ps1 [NBA Live 97 (PS1)] */
if (!check_extensions(sf,"asf,lasf,cnk"))
* .cnk/dct: ps1 [NBA Live 97 (PS1)] */
if (!check_extensions(sf, "asf,lasf,cnk,dct"))
return NULL;
/* see ea_schl.c for more info about blocks */
//TODO: handle SCCl? [NBA Live 97 (PS1)]
header_size = read_u32le(0x04,sf);
header_size = read_u32le(0x04, sf);
if (!parse_fixed_header(sf, &ea))
offset = is_id32be(0x0c, sf, "PATl") ? 0x0c : 0x08; /* extra field in PS1 */
if (!parse_fixed_header(sf, &ea, offset))
return NULL;
ea.start_offset = header_size; /* has garbage data in PATl */
return init_vgmstream_ea_fixed_header(sf, &ea);
}
/* EA BNKl with fixed header - from EA games (~1997?) */
VGMSTREAM* init_vgmstream_ea_bnk_fixed(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sf_body = NULL;
ea_fixed_header ea = {0};
int bnk_version, num_sounds;
int total_subsongs = 0, target_subsong = sf->stream_index;
off_t offset;
/* checks */
if (!is_id32be(0x00, sf, "BNKl"))
return NULL;
/* .bkh: FIFA 97 (PC)
* .vh: NBA Live 97 (PS1) */
if (check_extensions(sf, "bkh")) {
sf_body = open_streamfile_by_ext(sf, "bkd");
if (!sf_body) goto fail;
}
else if (check_extensions(sf, "vh")) {
sf_body = open_streamfile_by_ext(sf, "vb");
if (!sf_body) goto fail;
}
else
return NULL;
ea.is_bank = 1;
bnk_version = read_u16le(0x04, sf);
num_sounds = read_u16le(0x06, sf);
/* (intentionally?) blanked fields [Triple Play 97 (PC)] */
if (!bnk_version && !num_sounds) {
bnk_version = 0x01;
num_sounds = 0x80;
}
/* bnk v2+ is only in standard (variable header) ea_schl */
if (bnk_version != 0x01) goto fail;
/* always a 0x200 sized buffer w/ dummy nullptr entries */
if (num_sounds != 0x80) goto fail;
if (target_subsong == 0) target_subsong = 1;
for (int i = 0; i < num_sounds; i++) {
offset = read_u32le(0x08 + (i * 0x04), sf);
if (!offset) continue;
total_subsongs++;
if (total_subsongs == target_subsong) {
offset += 0x08 + (i * 0x04); /* pointer base is ptr pos */
if (!parse_fixed_header(sf, &ea, offset))
goto fail;
}
}
if (total_subsongs < 1 || target_subsong > total_subsongs)
goto fail;
start_offset = header_size;
vgmstream = init_vgmstream_ea_fixed_header(sf_body, &ea);
if (!vgmstream) goto fail;
vgmstream->num_streams = total_subsongs;
close_streamfile(sf_body);
return vgmstream;
fail:
close_streamfile(sf_body);
close_vgmstream(vgmstream);
return NULL;
}
/* EA standalone PATl fixed header - from EA games (~1997?) */
VGMSTREAM* init_vgmstream_ea_patl(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sf_body = NULL;
ea_fixed_header ea = {0};
/* checks */
if (!parse_fixed_header(sf, &ea, 0x00))
return NULL;
/* .pth: Triple Play 97 (PC) */
/* often also found as nameless file pairs in bigfiles [FIFA 97 (PC)] */
if (check_extensions(sf, "pth")) {
sf_body = open_streamfile_by_ext(sf, "ptd");
if (!sf_body) goto fail;
}
else
return NULL;
ea.is_bank = 1;
if (ea.start_offset != 0x00) goto fail;
vgmstream = init_vgmstream_ea_fixed_header(sf_body, &ea);
if (!vgmstream) goto fail;
close_streamfile(sf_body);
return vgmstream;
fail:
close_streamfile(sf_body);
close_vgmstream(vgmstream);
return NULL;
}
static VGMSTREAM* init_vgmstream_ea_fixed_header(STREAMFILE* sf, ea_fixed_header* ea) {
VGMSTREAM* vgmstream = NULL;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(ea.channels, ea.loop_flag);
vgmstream = allocate_vgmstream(ea->channels, ea->loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = ea.sample_rate;
vgmstream->num_samples = ea.num_samples;
//vgmstream->loop_start_sample = ea.loop_start;
//vgmstream->loop_end_sample = ea.loop_end;
//vgmstream->stream_size = ea->stream_size; /* only on PS1, and sometimes uninitialised garbage? */
vgmstream->sample_rate = ea->sample_rate;
vgmstream->num_samples = ea->num_samples;
/* loops are rare, loop_end might also need +1 just like variable_header?
* NBA Live 97 (PS1, JPN) ZAUDIOFX.BKH #15-#18 loop_end == num_samples-1 */
vgmstream->loop_start_sample = ea->loop_start;
vgmstream->loop_end_sample = ea->loop_end;
vgmstream->codec_endian = ea.big_endian;
vgmstream->codec_endian = ea->big_endian;
vgmstream->meta_type = meta_EA_SCHL_fixed;
vgmstream->layout_type = layout_blocked_ea_schl;
vgmstream->meta_type = ea->is_bank ? meta_EA_BNK_fixed : meta_EA_SCHL_fixed;
vgmstream->layout_type = ea->is_bank ? layout_none : layout_blocked_ea_schl;
switch (ea.codec) {
switch (ea->codec) {
case EA_CODEC_PCM:
vgmstream->coding_type = ea.bps==8 ? coding_PCM8 : (ea.big_endian ? coding_PCM16BE : coding_PCM16LE);
vgmstream->coding_type = ea->bps == 8 ? coding_PCM8 : (ea->big_endian ? coding_PCM16BE : coding_PCM16LE);
break;
case EA_CODEC_IMA:
@ -79,12 +210,12 @@ VGMSTREAM* init_vgmstream_ea_schl_fixed(STREAMFILE* sf) {
break;
default:
VGM_LOG("EA: unknown codec 0x%02x\n", ea.codec);
VGM_LOG("EA SCHl: unknown fixed header codec 0x%02x\n", ea->codec);
goto fail;
}
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
if (!vgmstream_open_stream(vgmstream, sf, ea->start_offset))
goto fail;
return vgmstream;
@ -94,60 +225,59 @@ fail:
}
static int parse_fixed_header(STREAMFILE* sf, ea_fixed_header* ea) {
uint32_t offset = 0x00, size = 0;
static int parse_fixed_header(STREAMFILE* sf, ea_fixed_header* ea, off_t offset) {
if (is_id32be(offset+0x08, sf, "PATl"))
offset = 0x08;
else if (is_id32be(offset+0x0c, sf, "PATl"))
offset = 0x0c; /* extra field in PS1 */
else
if (!is_id32be(offset + 0x00, sf, "PATl"))
goto fail;
size = read_u32le(offset+0x34, sf);
if (size == 0x20 && is_id32be(offset+0x38, sf, "TMpl")) { /* PC LE? */
offset += 0x3c;
/* PATl header is 0x10 bytes, and can be separate from the rest of the body (BNKl) */
offset += read_u32le(offset + 0x0c, sf) + 0x0c; /* body pointer base from ptr pos */
ea->version = read_u8 (offset+0x00, sf);
ea->bps = read_u8 (offset+0x01, sf);
ea->channels = read_u8 (offset+0x02, sf);
ea->codec = read_u8 (offset+0x03, sf);
//size = read_u32le(offset + 0x34, sf); /* pointer to end of all header bodies, not size */
if (/*size == 0x20 &&*/ is_id32be(offset + 0x28, sf, "TMpl")) { /* PC LE? */
offset += 0x2c;
ea->version = read_u8 (offset + 0x00, sf);
ea->bps = read_u8 (offset + 0x01, sf);
ea->channels = read_u8 (offset + 0x02, sf);
ea->codec = read_u8 (offset + 0x03, sf);
/* 0x04: 0? */
ea->sample_rate = read_u16le(offset+0x06, sf);
ea->num_samples = read_s32le(offset+0x08, sf);
/* 0x0c: -1? loop_start? */
/* 0x10: -1? loop_end? */
/* 0x14: 0? data start? */
/* 0x18: -1? */
/* 0x1c: volume? (always 128) */
ea->sample_rate = read_u16le(offset + 0x06, sf);
ea->num_samples = read_s32le(offset + 0x08, sf);
ea->loop_start = read_s32le(offset + 0x0c, sf);
ea->loop_end = read_s32le(offset + 0x10, sf);
ea->start_offset = read_u32le(offset + 0x14, sf); /* BNKl only */
/* 0x18: -1? */ /* SCHl only */
}
else if (size == 0x38 && is_id32be(offset+0x38, sf, "TMxl")) { /* PSX LE? */
offset += 0x3c;
else if (/*size == 0x38 &&*/ is_id32be(offset + 0x28, sf, "TMxl")) { /* PSX LE? */
offset += 0x2c;
ea->version = read_u8 (offset+0x00, sf);
ea->bps = read_u8 (offset+0x01, sf);
ea->channels = read_u8 (offset+0x02, sf);
ea->codec = read_u8 (offset+0x03, sf);
ea->version = read_u8 (offset + 0x00, sf);
ea->bps = read_u8 (offset + 0x01, sf);
ea->channels = read_u8 (offset + 0x02, sf);
ea->codec = read_u8 (offset + 0x03, sf);
/* 0x04: 0? */
ea->sample_rate = read_u16le(offset+0x06, sf);
/* 0x08: 0x20C? */
ea->num_samples = read_s32le(offset+0x0c, sf);
/* 0x10: -1? loop_start? */
/* 0x14: -1? loop_end? */
/* 0x18: 0x20C? */
ea->sample_rate = read_u16le(offset + 0x06, sf);
/* 0x08: 0x20C in SCHl, 0x800 in BNKl? */
ea->num_samples = read_s32le(offset + 0x0c, sf);
ea->loop_start = read_s32le(offset + 0x10, sf);
ea->loop_end = read_s32le(offset + 0x14, sf);
ea->start_offset = read_u32le(offset + 0x18, sf); /* BNKl only */
/* 0x1c: 0? */
/* 0x20: 0? */
//ea->stream_size = read_u32le(offset + 0x20, sf); /* BNKl only */
/* 0x24: 0? */
/* 0x28: -1? */
/* 0x2c: -1? */
/* 0x30: -1? */
/* 0x34: volume? (always 128) */
/* 0x30: -1? */ /* SCHl only */
}
else {
VGM_LOG("EA SCHl: unknown fixed header subtype\n");
goto fail;
}
/* after header bodies */
/* 0x00: volume? (127 or 128) */
//ea->loop_flag = (ea->loop_end_sample);
ea->loop_flag = (ea->loop_end != -1);
return 1;
fail:

View file

@ -46,20 +46,21 @@ VGMSTREAM* init_vgmstream_ea_schl(STREAMFILE* sf) {
return NULL;
/* check header */
if (read_u32be(0x00, sf) != EA_BLOCKID_HEADER && /* "SCHl" */
read_u32be(0x00, sf) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_EN) && /* "SHEN" */
read_u32be(0x00, sf) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_FR) && /* "SHFR" */
read_u32be(0x00, sf) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_GE) && /* "SHGE" */
read_u32be(0x00, sf) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_DE) && /* "SHDE" */
read_u32be(0x00, sf) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_IT) && /* "SHIT" */
read_u32be(0x00, sf) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_SP) && /* "SHSP" */
read_u32be(0x00, sf) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_ES) && /* "SHES" */
read_u32be(0x00, sf) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_MX) && /* "SHMX" */
read_u32be(0x00, sf) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_RU) && /* "SHRU" */
read_u32be(0x00, sf) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_JA) && /* "SHJA" */
read_u32be(0x00, sf) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_JP) && /* "SHJP" */
read_u32be(0x00, sf) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_PL) && /* "SHPL" */
read_u32be(0x00, sf) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_BR)) /* "SHBR" */
uint32_t header = read_u32be(0x00, sf);
if (header != EA_BLOCKID_HEADER && /* "SCHl" */
header != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_EN) && /* "SHEN" */
header != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_FR) && /* "SHFR" */
header != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_GE) && /* "SHGE" */
header != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_DE) && /* "SHDE" */
header != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_IT) && /* "SHIT" */
header != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_SP) && /* "SHSP" */
header != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_ES) && /* "SHES" */
header != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_MX) && /* "SHMX" */
header != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_RU) && /* "SHRU" */
header != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_JA) && /* "SHJA" */
header != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_JP) && /* "SHJP" */
header != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_PL) && /* "SHPL" */
header != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_BR)) /* "SHBR" */
return NULL;
/* Stream is divided into blocks/chunks: SCHl=audio header, SCCl=count of SCDl, SCDl=data xN, SCLl=loop end, SCEl=end.
@ -183,3 +184,55 @@ fail:
close_vgmstream(vgmstream);
return NULL;
}
/* EA standalone PT variable header - rare, found during the transition from fixed header */
VGMSTREAM* init_vgmstream_ea_pt(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sf_body = NULL;
off_t head_offset, body_offset;
size_t head_size;
int is_split = 0;
/* .pth: split [NBA Live 97 (PC)]
* .dat: joined [NBA Live 97/98 (PC)] */
/* often also found as nameless file pairs in bigfiles [FIFA 97 (PC)] */
if (check_extensions(sf, "pth")) {
sf_body = open_streamfile_by_ext(sf, "ptd");
if (!sf_body) goto fail;
is_split = 1;
}
else //if (!check_extensions(sf, "dat,ldat"))
return NULL;
if (is_split) {
head_size = get_streamfile_size(sf);
head_offset = 0x00;
body_offset = 0x00;
}
/* these contain multiple subsongs, but with no clear way
* to get each of their offsets, unimplemented for now */
//else { /* NBA 97 variant, NBA 98 has an even weirder variant */
// head_size = read_u32le(0x00, sf);
// head_offset = 0x04;
// body_offset = head_offset + head_size;
// sf_body = sf;
//}
if (!is_id32be(head_offset, sf, "PT\0\0")) /* does standalone GSTR also exist? */
goto fail;
vgmstream = load_vgmstream_ea_pt(sf, sf_body, head_offset, head_size, body_offset);
if (!vgmstream) goto fail;
if (is_split) close_streamfile(sf_body);
return vgmstream;
fail:
if (is_split) close_streamfile(sf_body);
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1,59 +1,60 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
/* EA WVE (VLC0/au00) - from Electronic Arts PS movies [Future Cop - L.A.P.D. (PS), Supercross 2000 (PS)] */
VGMSTREAM * init_vgmstream_ea_wve_au00(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
/* checks */
/* .wve: common, .fsv: Future Cop LAPD (PS1) */
if (!check_extensions(streamFile, "wve,fsv"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x564C4330) /* "VLC0" */
goto fail;
start_offset = read_32bitBE(0x04,streamFile);
if (read_32bitBE(start_offset, streamFile) != 0x61753030 && /* "au00" */
read_32bitBE(start_offset, streamFile) != 0x61753031) /* "au01" (last block, but could be first) */
goto fail;
loop_flag = 0;
channel_count = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_EA_WVE_AU00;
vgmstream->sample_rate = 22050;
/* You'd think they'd use coding_EA_XA_int but instead it's PS-ADPCM without flags and 0x0f frame size
* (equivalent to configurable PS-ADPCM), surely to shoehorn EA-XA sizes into the PS1 hardware decoder */
vgmstream->coding_type = coding_PSX_cfg;
vgmstream->interleave_block_size = 0x0f;
vgmstream->layout_type = layout_blocked_ea_wve_au00;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
/* calc num_samples manually */
{
vgmstream->next_block_offset = start_offset;
do {
block_update(vgmstream->next_block_offset,vgmstream);
vgmstream->num_samples += ps_cfg_bytes_to_samples(vgmstream->current_block_size, vgmstream->interleave_block_size, 1);
}
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
block_update(start_offset, vgmstream);
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
/* EA WVE (VLC0/au00) - from Electronic Arts PS movies [Future Cop - L.A.P.D. (PS), Supercross 2000 (PS)] */
VGMSTREAM* init_vgmstream_ea_wve_au00(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channels;
/* checks */
if (!is_id32be(0x00,sf, "VLC0"))
return NULL;
/* .wve: common, .fsv: Future Cop LAPD (PS1) */
if (!check_extensions(sf, "wve,fsv"))
return NULL;
start_offset = read_32bitBE(0x04,sf);
if (!is_id32be(start_offset, sf, "au00") &&
!is_id32be(start_offset, sf, "au01")) // last block, but could be first)
return NULL;
loop_flag = 0;
channels = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_EA_WVE_AU00;
vgmstream->sample_rate = 22050;
/* You'd think they'd use coding_EA_XA_int but instead it's PS-ADPCM without flags and 0x0f frame size
* (equivalent to configurable PS-ADPCM), surely to shoehorn EA-XA sizes into the PS1 hardware decoder */
vgmstream->coding_type = coding_PSX_cfg;
vgmstream->interleave_block_size = 0x0f;
vgmstream->layout_type = layout_blocked_ea_wve_au00;
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
goto fail;
/* calc num_samples manually */
{
vgmstream->next_block_offset = start_offset;
do {
block_update(vgmstream->next_block_offset,vgmstream);
vgmstream->num_samples += ps_cfg_bytes_to_samples(vgmstream->current_block_size, vgmstream->interleave_block_size, 1);
}
while (vgmstream->next_block_offset < get_streamfile_size(sf));
block_update(start_offset, vgmstream);
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1,113 +1,117 @@
#include "meta.h"
#include "../coding/coding.h"
/* FLX - from Ultima IX (.FLX is actually an archive format with sometimes sound data, let's support both anyway) */
VGMSTREAM * init_vgmstream_flx(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, stream_offset = 0;
size_t data_size;
int loop_flag, channel_count, codec;
int total_subsongs = 0, target_subsong = streamFile->stream_index;
size_t stream_size = 0;
/* check extensions (.flx: name of archive, files inside don't have extensions) */
if (!check_extensions(streamFile,"flx"))
goto fail;
/* all spaces up to 0x50 = archive FLX */
if (read_32bitBE(0x00,streamFile) == 0x20202020 && read_32bitBE(0x40,streamFile) == 0x20202020) {
int i;
int entries = read_32bitLE(0x50,streamFile);
off_t offset = 0x80;
if (read_32bitLE(0x54,streamFile) != 0x02
|| read_32bitLE(0x58,streamFile) != get_streamfile_size(streamFile))
goto fail;
if (target_subsong == 0) target_subsong = 1;
for (i = 0; i < entries; i++) {
off_t entry_offset = read_32bitLE(offset + 0x00, streamFile);
size_t entry_size = read_32bitLE(offset + 0x04, streamFile);
offset += 0x08;
if (entry_offset != 0x00)
total_subsongs++; /* many entries are empty */
if (total_subsongs == target_subsong && stream_offset == 0) {
stream_offset = entry_offset; /* found but let's keep adding total_streams */
stream_size = entry_size;
}
}
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
if (stream_offset == 0x00) goto fail;
}
else {
stream_offset = 0x00;
stream_size = get_streamfile_size(streamFile);
}
if (read_32bitLE(stream_offset + 0x30,streamFile) != 0x10)
goto fail;
data_size = read_32bitLE(stream_offset + 0x28,streamFile);
channel_count = read_32bitLE(stream_offset + 0x34,streamFile);
codec = read_32bitLE(stream_offset + 0x38,streamFile);
loop_flag = (channel_count > 1); /* full seamless repeats in music */
start_offset = stream_offset + 0x3c;
/* 0x00: id */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(stream_offset + 0x2c,streamFile);
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_PC_FLX;
switch(codec) {
case 0x00: /* PCM (sfx) */
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, 16);
break;
case 0x01: /* EA-XA (music, sfx) */
vgmstream->coding_type = channel_count > 1 ? coding_EA_XA : coding_EA_XA_int;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = read_32bitLE(stream_offset + 0x28,streamFile) / 0x0f*channel_count * 28; /* ea_xa_bytes_to_samples */
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
break;
case 0x02: /* EA-MT (voices) */
vgmstream->coding_type = coding_EA_MT;
vgmstream->layout_type = layout_none;
vgmstream->codec_data = init_ea_mt(vgmstream->channels, 0);
if (!vgmstream->codec_data) goto fail;
vgmstream->num_samples = read_32bitLE(start_offset,streamFile);
start_offset += 0x04;
break;
default:
VGM_LOG("FLX: unknown codec 0x%x\n", codec);
goto fail;
}
read_string(vgmstream->stream_name,0x20+1, stream_offset + 0x04,streamFile);
/* open the file for reading */
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"
/* .FLX - from Ultima IX (PC) */
VGMSTREAM* init_vgmstream_flx(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset, stream_offset = 0;
size_t data_size;
int loop_flag, channels, codec;
int total_subsongs = 0, target_subsong = sf->stream_index;
size_t stream_size = 0;
/* checks */
/* .flx: name of archive (filenames inside don't have extensions) */
if (!check_extensions(sf,"flx,"))
return NULL;
// .FLX an archive format with sometimes sound data, let's support both anyway
// all spaces up to 0x50 = archive FLX
if (is_id32be(0x00,sf, " ") && is_id32be(0x40,sf, " ")) {
int entries = read_s32le(0x50,sf);
if (read_u32le(0x54,sf) != 0x02)
return NULL;
if (read_u32le(0x58,sf) != get_streamfile_size(sf))
return NULL;
if (target_subsong == 0) target_subsong = 1;
uint32_t offset = 0x80;
for (int i = 0; i < entries; i++) {
off_t entry_offset = read_u32le(offset + 0x00, sf);
size_t entry_size = read_u32le(offset + 0x04, sf);
offset += 0x08;
if (entry_offset != 0x00)
total_subsongs++; /* many entries are empty */
if (total_subsongs == target_subsong && stream_offset == 0) {
stream_offset = entry_offset; /* found but let's keep adding total_streams */
stream_size = entry_size;
}
}
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
if (stream_offset == 0x00)
return NULL;
}
else {
stream_offset = 0x00;
stream_size = get_streamfile_size(sf);
}
// file ID, can be a bit higher in sfx packs
if (read_u32le(stream_offset + 0x00,sf) >= 0x10000)
return NULL;
// 04: filename
if (read_u32le(stream_offset + 0x30,sf) != 0x10)
return NULL;
data_size = read_u32le(stream_offset + 0x28,sf);
channels = read_s32le(stream_offset + 0x34,sf);
codec = read_u32le(stream_offset + 0x38,sf);
loop_flag = (channels > 1); /* full seamless repeats in music */
start_offset = stream_offset + 0x3c;
/* 0x00: id */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(stream_offset + 0x2c,sf);
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_PC_FLX;
switch(codec) {
case 0x00: /* PCM (sfx) */
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channels, 16);
break;
case 0x01: /* EA-XA (music, sfx) */
vgmstream->coding_type = channels > 1 ? coding_EA_XA : coding_EA_XA_int;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = read_32bitLE(stream_offset + 0x28,sf) / 0x0f*channels * 28; /* ea_xa_bytes_to_samples */
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
break;
case 0x02: /* EA-MT (voices) */
vgmstream->coding_type = coding_EA_MT;
vgmstream->layout_type = layout_none;
vgmstream->codec_data = init_ea_mt(vgmstream->channels, 0);
if (!vgmstream->codec_data) goto fail;
vgmstream->num_samples = read_32bitLE(start_offset,sf);
start_offset += 0x04;
break;
default:
VGM_LOG("FLX: unknown codec 0x%x\n", codec);
goto fail;
}
read_string(vgmstream->stream_name,0x20+1, stream_offset + 0x04,sf);
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -70,9 +70,10 @@ static const fsbkey_info fsbkey_list[] = {
{ MODE_FSB5, FSBKEY_ADD("3cfe772db5b55b806541d3faf894020e") }, // Final Fantasy XV: War for Eos (Android)
{ MODE_FSB5, FSBKEY_ADD("aj#$kLucf2lh}eqh") }, // Forza Motorsport 2023 (PC)
{ MODE_FSB4, FSBKEY_ADD("dpdjeoqkr") }, // AirRider CrazyRacing (PC)
{ MODE_FSB5, FSBKEY_ADD("weareAbsolutelyUnsure2018") }, // Wanderstop (PC)
{ MODE_FSB5, FSBKEY_ADD(".xW3uXQ8q79yunvMjL6nahLXts9esEXX2VgetuPCxdLrAjUUbZAmB7R*A6KjW24NU_8ifMZ8TC4Qk@_oEsjsK2QLpAaG-Fy!wYKP") }, // UNBEATABLE Demo (PC)
{ MODE_FSB5, FSBKEY_ADD(",H9}:p?`bRlQG5_yJ\"\"/L,X_{:=Gs1") }, // Rennsport (PC)
{ MODE_FSB5, FSBKEY_ADD("weareAbsolutelyUnsure2018") }, // Wanderstop (PC)
{ MODE_FSB5, FSBKEY_ADD(".xW3uXQ8q79yunvMjL6nahLXts9esEXX2VgetuPCxdLrAjUUbZAmB7R*A6KjW24NU_8ifMZ8TC4Qk@_oEsjsK2QLpAaG-Fy!wYKP") }, // UNBEATABLE Demo (PC)
{ MODE_FSB5, FSBKEY_ADD(",H9}:p?`bRlQG5_yJ\"\"/L,X_{:=Gs1") }, // Rennsport (PC)
{ MODE_FSB5, FSBKEY_ADD("K50j8B2H4pVUfzt7yxfTprg9wdr9zIH6") }, // Gunner, HEAT, PC! (PC)
/* some games use a key per file, generated from the filename
* (could add all of them but there are a lot of songs, so external .fsbkey are probably better) */

View file

@ -1575,6 +1575,8 @@ static const hcakey_info hcakey_list[] = {
// Patapon 1 & 2 Reloaded (PC)
{3316332033470531258}, // 2E05FA69EC4286BA
// Aether Gazer (multi)
{1578660190369042886}, // 15E887143BFF51C6
};
#endif

View file

@ -194,8 +194,9 @@ VGMSTREAM * init_vgmstream_pos(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_nwa(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_1snh(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_eacs(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_ea_1snh(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ea_eacs(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ea_crdf(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_xss(STREAMFILE * streamFile);
@ -290,8 +291,8 @@ VGMSTREAM * init_vgmstream_fag(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_mic(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ngc_pdt_split(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ngc_pdt(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_pdt(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_pdt_split(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_mus_krome(STREAMFILE* sf);
@ -304,8 +305,6 @@ VGMSTREAM* init_vgmstream_spsd(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_bgw(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_spw(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_ass(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ubi_jade(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ubi_jade_container(STREAMFILE * streamFile);
@ -392,8 +391,6 @@ VGMSTREAM * init_vgmstream_gcub(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_maxis_xa(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ngc_sck_dsp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_apple_caff(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_pc_mxst(STREAMFILE* streamFile);
@ -578,20 +575,24 @@ VGMSTREAM * init_vgmstream_xa_04sw(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_txth(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ea_schl_video(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_abk_schl(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_amb_schl(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_hdr_dat(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_hdr_dat_v2(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_map_mus(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_mpf_mus_schl(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_msb_mus_schl(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_ea_schl(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ea_schl_video(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ea_bnk(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ea_abk_schl(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ea_amb_schl(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ea_hdr_dat(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ea_hdr_dat_v2(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ea_map_mus(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ea_mpf_mus_schl(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ea_msb_mus_schl(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ea_pt(STREAMFILE* sf);
VGMSTREAM* load_vgmstream_ea_bnk(STREAMFILE* sf, off_t offset, int target_stream, int is_embedded);
VGMSTREAM* load_vgmstream_ea_schl(STREAMFILE* sf, off_t offset);
VGMSTREAM* load_vgmstream_ea_pt(STREAMFILE* sf_head, STREAMFILE* sf_body, off_t head_offset, size_t head_size, off_t body_offset);
VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_ea_patl(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ea_schl_fixed(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ea_bnk_fixed(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_sk_aud(STREAMFILE * streamFile);
@ -692,7 +693,7 @@ VGMSTREAM * init_vgmstream_sthd(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ngc_dsp_std_le(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_pcm_sre(STREAMFILE *streamFile);
VGMSTREAM* init_vgmstream_sre_pcm(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ubi_lyn(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ubi_lyn_container(STREAMFILE * streamFile);

View file

@ -29,17 +29,13 @@ VGMSTREAM* init_vgmstream_mhwk(STREAMFILE* sf) {
chunk_size = read_u32be(current_offset + 0x04, sf);
current_offset += 0x08;
if (chunk_id == get_id32be("Cue#")) {
current_offset += chunk_size;
continue;
}
else if (chunk_id == get_id32be("ADPC")) {
current_offset += chunk_size;
continue;
}
else if (chunk_id == get_id32be("Data")) {
if (chunk_id == get_id32be("Data")) {
break;
}
else if (chunk_id == get_id32be("Cue#") || chunk_id == get_id32be("ADPC")) {
current_offset += chunk_size;
continue;
}
else {
goto fail;
}
@ -88,6 +84,17 @@ VGMSTREAM* init_vgmstream_mhwk(STREAMFILE* sf) {
vgmstream->coding_type = coding_IMA;
vgmstream->layout_type = layout_none;
break;
//Riven DVD
case 0x0002: /* MPEG Layer II */
#if defined(VGM_USE_MPEG)
vgmstream->coding_type = coding_MPEG_layer2;
#elif defined(VGM_USE_FFMPEG)
vgmstream->coding_type = coding_FFmpeg;
#else
goto fail;
#endif
vgmstream->layout_type = layout_none;
break;
default: /* Unknown format */
goto fail;

View file

@ -26,14 +26,14 @@ VGMSTREAM* init_vgmstream_mp4_aac_ffmpeg(STREAMFILE* sf) {
/* checks */
if ((read_u32be(0x00,sf) & 0xFFFFFF00) != 0) /* first atom BE size (usually ~0x18) */
goto fail;
return NULL;
if (!is_id32be(0x04,sf, "ftyp"))
goto fail;
return NULL;
/* .bin: Final Fantasy Dimensions (iOS), Final Fantasy V (iOS)
* .msd: UNO (iOS) */
if (!check_extensions(sf,"mp4,m4a,m4v,lmp4,bin,lbin,msd"))
goto fail;
return NULL;
file_size = get_streamfile_size(sf);
@ -180,56 +180,4 @@ static void parse_mp4(STREAMFILE* sf, mp4_header* mp4) {
}
}
/* CRI's encryption info (for lack of a better place) [Final Fantasy Digital Card Game (Browser)]
*
* Like other CRI stuff their MP4 can be encrypted, from file's beginning (including headers).
* This is more or less how data is decrypted (supposedly, from decompilations), for reference:
*/
#if 0
void criAacCodec_SetDecryptionKey(uint64_t keycode, uint16_t* key) {
if (!keycode)
return;
uint16_t k0 = 4 * ((keycode >> 0) & 0x0FFF) | 1;
uint16_t k1 = 2 * ((keycode >> 12) & 0x1FFF) | 1;
uint16_t k2 = 4 * ((keycode >> 25) & 0x1FFF) | 1;
uint16_t k3 = 2 * ((keycode >> 38) & 0x3FFF) | 1;
key[0] = k0 ^ k1;
key[1] = k1 ^ k2;
key[2] = k2 ^ k3;
key[3] = ~k3;
/* criatomexacb_generate_aac_decryption_key is slightly different, unsure which one is used: */
//key[0] = k0 ^ k3;
//key[1] = k2 ^ k3;
//key[2] = k2 ^ k3;
//key[3] = ~k3;
}
void criAacCodec_DecryptData(const uint16_t* key, uint8_t* data, uint32_t size) {
if (data_size)
return;
uint16_t seed0 = ~key[3];
uint16_t seed1 = seed0 ^ key[2];
uint16_t seed2 = seed1 ^ key[1];
uint16_t seed3 = seed2 ^ key[0];
uint16_t xor = 2 * seed0 | 1;
uint16_t add = 2 * seed0 | 1; /* not seed1 */
uint16_t mul = 4 * seed2 | 1;
for (int i = 0; i < data_size; i++) {
if (!(uint16_t)i) { /* every 0x10000, without modulo */
mul = (4 * seed2 + seed3 * (mul & 0xFFFC)) & 0xFFFD | 1;
add = (2 * seed0 + seed1 * (add & 0xFFFE)) | 1;
}
xor = xor * mul + add;
*data ^= (xor >> 8) & 0xFF;
++data;
}
}
#endif
#endif

View file

@ -1,55 +0,0 @@
#include "meta.h"
#include "../coding/coding.h"
//todo this was extracted from a .pak bigfile. Inside are headers then data (no extensions),
// but headers are VAGp in the PS2 version, so it would make more sense to extract pasting
// header+data together, or support as-is (.SCK is a fake extension).
/* SCK+DSP - Scorpion King (GC) */
VGMSTREAM * init_vgmstream_ngc_sck_dsp(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * streamHeader = NULL;
int channel_count, loop_flag;
size_t data_size;
/* check extension, case insensitive */
if (!check_extensions(streamFile, "dsp"))
goto fail;
streamHeader = open_streamfile_by_ext(streamFile, "sck");
if (!streamHeader) goto fail;
if (read_32bitBE(0x5C,streamHeader) != 0x60A94000)
goto fail;
channel_count = 2;
loop_flag = 0;
data_size = read_32bitBE(0x14,streamHeader);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitBE(0x18,streamHeader);
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitBE(0xC,streamHeader);
if (vgmstream->interleave_block_size > 0)
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size * channel_count)) / channel_count;
vgmstream->meta_type = meta_NGC_SCK_DSP;
dsp_read_coefs_be(vgmstream,streamHeader, 0x2c, 0x00);
if (!vgmstream_open_stream(vgmstream,streamFile,0x00))
goto fail;
close_streamfile(streamHeader);
return vgmstream;
fail:
close_streamfile(streamHeader);
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1,76 +0,0 @@
#include "meta.h"
#include "../coding/coding.h"
/* .PCM+SRE. - Capcom's header+data container thing [Viewtiful Joe (PS2)] */
VGMSTREAM * init_vgmstream_pcm_sre(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * streamHeader = NULL;
off_t start_offset;
int loop_flag, channel_count;
size_t table1_entries, table2_entries;
off_t table1_offset, table2_offset, header_offset;
int total_subsongs, target_subsong = streamFile->stream_index;
/* checks */
/* .pcm=data, .sre=header */
if (!check_extensions(streamFile, "pcm"))
goto fail;
/* first PS-ADPCM frame should be is null */
if (read_32bitBE(0x00,streamFile) != 0x00020000 ||
read_32bitBE(0x04,streamFile) != 0x00000000 ||
read_32bitBE(0x08,streamFile) != 0x00000000 ||
read_32bitBE(0x0c,streamFile) != 0x00000000)
goto fail;
streamHeader = open_streamfile_by_ext(streamFile, "sre");
if (!streamHeader) goto fail;
table1_entries = read_32bitLE(0x00, streamHeader);
table1_offset = read_32bitLE(0x04, streamHeader);
table2_entries = read_32bitLE(0x08, streamHeader);
table2_offset = read_32bitLE(0x0c, streamHeader);
if (table1_entries*0x60 + table1_offset != table2_offset)
goto fail; /* just in case */
total_subsongs = table2_entries;
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
header_offset = table2_offset + (target_subsong-1)*0x20;
channel_count = read_32bitLE(header_offset+0x00,streamHeader);
loop_flag = read_32bitLE(header_offset+0x18,streamHeader);
start_offset = read_32bitLE(header_offset+0x08,streamHeader);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_16bitLE(header_offset+0x04,streamHeader);
vgmstream->meta_type = meta_PCM_SRE;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x1000;
vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(header_offset+0x0c,streamHeader), channel_count);
vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(header_offset+0x10,streamHeader)*channel_count, channel_count);
vgmstream->loop_end_sample = ps_bytes_to_samples(read_32bitLE(header_offset+0x14,streamHeader)*channel_count, channel_count);
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = read_32bitLE(header_offset+0x0c,streamHeader);
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
close_streamfile(streamHeader);
return vgmstream;
fail:
close_streamfile(streamHeader);
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1,214 +1,211 @@
#include "meta.h"
#include "../coding/coding.h"
/* PDT - Hudson's stream container [Adventure Island (GC), Muscle Champion (GC), Mario Party series (GC)] */
VGMSTREAM * init_vgmstream_ngc_pdt(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int loop_flag, channel_count, sample_rate;
size_t entries, nibble_size, loop_start;
off_t entries_offset, coefs_offset, header_offset;
off_t channel1_offset = 0, channel2_offset = 0, coef_offset = 0;
int total_subsongs, target_subsong = streamFile->stream_index;
/* checks */
if (!check_extensions(streamFile, "pdt"))
goto fail;
if (read_16bitBE(0x00,streamFile) != 0x01) /* version? */
goto fail;
if (read_32bitBE(0x04,streamFile) != 0x02 && /* Mario Party 4 (GC) */
read_32bitBE(0x04,streamFile) != 0x04) /* Cubic Lode Runner (GC) */
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x7d00) /* not-sample rate? */
goto fail;
if (read_32bitBE(0x0c,streamFile) != 0x02 && /* not-channels? */
read_32bitBE(0x0c,streamFile) != 0x04)
goto fail;
entries = read_16bitBE(0x02,streamFile);
entries_offset = read_32bitBE(0x10,streamFile);
coefs_offset = read_32bitBE(0x14,streamFile);
//headers_offset = read_32bitBE(0x18,streamFile); /* we'll have pointers to those two */
//streams_offset = read_32bitBE(0x1c,streamFile);
/* find subsongs and target header, as entries can be empty/repeated */
{
/* tables to cache reads as it can be kinda slow with so many loops */
uint32_t data_offsets[0x2000];
uint32_t entry_offset, data_offset;
int i,j;
if (entries > 0x2000)
goto fail;
total_subsongs = 0;
if (target_subsong == 0) target_subsong = 1;
header_offset = 0;
for (i = 0; i < entries; i++) {
int is_unique = 1;
entry_offset = read_32bitBE(entries_offset + i*0x04,streamFile);
if (entry_offset == 0x00)
continue;
data_offset = read_32bitBE(entry_offset+0x10,streamFile);
/* check if current entry header was repeated (same file offset, difference in flags only) */
for (j = 0; j < total_subsongs; j++) {
if (data_offsets[j] == data_offset) {
is_unique = 0;
break;
}
}
if (!is_unique)
continue;
data_offsets[total_subsongs] = data_offset;
total_subsongs++;
/* target GET, but keep going to count subsongs */
if (!header_offset && target_subsong == total_subsongs) {
header_offset = entry_offset;
}
}
}
/* parse header */
{
uint8_t flags;
size_t coef1_entry;
off_t coef1_offset;
flags = read_8bit(header_offset+0x00,streamFile);
sample_rate = read_32bitBE(header_offset+0x04,streamFile);
/* 0x01: unknown + 0x4000 */
sample_rate = read_32bitBE(header_offset+0x04,streamFile);
nibble_size = read_32bitBE(header_offset+0x08,streamFile);
loop_start = read_32bitBE(header_offset+0x0c,streamFile);
channel1_offset = read_32bitBE(header_offset+0x10,streamFile);
coef1_entry = read_16bitBE(header_offset+0x14,streamFile);
coef1_offset = coefs_offset + coef1_entry*0x20;
if (flags & 0x01) {
//size_t coef2_entry;
//off_t coef2_offset;
channel2_offset = read_32bitBE(header_offset+0x18,streamFile);
/* always after coef1 in practice */
//coef2_entry = read_16bitBE(header_offset+0x1c,streamFile);
//coef2_offset = coefs_offset + coef2_entry*0x20;
//if (coef1_offset + 0x20 != coef2_offset)
// goto fail;
}
coef_offset = coef1_offset;
loop_flag = (flags & 0x02);
channel_count = (flags & 0x01) ? 2 : 1;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
//vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);//todo remove
vgmstream->num_samples = dsp_nibbles_to_samples(nibble_size);
//vgmstream->loop_start_sample = dsp_bytes_to_samples(loop_start, channel_count);//todo remove
vgmstream->loop_start_sample = dsp_nibbles_to_samples(loop_start);
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->meta_type = meta_NGC_PDT;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
dsp_read_coefs_be(vgmstream, streamFile, coef_offset, 0x20);
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = nibble_size / 2 * channel_count;
if (!vgmstream_open_stream(vgmstream,streamFile,channel1_offset))
goto fail;
/* channels may start at slightly separated offsets */
if (channel_count == 2) {
vgmstream->ch[1].channel_start_offset =
vgmstream->ch[1].offset = channel2_offset;
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* PDT - custom fake header for split (PDTExt) .ptd [Mario Party (GC)] */
VGMSTREAM * init_vgmstream_ngc_pdt_split(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
/* checks */
if (!check_extensions(streamFile, "pdt"))
goto fail;
/* 0x10 fake header + chunks of the original header / data pasted together */
if (read_32bitBE(0x00,streamFile) != 0x50445420 && /* "PDT " */
read_32bitBE(0x04,streamFile) != 0x44535020 && /* "DSP " */
read_32bitBE(0x08,streamFile) != 0x48454144 && /* "HEAD " */
read_16bitBE(0x0C,streamFile) != 0x4552) /* "ER " */
goto fail;
start_offset = 0x800;
channel_count = (uint16_t)(read_16bitLE(0x0E,streamFile));
loop_flag = (read_32bitBE(0x1C,streamFile) != 2);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitBE(0x14,streamFile);
if (channel_count == 1) {
vgmstream->num_samples = read_32bitBE(0x18,streamFile)*14/8/channel_count/2;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitBE(0x1C,streamFile)*14/8/channel_count/2;
vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile)*14/8/channel_count/2;
}
}
else if (channel_count == 2) {
vgmstream->num_samples = read_32bitBE(0x18,streamFile)*14/8/channel_count;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitBE(0x1C,streamFile)*14/8/channel_count;
vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile)*14/8/channel_count;
}
}
else {
goto fail;
}
vgmstream->meta_type = meta_NGC_PDT;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
dsp_read_coefs_be(vgmstream, streamFile, 0x50, 0x20);
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
if (channel_count == 2) {
vgmstream->ch[1].channel_start_offset =
vgmstream->ch[1].offset = ((get_streamfile_size(streamFile)+start_offset) / channel_count);
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* .PDT - Hudson's stream container [Adventure Island (GC), Muscle Champion (GC), Mario Party series (GC)] */
VGMSTREAM* init_vgmstream_pdt(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
int loop_flag, channel_count, sample_rate;
size_t entries, nibble_size, loop_start;
off_t entries_offset, coefs_offset, header_offset;
off_t channel1_offset = 0, channel2_offset = 0, coef_offset = 0;
int total_subsongs, target_subsong = sf->stream_index;
/* checks */
if (!check_extensions(sf, "pdt"))
return NULL;
if (read_16bitBE(0x00,sf) != 0x01) /* version? */
return NULL;
if (read_32bitBE(0x04,sf) != 0x02 && /* Mario Party 4 (GC) */
read_32bitBE(0x04,sf) != 0x04) /* Cubic Lode Runner (GC) */
return NULL;
if (read_32bitBE(0x08,sf) != 0x7d00) /* not-sample rate? */
return NULL;
if (read_32bitBE(0x0c,sf) != 0x02 && /* not-channels? */
read_32bitBE(0x0c,sf) != 0x04)
return NULL;
entries = read_16bitBE(0x02,sf);
entries_offset = read_32bitBE(0x10,sf);
coefs_offset = read_32bitBE(0x14,sf);
//headers_offset = read_32bitBE(0x18,streamFile); /* we'll have pointers to those two */
//streams_offset = read_32bitBE(0x1c,streamFile);
/* find subsongs and target header, as entries can be empty/repeated */
{
/* tables to cache reads as it can be kinda slow with so many loops */
uint32_t data_offsets[0x2000];
uint32_t entry_offset, data_offset;
if (entries > 0x2000)
goto fail;
total_subsongs = 0;
if (target_subsong == 0) target_subsong = 1;
header_offset = 0;
for (int i = 0; i < entries; i++) {
int is_unique = 1;
entry_offset = read_32bitBE(entries_offset + i*0x04,sf);
if (entry_offset == 0x00)
continue;
data_offset = read_32bitBE(entry_offset+0x10,sf);
/* check if current entry header was repeated (same file offset, difference in flags only) */
for (int j = 0; j < total_subsongs; j++) {
if (data_offsets[j] == data_offset) {
is_unique = 0;
break;
}
}
if (!is_unique)
continue;
data_offsets[total_subsongs] = data_offset;
total_subsongs++;
/* target GET, but keep going to count subsongs */
if (!header_offset && target_subsong == total_subsongs) {
header_offset = entry_offset;
}
}
}
/* parse header */
{
uint8_t flags;
size_t coef1_entry;
off_t coef1_offset;
flags = read_8bit(header_offset+0x00,sf);
sample_rate = read_32bitBE(header_offset+0x04,sf);
/* 0x01: unknown + 0x4000 */
sample_rate = read_32bitBE(header_offset+0x04,sf);
nibble_size = read_32bitBE(header_offset+0x08,sf);
loop_start = read_32bitBE(header_offset+0x0c,sf);
channel1_offset = read_32bitBE(header_offset+0x10,sf);
coef1_entry = read_16bitBE(header_offset+0x14,sf);
coef1_offset = coefs_offset + coef1_entry*0x20;
if (flags & 0x01) {
//size_t coef2_entry;
//off_t coef2_offset;
channel2_offset = read_32bitBE(header_offset+0x18,sf);
/* always after coef1 in practice */
//coef2_entry = read_16bitBE(header_offset+0x1c,streamFile);
//coef2_offset = coefs_offset + coef2_entry*0x20;
//if (coef1_offset + 0x20 != coef2_offset)
// goto fail;
}
coef_offset = coef1_offset;
loop_flag = (flags & 0x02);
channel_count = (flags & 0x01) ? 2 : 1;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
//vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);//todo remove
vgmstream->num_samples = dsp_nibbles_to_samples(nibble_size);
//vgmstream->loop_start_sample = dsp_bytes_to_samples(loop_start, channel_count);//todo remove
vgmstream->loop_start_sample = dsp_nibbles_to_samples(loop_start);
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->meta_type = meta_PDT;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
dsp_read_coefs_be(vgmstream, sf, coef_offset, 0x20);
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = nibble_size / 2 * channel_count;
if (!vgmstream_open_stream(vgmstream,sf,channel1_offset))
goto fail;
/* channels may start at slightly separated offsets */
if (channel_count == 2) {
vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset = channel2_offset;
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* PDT - custom fake header for split (PDTExt) .ptd [Mario Party (GC)] */
VGMSTREAM* init_vgmstream_pdt_split(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channels;
/* checks */
if (!check_extensions(sf, "pdt"))
return NULL;
/* 0x10 fake header + chunks of the original header / data pasted together */
if (read_32bitBE(0x00,sf) != 0x50445420 && /* "PDT " */
read_32bitBE(0x04,sf) != 0x44535020 && /* "DSP " */
read_32bitBE(0x08,sf) != 0x48454144 && /* "HEAD " */
read_16bitBE(0x0C,sf) != 0x4552) /* "ER " */
goto fail;
start_offset = 0x800;
channels = (uint16_t)(read_16bitLE(0x0E,sf));
loop_flag = (read_32bitBE(0x1C,sf) != 2);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitBE(0x14,sf);
if (channels == 1) {
vgmstream->num_samples = read_32bitBE(0x18,sf)*14/8/channels/2;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitBE(0x1C,sf)*14/8/channels/2;
vgmstream->loop_end_sample = read_32bitBE(0x18,sf)*14/8/channels/2;
}
}
else if (channels == 2) {
vgmstream->num_samples = read_32bitBE(0x18,sf)*14/8/channels;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitBE(0x1C,sf)*14/8/channels;
vgmstream->loop_end_sample = read_32bitBE(0x18,sf)*14/8/channels;
}
}
else {
goto fail;
}
vgmstream->meta_type = meta_PDT;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
dsp_read_coefs_be(vgmstream, sf, 0x50, 0x20);
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
goto fail;
if (channels == 2) {
vgmstream->ch[1].channel_start_offset =
vgmstream->ch[1].offset = ((get_streamfile_size(sf)+start_offset) / channels);
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -1,106 +1,135 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
#include <string.h>
static int get_adm_loop_info(STREAMFILE *streamFile, off_t *loop_start_offset);
/* .adm - from Dragon Quest V (PS2) */
VGMSTREAM * init_vgmstream_ps2_adm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int channel_count, loop_flag = 0;
off_t start_offset, loop_start_offset = 0;
/* checks */
if (!check_extensions(streamFile,"adm"))
goto fail;
/* raw data, but test some .ADM blocks as they always start with PS-ADPCM flag 0x06 every 0x1000 */
{
int i;
for (i = 0; i < 10; i++) {
if (read_8bit(0x1000*i + 0x01, streamFile) != 0x06)
goto fail;
}
}
start_offset = 0x00;
loop_flag = get_adm_loop_info(streamFile, &loop_start_offset);
channel_count = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_PS2_ADM;
vgmstream->sample_rate = 44100;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_adm;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
/* calc num_samples as playable data size varies between files/blocks */
{
vgmstream->next_block_offset = start_offset;
do {
block_update(vgmstream->next_block_offset,vgmstream);
if (loop_flag && vgmstream->current_block_offset == loop_start_offset)
vgmstream->loop_start_sample = vgmstream->num_samples;
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
}
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
block_update(start_offset,vgmstream);
if (loop_flag)
vgmstream->loop_end_sample = vgmstream->num_samples;
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* loops are not in the .ADM or .DAT bigfile containing them but in the exe; manually get them (a bit meh but whatevs) */
static int get_adm_loop_info(STREAMFILE *streamFile, off_t *loop_start_offset) {
char file_name[PATH_LIMIT];
char index_name[PATH_LIMIT];
STREAMFILE *streamExe = NULL;
int i, name_index = -1, loop_flag;
off_t offset;
streamExe = open_streamfile_by_filename(streamFile, "SLPM_655.55");
if (!streamExe) goto fail;
get_streamfile_filename(streamFile, file_name, PATH_LIMIT);
/* get file index from name list (file_name == index_name = index number */
offset = 0x23B3c0;
for (i = 0; i < 51; i++) {
read_string(index_name,0x20+1, offset,streamExe);
if (strcmp(index_name, file_name)==0) {
name_index = i;
break;
}
offset += 0x20;
}
if (name_index < 0)
goto fail;
/* get file info using index */
offset = 0x23BAEC + 0x1c*name_index;
loop_flag = (read_32bitLE(offset + 0x10, streamExe) == 0); /* 1: don't loop, 0: loop */
if (loop_flag) { /* loop flag */
*loop_start_offset = read_32bitLE(offset + 0x04, streamExe);
}
/* 0x08: num_samples/loop_end, 0x0c: sample rate (always 44100), 0x14/18: some size? */
close_streamfile(streamExe);
return loop_flag;
fail:
close_streamfile(streamExe);
return 0;
}
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
#include <string.h>
static int get_adm_loop_info(STREAMFILE *streamFile, off_t *loop_start_offset);
/* .adm - from Dragon Quest V (PS2) */
VGMSTREAM* init_vgmstream_ps2_adm(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
int channels, loop_flag = 0;
off_t start_offset, loop_start_offset = 0;
/* checks */
if (!check_extensions(sf,"adm"))
return NULL;
//TODO improve/move to .txth (block behavior must be handled in vgmstream though)
// - most blocks end with a 0x03 flag + 0x10 padding, then next blocks restarts with 0x06 flag
// - MTXADPCM.IRX reads a 0x400 L block then R block, doesn't seem to do any block handling
// - padded blocks don't seem consistent or depends on size/loop/etc:
// (but there seems to be 4 parts in looped files and 2 in non-looped)
// - MS_overture_lp.adm (loop offset 0x2B2000)
// - 0x000000~0x020000: padding (all blocks end with 0x03 flag + 0x10 padding)
// - 0x020000~0x2B2800: no padding (only last LR block ends with 0x03 flags)
// - 0x2B2800~0x2FA800: padding (all blocks)
// - 0x2FB000~0x442000: no padding
// - MS_saint.adm (loop offset 0x082000)
// - 0x000000~0x04E000: padding
// - 0x04E000~0x082800: no padding
// - 0x082800~0x0CF000: padding
// - 0x0CF000~0x40B000: no padding
// - MS_item.adm
// - 0x000000~0x016000: padding
// - 0x016000~0x01A000: no padding
// - possibly automatically handled by SPU2
// - 0x03 flag > ends playback > immediately gets next block = no audio skips
/* raw data, but test some .ADM blocks as they always start with PS-ADPCM flag 0x06 every 0x1000 */
for (int i = 0; i < 10; i++) {
if (read_u8(0x1000 * i + 0x01, sf) != 0x06)
return NULL;
}
start_offset = 0x00;
loop_flag = get_adm_loop_info(sf, &loop_start_offset);
channels = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
// TODO use info from header
vgmstream->meta_type = meta_PS2_ADM;
vgmstream->sample_rate = 44100;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_adm;
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
goto fail;
/* calc num_samples as playable data size varies between files/blocks */
{
vgmstream->next_block_offset = start_offset;
do {
block_update(vgmstream->next_block_offset,vgmstream);
if (loop_flag && vgmstream->current_block_offset == loop_start_offset)
vgmstream->loop_start_sample = vgmstream->num_samples;
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
}
while (vgmstream->next_block_offset < get_streamfile_size(sf));
block_update(start_offset,vgmstream);
if (loop_flag)
vgmstream->loop_end_sample = vgmstream->num_samples;
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* loops are not in the .ADM or .DAT bigfile containing them but in the exe; manually get them (a bit meh but whatevs) */
static int get_adm_loop_info(STREAMFILE* sf, off_t *loop_start_offset) {
char file_name[PATH_LIMIT];
char index_name[PATH_LIMIT];
STREAMFILE *sh = NULL;
int i, name_index = -1, loop_flag;
off_t offset;
sh = open_streamfile_by_filename(sf, "SLPM_655.55");
if (!sh) goto fail;
get_streamfile_filename(sf, file_name, PATH_LIMIT);
/* get file index from name list (file_name == index_name = index number */
offset = 0x23B3c0;
for (i = 0; i < 51; i++) {
read_string(index_name,0x20+1, offset,sh);
if (strcmp(index_name, file_name)==0) {
name_index = i;
break;
}
offset += 0x20;
}
if (name_index < 0)
goto fail;
/* get file info using index */
offset = 0x23BAF0 + 0x1c * name_index;
loop_flag = (read_32bitLE(offset + 0x0c, sh) == 0); /* 1: don't loop, 0: loop */
if (loop_flag) { /* loop flag */
*loop_start_offset = read_32bitLE(offset + 0x00, sh);
}
// 23BA20 = adpcm volumes?
// 23BAF0 = adpcm info
// 00: loop start offset
// 04: loop end (size)
// 08: sample rate
// 0c: loop flag (0=inf, 1=no loop)
// 10: loop start block (in 0x800 sizes)
// 14: loop length block (in 0x800 sizes)
// 18: null
close_streamfile(sh);
return loop_flag;
fail:
close_streamfile(sh);
return 0;
}

View file

@ -1,51 +0,0 @@
#include "meta.h"
#include "../coding/coding.h"
/* .ASS - from Dai Senryaku VII: Exceed (PS2) */
VGMSTREAM * init_vgmstream_ps2_ass(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
size_t channel_size, interleave;
int loop_flag, channel_count, sample_rate;
int32_t num_samples, loop_start = 0, loop_end = 0;
/* checks */
if (!check_extensions(streamFile, "ass"))
goto fail;
start_offset = 0x800;
channel_count = read_32bitLE(0x00,streamFile); /* assumed */
if (channel_count != 2) goto fail;
sample_rate = read_32bitLE(0x04,streamFile);
channel_size = read_32bitLE(0x08,streamFile);
interleave = read_32bitLE(0x0c,streamFile);
num_samples = ps_bytes_to_samples(channel_size,1);
loop_flag = ps_find_loop_offsets(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start, &loop_end);
loop_flag = loop_flag && (num_samples > 10*sample_rate); /* disable looping for smaller files (in seconds) */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_PS2_ASS;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -12,7 +12,7 @@ VGMSTREAM* init_vgmstream_psnd(STREAMFILE* sf) {
/* checks */
if (!is_id32be(0x00,sf, "PSND"))
return NULL;
/* .psn: actual extension in exes */
/* .psn: actual extension in exes/bigfiles */
if (!check_extensions(sf, "psn"))
return NULL;
@ -22,21 +22,23 @@ VGMSTREAM* init_vgmstream_psnd(STREAMFILE* sf) {
switch (type) {
case 0x0030006: /* CBNK */
channels = read_u8(0xE,sf);
if (read_u8(0x0f, sf) != 16) goto fail; /* bps */
channels = read_u8(0x0E,sf);
if (read_u8(0x0f, sf) != 16) // bps
goto fail;
start_offset = 0x10;
break;
case 0x0000004: /* RR */
channels = 1;
start_offset = 0x0e;
break;
default:
goto fail;
}
data_size = data_size + 0x08 - start_offset;
loop_flag = 0; /* generally 22050hz music loops */
loop_flag = 0; // generally 22050hz music fully loops
/* build the VGMSTREAM */
@ -51,11 +53,16 @@ VGMSTREAM* init_vgmstream_psnd(STREAMFILE* sf) {
vgmstream->interleave_block_size = 0x02;
vgmstream->num_samples = pcm16_bytes_to_samples(data_size, channels);
break;
case 0x0000004:
vgmstream->coding_type = coding_DVI_IMA;
vgmstream->coding_type = coding_DVI_IMA_mono;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = ima_bytes_to_samples(data_size, channels);
// Reckless Getaway 2 (Android), Xenowerk (Android)
vgmstream->allow_dual_stereo = true;
break;
default:
goto fail;
}

View file

@ -484,8 +484,9 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
* .se: Rockman X4 (PC)
* .v: Rozen Maiden: Duellwalzer (PS2)
* .xst: Animaniacs: The Great Edgar Hunt (Xbox)
* .wxv: Dariusburst (PSP)
*/
if (!check_extensions(sf, "wav,lwav,xwav,mwv,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv,wvx,str,at3,rws,aud,at9,ckd,saf,ima,nsa,pcm,xvag,ogg,logg,p1d,xms,mus,dat,ldat,wma,lwma,caf,wax,voi,se,v,xst")) {
if (!check_extensions(sf, "wav,lwav,xwav,mwv,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv,wvx,str,at3,rws,aud,at9,ckd,saf,ima,nsa,pcm,xvag,ogg,logg,p1d,xms,mus,dat,ldat,wma,lwma,caf,wax,voi,se,v,xst,wxv")) {
return NULL;
}

View file

@ -1,74 +1,73 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
static int get_sk_num_samples(STREAMFILE *streamFile, off_t start_offset);
/* AUD/SK - Silicon Knights obfuscated Ogg (cutscene/voices) [Eternal Darkness (GC)] */
VGMSTREAM * init_vgmstream_sk_aud(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag = 0, channel_count, sample_rate;
/* check extension, case insensitive */
if (!check_extensions(streamFile,"aud"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x11534B10) /* \11"SK"\10 */
goto fail;
/* the format is just mutant Ogg so actually peeking into the Vorbis id packet here */
channel_count = read_8bit (0x23,streamFile);
sample_rate = read_32bitLE(0x24,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = get_sk_num_samples(streamFile, 0);
vgmstream->meta_type = meta_SK_AUD;
#ifdef VGM_USE_VORBIS
{
vorbis_custom_config cfg = {0};
vgmstream->layout_type = layout_none;
vgmstream->coding_type = coding_VORBIS_custom;
vgmstream->codec_data = init_vorbis_custom(streamFile, 0x00, VORBIS_SK, &cfg);
if (!vgmstream->codec_data) goto fail;
start_offset = cfg.data_start_offset;
}
#else
goto fail;
#endif
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* SK/Ogg doesn't have num_samples info, manually read total samples */
static int get_sk_num_samples(STREAMFILE *streamFile, off_t start_offset) {
uint32_t expected_id = 0x11534B10; /* \11"SK"\10 (would read "OggS" by changing the ID) */
off_t off = get_streamfile_size(streamFile) - 4-1-1-8-4-4-4;
/* simplest way is to find last OggS/SK page from stream end */
while (off >= start_offset) {
uint32_t current_id = read_32bitBE(off, streamFile);
if (current_id == expected_id) { /* last packet starts with 0x0004, if more checks are needed */
return read_32bitLE(off+4+1+1, streamFile); /* get last granule = total samples (64b but whatevs) */
}
off--;
}
return 0;
}
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
static int32_t get_sk_num_samples(STREAMFILE* sf, off_t start_offset);
/* SK (.AUD) - Silicon Knights obfuscated Ogg (cutscene/voices) [Eternal Darkness (GC)] */
VGMSTREAM* init_vgmstream_sk_aud(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag = 0, channels, sample_rate;
/* checks */
if (read_u32be(0x00,sf) != 0x11534B10) /* \11"SK"\10 */
return NULL;
if (!check_extensions(sf,"aud"))
return NULL;
/* the format is just mutant Ogg so actually peeking into the Vorbis id packet here */
channels = read_u8 (0x23,sf);
sample_rate = read_s32le(0x24,sf);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = get_sk_num_samples(sf, 0);
vgmstream->meta_type = meta_SK_AUD;
#ifdef VGM_USE_VORBIS
{
vorbis_custom_config cfg = {0};
vgmstream->layout_type = layout_none;
vgmstream->coding_type = coding_VORBIS_custom;
vgmstream->codec_data = init_vorbis_custom(sf, 0x00, VORBIS_SK, &cfg);
if (!vgmstream->codec_data) goto fail;
start_offset = cfg.data_start_offset;
}
#else
goto fail;
#endif
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
// TODO: improve reads in blocks
/* SK/Ogg doesn't have num_samples info, manually read total samples */
static int32_t get_sk_num_samples(STREAMFILE* sf, off_t start_offset) {
uint32_t expected_id = 0x11534B10; /* \11"SK"\10 (would read "OggS" by changing the ID) */
off_t off = get_streamfile_size(sf) - 4-1-1-8-4-4-4;
/* simplest way is to find last OggS/SK page from stream end */
while (off >= start_offset) {
uint32_t current_id = read_u32be(off, sf);
if (current_id == expected_id) { /* last packet starts with 0x0004, if more checks are needed */
return read_s32le(off+4+1+1, sf); /* get last granule = total samples (64b but whatevs) */
}
off--;
}
return 0;
}

View file

@ -1,110 +1,112 @@
#include "meta.h"
#include "../coding/coding.h"
/* SPD+SPT - Nintendo bank (bgm or sfx) format [Bloodrayne (GC), 4x4 EVO 2 (GC), Table Tennis (Wii)] */
VGMSTREAM * init_vgmstream_spt_spd(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *sf_h = NULL;
int channel_count, loop_flag, sample_rate;
off_t header_offset, extra_offset, start_offset;
int32_t loop_start, loop_end, stream_start, stream_end;
size_t stream_size;
uint32_t flags;
int total_subsongs, target_subsong = streamFile->stream_index;
/* checks */
if (!check_extensions(streamFile, "spd"))
goto fail;
sf_h = open_streamfile_by_ext(streamFile, "spt");
if (!sf_h) goto fail;
/* ignore alt .spt+spd [Spyro: Enter the Dragonfly (GC)] */
if (read_u16be(0x00, sf_h) != 0) /* always 0xA20C? */
goto fail;
total_subsongs = read_s32be(0x00, sf_h);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
header_offset = 0x04 + 0x1c * (target_subsong-1);
extra_offset = 0x04 + 0x1c * total_subsongs + 0x2e * (target_subsong-1);
flags = read_u32be(header_offset + 0x00, sf_h);
sample_rate = read_s32be(header_offset + 0x04, sf_h);
loop_start = read_s32be(header_offset + 0x08, sf_h);
loop_end = read_s32be(header_offset + 0x0c, sf_h);
stream_end = read_s32be(header_offset + 0x10, sf_h);
stream_start = read_s32be(header_offset + 0x14, sf_h);
/* 0x18: null */
channel_count = 1;
loop_flag = (flags & 1);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_SPT_SPD;
vgmstream->allow_dual_stereo = 1;
vgmstream->sample_rate = sample_rate;
vgmstream->layout_type = layout_none;
vgmstream->num_streams = total_subsongs;
switch(flags & (~1)) { /* bitflags */
case 0: /* common */
/* values in file nibbles? */
start_offset = (stream_start / 2 - 1);
stream_size = (stream_end / 2 + 1) - (stream_start / 2 - 1);
if (loop_flag) {
loop_start = (loop_start / 2 - 1) - start_offset;
loop_end = (loop_end / 2 + 1) - start_offset;
}
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->num_samples = dsp_bytes_to_samples(stream_size, channel_count);
if (loop_flag) {
vgmstream->loop_start_sample = dsp_bytes_to_samples(loop_start, channel_count);
vgmstream->loop_end_sample = dsp_bytes_to_samples(loop_end, channel_count);
}
dsp_read_coefs_be(vgmstream, sf_h, extra_offset + 0x00, 0x00);
dsp_read_hist_be (vgmstream, sf_h, extra_offset + 0x24, 0x00);
break;
case 2: /* rare [Monster Jam: Maximum Destruction (GC)] */
/* values in samples? */
start_offset = (stream_start * 2);
stream_size = (stream_end * 2) - (stream_start * 2);
if (loop_flag) {
loop_start = (loop_start * 2) - start_offset;
loop_end = (loop_end * 2) - start_offset;
}
vgmstream->coding_type = coding_PCM16BE;
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16);
if (loop_flag) {
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
}
break;
case 4: /* supposedly PCM8 */
default:
goto fail;
}
vgmstream->stream_size = stream_size;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
close_streamfile(sf_h);
return vgmstream;
fail:
close_streamfile(sf_h);
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* .SPT+SPD - Nintendo bank (bgm or sfx) [Bloodrayne (GC), 4x4 EVO 2 (GC), Table Tennis (Wii)] */
VGMSTREAM* init_vgmstream_spt_spd(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sb = NULL;
int channels, loop_flag, sample_rate;
off_t header_offset, extra_offset, start_offset;
int32_t loop_start, loop_end, stream_start, stream_end;
size_t stream_size;
uint32_t flags;
int total_subsongs, target_subsong = sf->stream_index;
/* checks */
total_subsongs = read_s32be(0x00, sf);
// ignores alt .spt+spd that start with 0xA20C [Spyro: Enter the Dragonfly (GC)]
if (total_subsongs < 0 || total_subsongs > 0xFFFF)
return NULL;
if (!check_extensions(sf, "spt"))
return NULL;
sb = open_streamfile_by_ext(sf, "spd");
if (!sb) return NULL;
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
header_offset = 0x04 + 0x1c * (target_subsong-1);
extra_offset = 0x04 + 0x1c * total_subsongs + 0x2e * (target_subsong - 1);
flags = read_u32be(header_offset + 0x00, sf);
sample_rate = read_s32be(header_offset + 0x04, sf);
loop_start = read_s32be(header_offset + 0x08, sf);
loop_end = read_s32be(header_offset + 0x0c, sf);
stream_end = read_s32be(header_offset + 0x10, sf);
stream_start = read_s32be(header_offset + 0x14, sf);
// 0x18: null
channels = 1;
loop_flag = (flags & 1);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_SPT_SPD;
vgmstream->allow_dual_stereo = 1;
vgmstream->sample_rate = sample_rate;
vgmstream->layout_type = layout_none;
vgmstream->num_streams = total_subsongs;
switch(flags & (~1)) { /* bitflags */
case 0: /* common */
/* values in file nibbles? */
start_offset = (stream_start / 2 - 1);
stream_size = (stream_end / 2 + 1) - (stream_start / 2 - 1);
if (loop_flag) {
loop_start = (loop_start / 2 - 1) - start_offset;
loop_end = (loop_end / 2 + 1) - start_offset;
}
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->num_samples = dsp_bytes_to_samples(stream_size, channels);
if (loop_flag) {
vgmstream->loop_start_sample = dsp_bytes_to_samples(loop_start, channels);
vgmstream->loop_end_sample = dsp_bytes_to_samples(loop_end, channels);
}
dsp_read_coefs_be(vgmstream, sf, extra_offset + 0x00, 0x00);
dsp_read_hist_be (vgmstream, sf, extra_offset + 0x24, 0x00);
break;
case 2: /* rare [Monster Jam: Maximum Destruction (GC)] */
/* values in samples? */
start_offset = (stream_start * 2);
stream_size = (stream_end * 2) - (stream_start * 2);
if (loop_flag) {
loop_start = (loop_start * 2) - start_offset;
loop_end = (loop_end * 2) - start_offset;
}
vgmstream->coding_type = coding_PCM16BE;
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channels, 16);
if (loop_flag) {
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
}
break;
case 4: /* supposedly PCM8 */
default:
goto fail;
}
vgmstream->stream_size = stream_size;
if (!vgmstream_open_stream(vgmstream, sb, start_offset))
goto fail;
close_streamfile(sb);
return vgmstream;
fail:
close_streamfile(sb);
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -0,0 +1,68 @@
#include "meta.h"
#include "../coding/coding.h"
/* .SRE+PCM. - Capcom's header+data container thing [Viewtiful Joe (PS2)] */
VGMSTREAM* init_vgmstream_sre_pcm(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sb = NULL;
off_t start_offset;
int loop_flag, channels;
int table1_entries, table2_entries;
uint32_t table1_offset, table2_offset;
int total_subsongs, target_subsong = sf->stream_index;
/* checks */
table1_entries = read_s32le(0x00, sf);
if (table1_entries <= 0 || table1_entries >= 0x100) //arbitrary max
return NULL;
table1_offset = read_u32le(0x04, sf);
table2_entries = read_s32le(0x08, sf);
table2_offset = read_u32le(0x0c, sf);
if (table1_entries * 0x60 + table1_offset != table2_offset)
return NULL;
if (!check_extensions(sf, "sre"))
return NULL;
total_subsongs = table2_entries;
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1)
return NULL;
uint32_t header_offset = table2_offset + (target_subsong - 1) * 0x20;
channels = read_s32le(header_offset+0x00,sf);
loop_flag = read_s32le(header_offset+0x18,sf);
start_offset = read_u32le(header_offset+0x08,sf);
sb = open_streamfile_by_ext(sf, "pcm");
if (!sb) goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_u16le(header_offset+0x04,sf);
vgmstream->meta_type = meta_SRE_PCM;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x1000;
vgmstream->num_samples = ps_bytes_to_samples(read_u32le(header_offset+0x0c,sf), channels);
vgmstream->loop_start_sample = ps_bytes_to_samples(read_u32le(header_offset+0x10,sf), 1);
vgmstream->loop_end_sample = ps_bytes_to_samples(read_u32le(header_offset+0x14,sf), 1);
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = read_u32le(header_offset+0x0c,sf);
if (!vgmstream_open_stream(vgmstream,sb,start_offset))
goto fail;
close_streamfile(sb);
return vgmstream;
fail:
close_streamfile(sb);
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -159,6 +159,7 @@ VGMSTREAM* init_vgmstream_vab(STREAMFILE* sf) {
}
pitch = SsPitchFromNote(note, fine, center, shift);
if (pitch > 0x4000) pitch = 0x4000; /* SPU clamp */
data_offset = is_vh ? 0x00 : (waves_off + 256 * 0x02);
for (i = 0; i < wave_num; i++) {

View file

@ -11,10 +11,10 @@ VGMSTREAM* init_vgmstream_vgs_ps(STREAMFILE* sf) {
/* check */
if (!check_extensions(sf,"vgs"))
goto fail;
if (!is_id32be(0x00,sf, "VGS\0")) /* 'VAG stereo', presumably (simple VAG clone) */
goto fail;
return NULL;
if (!check_extensions(sf,"vgs"))
return NULL;
start_offset = 0x30;
data_size = get_streamfile_size(sf) - start_offset;

View file

@ -1,83 +1,83 @@
#include "meta.h"
#include "../coding/coding.h"
/* .wsi - blocked dsp [Alone in the Dark (Wii)] */
VGMSTREAM * init_vgmstream_wsi(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, header_offset;
size_t header_spacing;
int loop_flag, channel_count;
/* checks */
if (!check_extensions(streamFile, "wsi"))
goto fail;
channel_count = read_32bitBE(0x04,streamFile);
if (channel_count != 2) goto fail; /* assumed */
/* check for consistent block headers */
{
off_t block_offset;
off_t block_size_has_been;
int i;
block_offset = read_32bitBE(0x00,streamFile);
if (block_offset < 0x08) goto fail;
block_size_has_been = block_offset;
/* check 4 blocks, to get an idea */
for (i = 0; i < 4*channel_count; i++) {
off_t block_size = read_32bitBE(block_offset,streamFile);
if (block_size < 0x10)
goto fail; /* expect at least the block header */
if (i%channel_count+1 != read_32bitBE(block_offset+0x08,streamFile))
goto fail; /* expect the channel numbers to alternate */
if (i%channel_count==0)
block_size_has_been = block_size;
else if (block_size != block_size_has_been)
goto fail; /* expect every block in a set of channels to have the same size */
block_offset += block_size;
}
}
start_offset = read_32bitBE(0x00, streamFile);
header_offset = start_offset + 0x10;
header_spacing = read_32bitBE(start_offset,streamFile);
/* contains standard DSP header, but since it's blocked validations (start/loop ps, etc)
* will fail, so no point to handle as standard DSP */
loop_flag = read_16bitBE(header_offset+0x0c,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_DSP_WSI;
vgmstream->sample_rate = read_32bitBE(header_offset+0x08,streamFile);
vgmstream->num_samples = read_32bitBE(header_offset+0x00,streamFile) / 14 * 14; /* remove incomplete last frame */
vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bitBE(header_offset+0x10,streamFile));
vgmstream->loop_end_sample = dsp_nibbles_to_samples(read_32bitBE(header_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_blocked_wsi;
dsp_read_coefs_be(vgmstream, streamFile, header_offset+0x1c, header_spacing);
dsp_read_hist_be(vgmstream, streamFile, header_offset+0x40, header_spacing);
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"
/* .wsi - blocked dsp [Alone in the Dark (Wii)] */
VGMSTREAM * init_vgmstream_wsi(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, header_offset;
size_t header_spacing;
int loop_flag, channel_count;
/* checks */
if (!check_extensions(streamFile, "wsi"))
goto fail;
channel_count = read_32bitBE(0x04,streamFile);
if (channel_count != 2) goto fail; /* assumed */
/* check for consistent block headers */
{
off_t block_offset;
off_t block_size_has_been;
int i;
block_offset = read_32bitBE(0x00,streamFile);
if (block_offset < 0x08) goto fail;
block_size_has_been = block_offset;
/* check 4 blocks, to get an idea */
for (i = 0; i < 4*channel_count; i++) {
off_t block_size = read_32bitBE(block_offset,streamFile);
if (block_size < 0x10)
goto fail; /* expect at least the block header */
if (i%channel_count+1 != read_32bitBE(block_offset+0x08,streamFile))
goto fail; /* expect the channel numbers to alternate */
if (i%channel_count==0)
block_size_has_been = block_size;
else if (block_size != block_size_has_been)
goto fail; /* expect every block in a set of channels to have the same size */
block_offset += block_size;
}
}
start_offset = read_32bitBE(0x00, streamFile);
header_offset = start_offset + 0x10;
header_spacing = read_32bitBE(start_offset,streamFile);
/* contains standard DSP header, but since it's blocked validations (start/loop ps, etc)
* will fail, so no point to handle as standard DSP */
loop_flag = read_16bitBE(header_offset+0x0c,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_DSP_WSI;
vgmstream->sample_rate = read_32bitBE(header_offset+0x08,streamFile);
vgmstream->num_samples = read_32bitBE(header_offset+0x00,streamFile) / 14 * 14; /* remove incomplete last frame */
vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bitBE(header_offset+0x10,streamFile));
vgmstream->loop_end_sample = dsp_nibbles_to_samples(read_32bitBE(header_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_blocked_wsi;
dsp_read_coefs_be(vgmstream, streamFile, header_offset+0x1c, header_spacing);
dsp_read_hist_be(vgmstream, streamFile, header_offset+0x40, header_spacing);
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View file

@ -45,7 +45,6 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_sfl_ogg,
init_vgmstream_sadb,
init_vgmstream_ps2_bmdx,
init_vgmstream_wsi,
init_vgmstream_aifc,
init_vgmstream_str_snds,
init_vgmstream_ws_aud,
@ -57,6 +56,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_nwa,
init_vgmstream_ea_1snh,
init_vgmstream_ea_eacs,
init_vgmstream_ea_crdf,
init_vgmstream_xss,
init_vgmstream_sl3,
init_vgmstream_hgc1,
@ -102,21 +102,17 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_sadl,
init_vgmstream_fag,
init_vgmstream_mic,
init_vgmstream_ngc_pdt_split,
init_vgmstream_ngc_pdt,
init_vgmstream_mus_krome,
init_vgmstream_spsd,
init_vgmstream_rsd,
init_vgmstream_bgw,
init_vgmstream_spw,
init_vgmstream_ps2_ass,
init_vgmstream_ubi_jade,
init_vgmstream_ubi_jade_container,
init_vgmstream_seg,
init_vgmstream_riff_ima,
init_vgmstream_knon,
init_vgmstream_gca,
init_vgmstream_spt_spd,
init_vgmstream_ish_isd,
init_vgmstream_gsnd,
init_vgmstream_ydsp,
@ -154,7 +150,6 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_dsp_kceje,
init_vgmstream_gcub,
init_vgmstream_maxis_xa,
init_vgmstream_ngc_sck_dsp,
init_vgmstream_apple_caff,
init_vgmstream_pc_mxst,
init_vgmstream_sab,
@ -255,6 +250,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_xa_xa30,
init_vgmstream_xa_04sw,
init_vgmstream_ea_bnk,
init_vgmstream_ea_bnk_fixed,
init_vgmstream_ea_abk_schl,
init_vgmstream_ea_amb_schl,
init_vgmstream_ea_hdr_dat,
@ -263,6 +259,8 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_ea_mpf_mus_schl,
init_vgmstream_ea_msb_mus_schl,
init_vgmstream_ea_schl_fixed,
init_vgmstream_ea_patl,
init_vgmstream_ea_pt,
init_vgmstream_sk_aud,
init_vgmstream_stma,
init_vgmstream_ea_snu,
@ -295,7 +293,6 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_ea_sbr,
init_vgmstream_ea_sbr_harmony,
init_vgmstream_vid1,
init_vgmstream_flx,
init_vgmstream_mogg,
init_vgmstream_kma9,
init_vgmstream_xwc,
@ -311,7 +308,6 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_ea_wve_au00,
init_vgmstream_ea_wve_ad10,
init_vgmstream_sthd,
init_vgmstream_pcm_sre,
init_vgmstream_dsp_mcadpcm,
init_vgmstream_ubi_lyn,
init_vgmstream_ubi_lyn_container,
@ -541,6 +537,11 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_imc_container,
init_vgmstream_wv6,
init_vgmstream_smh_smc,
init_vgmstream_flx,
init_vgmstream_pdt,
init_vgmstream_spt_spd,
init_vgmstream_wsi,
init_vgmstream_sre_pcm,
/* need companion files */
init_vgmstream_pos,
init_vgmstream_sli_loops,
@ -562,6 +563,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_exakt_sc, /* .sc raw PCM */
init_vgmstream_ps2_adm, /* weird non-constant PSX blocks */
init_vgmstream_rwsd, /* crap, to be removed */
init_vgmstream_pdt_split, /* fake format */
#ifdef VGM_USE_FFMPEG
init_vgmstream_ffmpeg, /* may play anything incorrectly, since FFmpeg doesn't check extensions */
#endif

View file

@ -376,11 +376,10 @@ typedef enum {
meta_SADL,
meta_FAG, /* Jackie Chan - Stuntmaster */
meta_MIC,
meta_NGC_PDT, /* Mario Party 6 */
meta_PDT,
meta_ASD_NAXAT,
meta_SPSD,
meta_RSD,
meta_PS2_ASS,
meta_SEG,
meta_RIFF_IMA,
meta_KNON,
@ -400,7 +399,8 @@ typedef enum {
meta_XMU,
meta_EA_SCHL, /* Electronic Arts SCHl with variable header */
meta_EA_SCHL_fixed, /* Electronic Arts SCHl with fixed header */
meta_EA_BNK, /* Electronic Arts BNK */
meta_EA_BNK, /* Electronic Arts BNK with variable header */
meta_EA_BNK_fixed, /* Electronic Arts BNK with fixed header */
meta_EA_1SNH, /* Electronic Arts 1SNh/EACS */
meta_EA_EACS,
meta_RAW_PCM,
@ -446,9 +446,8 @@ typedef enum {
meta_2DX9,
meta_VGV,
meta_GCUB,
meta_MAXIS_XA, /* Sim City 3000 (PC) */
meta_NGC_SCK_DSP, /* Scorpion King (NGC) */
meta_CAFF, /* iPhone .caf */
meta_MAXIS_XA,
meta_CAFF,
meta_EXAKT_SC, /* Activision EXAKT .SC (PS2) */
meta_WII_WAS, /* DiRT 2 (WII) */
meta_PONA_3DO, /* Policenauts (3DO) */
@ -576,7 +575,7 @@ typedef enum {
meta_EA_WVE_AD10, /* Electronic Arts PS movies [Wing Commander 3/4 (PS)] */
meta_STHD, /* STHD .stx [Kakuto Chojin (Xbox)] */
meta_MP4, /* MP4/AAC */
meta_PCM_SRE, /* .PCM+SRE [Viewtiful Joe (PS2)] */
meta_SRE_PCM,
meta_DSP_MCADPCM, /* Skyrim (Switch) */
meta_UBI_LYN, /* Ubisoft LyN engine [The Adventures of Tintin (multi)] */
meta_MSB_MSH, /* sfx companion of MIH+MIB */

View file

@ -401,7 +401,6 @@
<string>asd</string>
<string>asf</string>
<string>asr</string>
<string>ass</string>
<string>ast</string>
<string>at3</string>
<string>at9</string>
@ -419,6 +418,7 @@
<string>awb</string>
<string>awc</string>
<string>awd</string>
<string>awx</string>
<string>b1s</string>
<string>baf</string>
<string>baka</string>
@ -438,6 +438,7 @@
<string>bik2</string>
<string>binka</string>
<string>bk2</string>
<string>bkh</string>
<string>bkr</string>
<string>blk</string>
<string>bmdx</string>
@ -470,11 +471,14 @@
<string>cnk</string>
<string>cpk</string>
<string>cps</string>
<string>crd</string>
<string>csa</string>
<string>csb</string>
<string>csmp</string>
<string>cvs</string>
<string>cwav</string>
<string>cxb</string>
<string>cxk</string>
<string>cxs</string>
<string>d2</string>
<string>da</string>
@ -489,12 +493,14 @@
<string>dic</string>
<string>diva</string>
<string>dmsg</string>
<string>drm</string>
<string>ds2</string>
<string>dsb</string>
<string>dsf</string>
<string>dsp</string>
<string>dspw</string>
<string>dtk</string>
<string>dty</string>
<string>dvi</string>
<string>dyx</string>
<string>e4x</string>
@ -656,13 +662,14 @@
<string>mds</string>
<string>mdsp</string>
<string>med</string>
<string>mhwk</string>
<string>mhk</string>
<string>mjb</string>
<string>mi4</string>
<string>mib</string>
<string>mic</string>
<string>mio</string>
<string>mogg</string>
<string>mon</string>
<string>move</string>
<string>mpdsp</string>
<string>mpds</string>
@ -745,6 +752,7 @@
<string>psf</string>
<string>psh</string>
<string>psn</string>
<string>pth</string>
<string>pwb</string>
<string>qwv</string>
<string>r</string>
@ -846,19 +854,22 @@
<string>snz</string>
<string>sod</string>
<string>son</string>
<string>spd</string>
<string>spc</string>
<string>sph</string>
<string>spt</string>
<string>spm</string>
<string>sps</string>
<string>spsd</string>
<string>spw</string>
<string>srsa</string>
<string>srcd</string>
<string>sre</string>
<string>srsa</string>
<string>ss2</string>
<string>ssd</string>
<string>ssf</string>
<string>ssm</string>
<string>sspr</string>
<string>ssp</string>
<string>sspr</string>
<string>sss</string>
<string>ster</string>
<string>sth</string>
@ -973,6 +984,7 @@
<string>wvs</string>
<string>wvx</string>
<string>wxd</string>
<string>wxv</string>
<string>x</string>
<string>x360audio</string>
<string>xa</string>