Updated VGMStream to r1050-1001-gebdfed99.
parent
ce1d938b3a
commit
56ed9c3429
|
@ -43,7 +43,6 @@
|
||||||
83345A521F8AEB2800B2EAA4 /* xvag.c in Sources */ = {isa = PBXBuildFile; fileRef = 83345A4E1F8AEB2800B2EAA4 /* xvag.c */; };
|
83345A521F8AEB2800B2EAA4 /* xvag.c in Sources */ = {isa = PBXBuildFile; fileRef = 83345A4E1F8AEB2800B2EAA4 /* xvag.c */; };
|
||||||
833A7A2E1ED11961003EC53E /* xau.c in Sources */ = {isa = PBXBuildFile; fileRef = 833A7A2D1ED11961003EC53E /* xau.c */; };
|
833A7A2E1ED11961003EC53E /* xau.c in Sources */ = {isa = PBXBuildFile; fileRef = 833A7A2D1ED11961003EC53E /* xau.c */; };
|
||||||
8349A8DF1FE6251F00E26435 /* vorbis_custom_utils_vid1.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8DC1FE6251E00E26435 /* vorbis_custom_utils_vid1.c */; };
|
8349A8DF1FE6251F00E26435 /* vorbis_custom_utils_vid1.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8DC1FE6251E00E26435 /* vorbis_custom_utils_vid1.c */; };
|
||||||
8349A8E01FE6251F00E26435 /* ffmpeg_decoder_utils_bgw_atrac3.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8DD1FE6251F00E26435 /* ffmpeg_decoder_utils_bgw_atrac3.c */; };
|
|
||||||
8349A8E11FE6251F00E26435 /* ea_mt_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8DE1FE6251F00E26435 /* ea_mt_decoder.c */; };
|
8349A8E11FE6251F00E26435 /* ea_mt_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8DE1FE6251F00E26435 /* ea_mt_decoder.c */; };
|
||||||
8349A8E81FE6253900E26435 /* blocked_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8E21FE6253800E26435 /* blocked_dec.c */; };
|
8349A8E81FE6253900E26435 /* blocked_dec.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8E21FE6253800E26435 /* blocked_dec.c */; };
|
||||||
8349A8E91FE6253900E26435 /* blocked_ea_1snh.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8E31FE6253800E26435 /* blocked_ea_1snh.c */; };
|
8349A8E91FE6253900E26435 /* blocked_ea_1snh.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A8E31FE6253800E26435 /* blocked_ea_1snh.c */; };
|
||||||
|
@ -221,7 +220,6 @@
|
||||||
836F6FBA18BDC2190095E648 /* ngc_ymf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7E18BDC2180095E648 /* ngc_ymf.c */; };
|
836F6FBA18BDC2190095E648 /* ngc_ymf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7E18BDC2180095E648 /* ngc_ymf.c */; };
|
||||||
836F6FBB18BDC2190095E648 /* ngca.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7F18BDC2180095E648 /* ngca.c */; };
|
836F6FBB18BDC2190095E648 /* ngca.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7F18BDC2180095E648 /* ngca.c */; };
|
||||||
836F6FBD18BDC2190095E648 /* nwa.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8118BDC2180095E648 /* nwa.c */; };
|
836F6FBD18BDC2190095E648 /* nwa.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8118BDC2180095E648 /* nwa.c */; };
|
||||||
836F6FBE18BDC2190095E648 /* ogg_vorbis_file.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8218BDC2180095E648 /* ogg_vorbis_file.c */; };
|
|
||||||
836F6FBF18BDC2190095E648 /* otm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8318BDC2180095E648 /* otm.c */; };
|
836F6FBF18BDC2190095E648 /* otm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8318BDC2180095E648 /* otm.c */; };
|
||||||
836F6FC018BDC2190095E648 /* p3d.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8418BDC2180095E648 /* p3d.c */; };
|
836F6FC018BDC2190095E648 /* p3d.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8418BDC2180095E648 /* p3d.c */; };
|
||||||
836F6FC118BDC2190095E648 /* pc_adp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8518BDC2180095E648 /* pc_adp.c */; };
|
836F6FC118BDC2190095E648 /* pc_adp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8518BDC2180095E648 /* pc_adp.c */; };
|
||||||
|
@ -405,6 +403,16 @@
|
||||||
839E21E81F2EDAF100EE54D7 /* mpeg_decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 839E21DE1F2EDAF000EE54D7 /* mpeg_decoder.h */; };
|
839E21E81F2EDAF100EE54D7 /* mpeg_decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 839E21DE1F2EDAF000EE54D7 /* mpeg_decoder.h */; };
|
||||||
839E21E91F2EDAF100EE54D7 /* vorbis_custom_utils_sk.c in Sources */ = {isa = PBXBuildFile; fileRef = 839E21DF1F2EDAF000EE54D7 /* vorbis_custom_utils_sk.c */; };
|
839E21E91F2EDAF100EE54D7 /* vorbis_custom_utils_sk.c in Sources */ = {isa = PBXBuildFile; fileRef = 839E21DF1F2EDAF000EE54D7 /* vorbis_custom_utils_sk.c */; };
|
||||||
839E21EB1F2EDB0600EE54D7 /* sk_aud.c in Sources */ = {isa = PBXBuildFile; fileRef = 839E21EA1F2EDB0500EE54D7 /* sk_aud.c */; };
|
839E21EB1F2EDB0600EE54D7 /* sk_aud.c in Sources */ = {isa = PBXBuildFile; fileRef = 839E21EA1F2EDB0500EE54D7 /* sk_aud.c */; };
|
||||||
|
83A21F7B201D895B000F04B9 /* blocked_xvag.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F7A201D895B000F04B9 /* blocked_xvag.c */; };
|
||||||
|
83A21F85201D8981000F04B9 /* atx.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F7C201D897F000F04B9 /* atx.c */; };
|
||||||
|
83A21F86201D8981000F04B9 /* xwc.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F7D201D8980000F04B9 /* xwc.c */; };
|
||||||
|
83A21F87201D8981000F04B9 /* fsb_keys.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A21F7E201D8980000F04B9 /* fsb_keys.h */; };
|
||||||
|
83A21F88201D8981000F04B9 /* ogg_vorbis.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F7F201D8980000F04B9 /* ogg_vorbis.c */; };
|
||||||
|
83A21F89201D8982000F04B9 /* atsl3.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F80201D8980000F04B9 /* atsl3.c */; };
|
||||||
|
83A21F8A201D8982000F04B9 /* fsb_encrypted.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F81201D8981000F04B9 /* fsb_encrypted.c */; };
|
||||||
|
83A21F8B201D8982000F04B9 /* sps_n1.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F82201D8981000F04B9 /* sps_n1.c */; };
|
||||||
|
83A21F8C201D8982000F04B9 /* kma9.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F83201D8981000F04B9 /* kma9.c */; };
|
||||||
|
83A21F8D201D8982000F04B9 /* sqex_sead.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A21F84201D8981000F04B9 /* sqex_sead.c */; };
|
||||||
83A3F0741E3AD8B900D6A794 /* formats.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A3F0711E3AD8B900D6A794 /* formats.c */; };
|
83A3F0741E3AD8B900D6A794 /* formats.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A3F0711E3AD8B900D6A794 /* formats.c */; };
|
||||||
83A3F0761E3AD8B900D6A794 /* stack_alloc.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A3F0731E3AD8B900D6A794 /* stack_alloc.h */; };
|
83A3F0761E3AD8B900D6A794 /* stack_alloc.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A3F0731E3AD8B900D6A794 /* stack_alloc.h */; };
|
||||||
83A5F75F198DF021009AF94C /* bfwav.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A5F75E198DF021009AF94C /* bfwav.c */; };
|
83A5F75F198DF021009AF94C /* bfwav.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A5F75E198DF021009AF94C /* bfwav.c */; };
|
||||||
|
@ -595,7 +603,6 @@
|
||||||
83345A4E1F8AEB2800B2EAA4 /* xvag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xvag.c; sourceTree = "<group>"; };
|
83345A4E1F8AEB2800B2EAA4 /* xvag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xvag.c; sourceTree = "<group>"; };
|
||||||
833A7A2D1ED11961003EC53E /* xau.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xau.c; sourceTree = "<group>"; };
|
833A7A2D1ED11961003EC53E /* xau.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xau.c; sourceTree = "<group>"; };
|
||||||
8349A8DC1FE6251E00E26435 /* vorbis_custom_utils_vid1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_utils_vid1.c; sourceTree = "<group>"; };
|
8349A8DC1FE6251E00E26435 /* vorbis_custom_utils_vid1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_utils_vid1.c; sourceTree = "<group>"; };
|
||||||
8349A8DD1FE6251F00E26435 /* ffmpeg_decoder_utils_bgw_atrac3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffmpeg_decoder_utils_bgw_atrac3.c; sourceTree = "<group>"; };
|
|
||||||
8349A8DE1FE6251F00E26435 /* ea_mt_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_mt_decoder.c; sourceTree = "<group>"; };
|
8349A8DE1FE6251F00E26435 /* ea_mt_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_mt_decoder.c; sourceTree = "<group>"; };
|
||||||
8349A8E21FE6253800E26435 /* blocked_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_dec.c; sourceTree = "<group>"; };
|
8349A8E21FE6253800E26435 /* blocked_dec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_dec.c; sourceTree = "<group>"; };
|
||||||
8349A8E31FE6253800E26435 /* blocked_ea_1snh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ea_1snh.c; sourceTree = "<group>"; };
|
8349A8E31FE6253800E26435 /* blocked_ea_1snh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_ea_1snh.c; sourceTree = "<group>"; };
|
||||||
|
@ -775,7 +782,6 @@
|
||||||
836F6E7E18BDC2180095E648 /* ngc_ymf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_ymf.c; sourceTree = "<group>"; };
|
836F6E7E18BDC2180095E648 /* ngc_ymf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_ymf.c; sourceTree = "<group>"; };
|
||||||
836F6E7F18BDC2180095E648 /* ngca.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngca.c; sourceTree = "<group>"; };
|
836F6E7F18BDC2180095E648 /* ngca.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngca.c; sourceTree = "<group>"; };
|
||||||
836F6E8118BDC2180095E648 /* nwa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nwa.c; sourceTree = "<group>"; };
|
836F6E8118BDC2180095E648 /* nwa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nwa.c; sourceTree = "<group>"; };
|
||||||
836F6E8218BDC2180095E648 /* ogg_vorbis_file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ogg_vorbis_file.c; sourceTree = "<group>"; };
|
|
||||||
836F6E8318BDC2180095E648 /* otm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = otm.c; sourceTree = "<group>"; };
|
836F6E8318BDC2180095E648 /* otm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = otm.c; sourceTree = "<group>"; };
|
||||||
836F6E8418BDC2180095E648 /* p3d.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = p3d.c; sourceTree = "<group>"; };
|
836F6E8418BDC2180095E648 /* p3d.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = p3d.c; sourceTree = "<group>"; };
|
||||||
836F6E8518BDC2180095E648 /* pc_adp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pc_adp.c; sourceTree = "<group>"; };
|
836F6E8518BDC2180095E648 /* pc_adp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pc_adp.c; sourceTree = "<group>"; };
|
||||||
|
@ -957,6 +963,16 @@
|
||||||
839E21DE1F2EDAF000EE54D7 /* mpeg_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mpeg_decoder.h; sourceTree = "<group>"; };
|
839E21DE1F2EDAF000EE54D7 /* mpeg_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mpeg_decoder.h; sourceTree = "<group>"; };
|
||||||
839E21DF1F2EDAF000EE54D7 /* vorbis_custom_utils_sk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_utils_sk.c; sourceTree = "<group>"; };
|
839E21DF1F2EDAF000EE54D7 /* vorbis_custom_utils_sk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vorbis_custom_utils_sk.c; sourceTree = "<group>"; };
|
||||||
839E21EA1F2EDB0500EE54D7 /* sk_aud.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sk_aud.c; sourceTree = "<group>"; };
|
839E21EA1F2EDB0500EE54D7 /* sk_aud.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sk_aud.c; sourceTree = "<group>"; };
|
||||||
|
83A21F7A201D895B000F04B9 /* blocked_xvag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_xvag.c; sourceTree = "<group>"; };
|
||||||
|
83A21F7C201D897F000F04B9 /* atx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = atx.c; sourceTree = "<group>"; };
|
||||||
|
83A21F7D201D8980000F04B9 /* xwc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xwc.c; sourceTree = "<group>"; };
|
||||||
|
83A21F7E201D8980000F04B9 /* fsb_keys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fsb_keys.h; sourceTree = "<group>"; };
|
||||||
|
83A21F7F201D8980000F04B9 /* ogg_vorbis.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ogg_vorbis.c; sourceTree = "<group>"; };
|
||||||
|
83A21F80201D8980000F04B9 /* atsl3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = atsl3.c; sourceTree = "<group>"; };
|
||||||
|
83A21F81201D8981000F04B9 /* fsb_encrypted.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fsb_encrypted.c; sourceTree = "<group>"; };
|
||||||
|
83A21F82201D8981000F04B9 /* sps_n1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sps_n1.c; sourceTree = "<group>"; };
|
||||||
|
83A21F83201D8981000F04B9 /* kma9.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kma9.c; sourceTree = "<group>"; };
|
||||||
|
83A21F84201D8981000F04B9 /* sqex_sead.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sqex_sead.c; sourceTree = "<group>"; };
|
||||||
83A3F0711E3AD8B900D6A794 /* formats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = formats.c; sourceTree = "<group>"; };
|
83A3F0711E3AD8B900D6A794 /* formats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = formats.c; sourceTree = "<group>"; };
|
||||||
83A3F0731E3AD8B900D6A794 /* stack_alloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stack_alloc.h; sourceTree = "<group>"; };
|
83A3F0731E3AD8B900D6A794 /* stack_alloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stack_alloc.h; sourceTree = "<group>"; };
|
||||||
83A5F75E198DF021009AF94C /* bfwav.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bfwav.c; sourceTree = "<group>"; };
|
83A5F75E198DF021009AF94C /* bfwav.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bfwav.c; sourceTree = "<group>"; };
|
||||||
|
@ -1134,51 +1150,40 @@
|
||||||
836F6DDF18BDC2180095E648 /* coding */ = {
|
836F6DDF18BDC2180095E648 /* coding */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
830EBE0F2004655D0023AA10 /* atrac9_decoder.c */,
|
|
||||||
8349A8DE1FE6251F00E26435 /* ea_mt_decoder.c */,
|
|
||||||
8349A8DD1FE6251F00E26435 /* ffmpeg_decoder_utils_bgw_atrac3.c */,
|
|
||||||
8349A8DC1FE6251E00E26435 /* vorbis_custom_utils_vid1.c */,
|
|
||||||
83345A491F8AEAF900B2EAA4 /* ffmpeg_decoder_utils_switch_opus.c */,
|
|
||||||
8374EE361F787AB500033E90 /* ffmpeg_decoder_utils_ea_xma.c */,
|
|
||||||
8374EE3D1F787AB600033E90 /* ffmpeg_decoder_utils.c */,
|
|
||||||
8374EE3C1F787AB600033E90 /* ffmpeg_decoder_utils.h */,
|
|
||||||
83AA5D0E1F6E2F5F0020821C /* ea_xa_decoder.c */,
|
|
||||||
83AA5D151F6E2F600020821C /* ea_xas_decoder.c */,
|
|
||||||
83AA5D141F6E2F600020821C /* mpeg_custom_utils_awc.c */,
|
|
||||||
83AA5D131F6E2F5F0020821C /* mpeg_custom_utils_ealayer3.c */,
|
|
||||||
83E56BA01F2EE3500026BC60 /* vorbis_custom_utils_ogl.c */,
|
|
||||||
839E21D91F2EDAF000EE54D7 /* mpeg_custom_utils_ahx.c */,
|
|
||||||
839E21DD1F2EDAF000EE54D7 /* mpeg_custom_utils.c */,
|
|
||||||
839E21DE1F2EDAF000EE54D7 /* mpeg_decoder.h */,
|
|
||||||
839E21D61F2EDAF000EE54D7 /* vorbis_custom_data_fsb.h */,
|
|
||||||
839E21DC1F2EDAF000EE54D7 /* vorbis_custom_data_wwise.h */,
|
|
||||||
839E21D71F2EDAF000EE54D7 /* vorbis_custom_decoder.c */,
|
|
||||||
839E21DB1F2EDAF000EE54D7 /* vorbis_custom_decoder.h */,
|
|
||||||
839E21DA1F2EDAF000EE54D7 /* vorbis_custom_utils_fsb.c */,
|
|
||||||
839E21DF1F2EDAF000EE54D7 /* vorbis_custom_utils_sk.c */,
|
|
||||||
839E21D81F2EDAF000EE54D7 /* vorbis_custom_utils_wwise.c */,
|
|
||||||
835027121ED119E000C25929 /* mta2_decoder.c */,
|
|
||||||
83709E0B1ECBC1C3005C03D3 /* mc3_decoder.c */,
|
|
||||||
83709E0C1ECBC1C3005C03D3 /* psv_decoder.c */,
|
|
||||||
831BA6221EAC61CB00CF89B0 /* coding_utils.c */,
|
|
||||||
838BDB6B1D3AFAB10022CA6F /* ffmpeg_decoder.c */,
|
|
||||||
832389511D224C0800482226 /* hca_decoder.c */,
|
|
||||||
83D7318B1A749EEE00CA1366 /* g719_decoder.c */,
|
|
||||||
836F6DE018BDC2180095E648 /* acm_decoder.c */,
|
836F6DE018BDC2180095E648 /* acm_decoder.c */,
|
||||||
836F6DE118BDC2180095E648 /* acm_decoder.h */,
|
836F6DE118BDC2180095E648 /* acm_decoder.h */,
|
||||||
836F6DE218BDC2180095E648 /* adx_decoder.c */,
|
836F6DE218BDC2180095E648 /* adx_decoder.c */,
|
||||||
836F6DE318BDC2180095E648 /* aica_decoder.c */,
|
836F6DE318BDC2180095E648 /* aica_decoder.c */,
|
||||||
836F6DE418BDC2180095E648 /* at3_decoder.c */,
|
836F6DE418BDC2180095E648 /* at3_decoder.c */,
|
||||||
|
830EBE0F2004655D0023AA10 /* atrac9_decoder.c */,
|
||||||
|
831BA6221EAC61CB00CF89B0 /* coding_utils.c */,
|
||||||
836F6DE518BDC2180095E648 /* coding.h */,
|
836F6DE518BDC2180095E648 /* coding.h */,
|
||||||
|
8349A8DE1FE6251F00E26435 /* ea_mt_decoder.c */,
|
||||||
|
83AA5D0E1F6E2F5F0020821C /* ea_xa_decoder.c */,
|
||||||
|
83AA5D151F6E2F600020821C /* ea_xas_decoder.c */,
|
||||||
|
8374EE361F787AB500033E90 /* ffmpeg_decoder_utils_ea_xma.c */,
|
||||||
|
83345A491F8AEAF900B2EAA4 /* ffmpeg_decoder_utils_switch_opus.c */,
|
||||||
|
8374EE3D1F787AB600033E90 /* ffmpeg_decoder_utils.c */,
|
||||||
|
8374EE3C1F787AB600033E90 /* ffmpeg_decoder_utils.h */,
|
||||||
|
838BDB6B1D3AFAB10022CA6F /* ffmpeg_decoder.c */,
|
||||||
|
836F6DE918BDC2180095E648 /* g72x_state.h */,
|
||||||
|
83D7318B1A749EEE00CA1366 /* g719_decoder.c */,
|
||||||
836F6DE718BDC2180095E648 /* g721_decoder.c */,
|
836F6DE718BDC2180095E648 /* g721_decoder.c */,
|
||||||
836F6DE818BDC2180095E648 /* g7221_decoder.c */,
|
836F6DE818BDC2180095E648 /* g7221_decoder.c */,
|
||||||
836F6DE918BDC2180095E648 /* g72x_state.h */,
|
832389511D224C0800482226 /* hca_decoder.c */,
|
||||||
836F6DEA18BDC2180095E648 /* ima_decoder.c */,
|
836F6DEA18BDC2180095E648 /* ima_decoder.c */,
|
||||||
836F6DEB18BDC2180095E648 /* l5_555_decoder.c */,
|
836F6DEB18BDC2180095E648 /* l5_555_decoder.c */,
|
||||||
836F6DEC18BDC2180095E648 /* lsf_decoder.c */,
|
836F6DEC18BDC2180095E648 /* lsf_decoder.c */,
|
||||||
|
83709E0B1ECBC1C3005C03D3 /* mc3_decoder.c */,
|
||||||
836F6DEE18BDC2180095E648 /* mp4_aac_decoder.c */,
|
836F6DEE18BDC2180095E648 /* mp4_aac_decoder.c */,
|
||||||
|
839E21D91F2EDAF000EE54D7 /* mpeg_custom_utils_ahx.c */,
|
||||||
|
83AA5D141F6E2F600020821C /* mpeg_custom_utils_awc.c */,
|
||||||
|
83AA5D131F6E2F5F0020821C /* mpeg_custom_utils_ealayer3.c */,
|
||||||
|
839E21DD1F2EDAF000EE54D7 /* mpeg_custom_utils.c */,
|
||||||
836F6DEF18BDC2180095E648 /* mpeg_decoder.c */,
|
836F6DEF18BDC2180095E648 /* mpeg_decoder.c */,
|
||||||
|
839E21DE1F2EDAF000EE54D7 /* mpeg_decoder.h */,
|
||||||
836F6DF018BDC2180095E648 /* msadpcm_decoder.c */,
|
836F6DF018BDC2180095E648 /* msadpcm_decoder.c */,
|
||||||
|
835027121ED119E000C25929 /* mta2_decoder.c */,
|
||||||
836F6DF118BDC2180095E648 /* mtaf_decoder.c */,
|
836F6DF118BDC2180095E648 /* mtaf_decoder.c */,
|
||||||
836F6DF218BDC2180095E648 /* nds_procyon_decoder.c */,
|
836F6DF218BDC2180095E648 /* nds_procyon_decoder.c */,
|
||||||
836F6DF318BDC2180095E648 /* ngc_afc_decoder.c */,
|
836F6DF318BDC2180095E648 /* ngc_afc_decoder.c */,
|
||||||
|
@ -1188,9 +1193,19 @@
|
||||||
836F6DF718BDC2180095E648 /* nwa_decoder.h */,
|
836F6DF718BDC2180095E648 /* nwa_decoder.h */,
|
||||||
836F6DF818BDC2180095E648 /* ogg_vorbis_decoder.c */,
|
836F6DF818BDC2180095E648 /* ogg_vorbis_decoder.c */,
|
||||||
836F6DF918BDC2180095E648 /* pcm_decoder.c */,
|
836F6DF918BDC2180095E648 /* pcm_decoder.c */,
|
||||||
|
83709E0C1ECBC1C3005C03D3 /* psv_decoder.c */,
|
||||||
836F6DFA18BDC2180095E648 /* psx_decoder.c */,
|
836F6DFA18BDC2180095E648 /* psx_decoder.c */,
|
||||||
836F6DFB18BDC2180095E648 /* SASSC_decoder.c */,
|
836F6DFB18BDC2180095E648 /* SASSC_decoder.c */,
|
||||||
836F6DFC18BDC2180095E648 /* sdx2_decoder.c */,
|
836F6DFC18BDC2180095E648 /* sdx2_decoder.c */,
|
||||||
|
839E21D61F2EDAF000EE54D7 /* vorbis_custom_data_fsb.h */,
|
||||||
|
839E21DC1F2EDAF000EE54D7 /* vorbis_custom_data_wwise.h */,
|
||||||
|
839E21D71F2EDAF000EE54D7 /* vorbis_custom_decoder.c */,
|
||||||
|
839E21DB1F2EDAF000EE54D7 /* vorbis_custom_decoder.h */,
|
||||||
|
839E21DA1F2EDAF000EE54D7 /* vorbis_custom_utils_fsb.c */,
|
||||||
|
83E56BA01F2EE3500026BC60 /* vorbis_custom_utils_ogl.c */,
|
||||||
|
839E21DF1F2EDAF000EE54D7 /* vorbis_custom_utils_sk.c */,
|
||||||
|
8349A8DC1FE6251E00E26435 /* vorbis_custom_utils_vid1.c */,
|
||||||
|
839E21D81F2EDAF000EE54D7 /* vorbis_custom_utils_wwise.c */,
|
||||||
836F6DFD18BDC2180095E648 /* ws_decoder.c */,
|
836F6DFD18BDC2180095E648 /* ws_decoder.c */,
|
||||||
836F6DFE18BDC2180095E648 /* xa_decoder.c */,
|
836F6DFE18BDC2180095E648 /* xa_decoder.c */,
|
||||||
);
|
);
|
||||||
|
@ -1200,26 +1215,26 @@
|
||||||
836F6DFF18BDC2180095E648 /* layout */ = {
|
836F6DFF18BDC2180095E648 /* layout */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
836F6E0018BDC2180095E648 /* aax_layout.c */,
|
||||||
|
836F6E0118BDC2180095E648 /* aix_layout.c */,
|
||||||
|
836F6E0218BDC2180095E648 /* ast_blocked.c */,
|
||||||
|
836F6E0318BDC2180095E648 /* bdsp_blocked.c */,
|
||||||
|
83AA5D1B1F6E2F7F0020821C /* blocked_awc.c */,
|
||||||
8349A8E21FE6253800E26435 /* blocked_dec.c */,
|
8349A8E21FE6253800E26435 /* blocked_dec.c */,
|
||||||
8349A8E31FE6253800E26435 /* blocked_ea_1snh.c */,
|
8349A8E31FE6253800E26435 /* blocked_ea_1snh.c */,
|
||||||
8349A8E41FE6253800E26435 /* blocked_ea_schl.c */,
|
8349A8E41FE6253800E26435 /* blocked_ea_schl.c */,
|
||||||
8349A8E71FE6253900E26435 /* blocked_ea_sns.c */,
|
8349A8E71FE6253900E26435 /* blocked_ea_sns.c */,
|
||||||
8349A8E51FE6253800E26435 /* blocked_ivaud.c */,
|
8349A8E51FE6253800E26435 /* blocked_ivaud.c */,
|
||||||
8349A8E61FE6253900E26435 /* blocked_vawx.c */,
|
8349A8E61FE6253900E26435 /* blocked_vawx.c */,
|
||||||
83AA5D1B1F6E2F7F0020821C /* blocked_awc.c */,
|
|
||||||
83AA5D1A1F6E2F7F0020821C /* blocked_vgs.c */,
|
83AA5D1A1F6E2F7F0020821C /* blocked_vgs.c */,
|
||||||
830165A11F256BF400CA0941 /* hwas_blocked.c */,
|
83A21F7A201D895B000F04B9 /* blocked_xvag.c */,
|
||||||
831BD1201EEE1D2A00198540 /* rws_blocked.c */,
|
|
||||||
836F6E0018BDC2180095E648 /* aax_layout.c */,
|
|
||||||
836F6E0118BDC2180095E648 /* aix_layout.c */,
|
|
||||||
836F6E0218BDC2180095E648 /* ast_blocked.c */,
|
|
||||||
836F6E0318BDC2180095E648 /* bdsp_blocked.c */,
|
|
||||||
836F6E0418BDC2180095E648 /* blocked.c */,
|
836F6E0418BDC2180095E648 /* blocked.c */,
|
||||||
836F6E0518BDC2180095E648 /* caf_blocked.c */,
|
836F6E0518BDC2180095E648 /* caf_blocked.c */,
|
||||||
836F6E0818BDC2180095E648 /* emff_blocked.c */,
|
836F6E0818BDC2180095E648 /* emff_blocked.c */,
|
||||||
836F6E0918BDC2180095E648 /* filp_blocked.c */,
|
836F6E0918BDC2180095E648 /* filp_blocked.c */,
|
||||||
836F6E0A18BDC2180095E648 /* gsb_blocked.c */,
|
836F6E0A18BDC2180095E648 /* gsb_blocked.c */,
|
||||||
836F6E0B18BDC2180095E648 /* halpst_blocked.c */,
|
836F6E0B18BDC2180095E648 /* halpst_blocked.c */,
|
||||||
|
830165A11F256BF400CA0941 /* hwas_blocked.c */,
|
||||||
836F6E0C18BDC2180095E648 /* ims_block.c */,
|
836F6E0C18BDC2180095E648 /* ims_block.c */,
|
||||||
836F6E0D18BDC2180095E648 /* interleave.c */,
|
836F6E0D18BDC2180095E648 /* interleave.c */,
|
||||||
836F6E1018BDC2180095E648 /* layout.h */,
|
836F6E1018BDC2180095E648 /* layout.h */,
|
||||||
|
@ -1230,6 +1245,7 @@
|
||||||
836F6E1618BDC2180095E648 /* ps2_iab_blocked.c */,
|
836F6E1618BDC2180095E648 /* ps2_iab_blocked.c */,
|
||||||
836F6E1718BDC2180095E648 /* ps2_strlr_blocked.c */,
|
836F6E1718BDC2180095E648 /* ps2_strlr_blocked.c */,
|
||||||
836F6E1818BDC2180095E648 /* psx_mgav_blocked.c */,
|
836F6E1818BDC2180095E648 /* psx_mgav_blocked.c */,
|
||||||
|
831BD1201EEE1D2A00198540 /* rws_blocked.c */,
|
||||||
836F6E1918BDC2180095E648 /* scd_int_layout.c */,
|
836F6E1918BDC2180095E648 /* scd_int_layout.c */,
|
||||||
836F6E1A18BDC2180095E648 /* str_snds_blocked.c */,
|
836F6E1A18BDC2180095E648 /* str_snds_blocked.c */,
|
||||||
836F6E1B18BDC2180095E648 /* thp_blocked.c */,
|
836F6E1B18BDC2180095E648 /* thp_blocked.c */,
|
||||||
|
@ -1246,95 +1262,36 @@
|
||||||
836F6E2718BDC2180095E648 /* meta */ = {
|
836F6E2718BDC2180095E648 /* meta */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
830EBE122004656E0023AA10 /* ktss.c */,
|
|
||||||
830EBE112004656E0023AA10 /* xnb.c */,
|
|
||||||
8349A9041FE6258100E26435 /* aax_streamfile.h */,
|
|
||||||
8349A9021FE6258100E26435 /* adx_keys.h */,
|
|
||||||
8349A9001FE6258000E26435 /* afc.c */,
|
|
||||||
8349A8F61FE6257E00E26435 /* aix_streamfile.h */,
|
|
||||||
8349A8F81FE6257E00E26435 /* bar_streamfile.h */,
|
|
||||||
8349A9051FE6258100E26435 /* bar.c */,
|
|
||||||
8349A8EE1FE6257C00E26435 /* dec.c */,
|
|
||||||
8349A8FF1FE6258000E26435 /* ea_1snh.c */,
|
|
||||||
8349A8F71FE6257E00E26435 /* ea_eaac.c */,
|
|
||||||
8349A8EF1FE6257C00E26435 /* ezw.c */,
|
|
||||||
8349A8FD1FE6257F00E26435 /* flx.c */,
|
|
||||||
8349A9031FE6258100E26435 /* mogg.c */,
|
|
||||||
8349A9061FE6258100E26435 /* naac.c */,
|
|
||||||
8349A8FA1FE6257E00E26435 /* ngc_vid1.c */,
|
|
||||||
8349A8FB1FE6257F00E26435 /* omu.c */,
|
|
||||||
8349A8FE1FE6257F00E26435 /* pc_adp_otns.c */,
|
|
||||||
8349A8F01FE6257C00E26435 /* pc_ast.c */,
|
|
||||||
8349A8F21FE6257D00E26435 /* ps2_pcm.c */,
|
|
||||||
8349A8FC1FE6257F00E26435 /* ps2_xa2_rrp.c */,
|
|
||||||
8349A8F11FE6257D00E26435 /* sab.c */,
|
|
||||||
8349A8F51FE6257D00E26435 /* scd_pcm.c */,
|
|
||||||
8349A8F31FE6257D00E26435 /* sqex_scd_streamfile.h */,
|
|
||||||
8349A8F41FE6257D00E26435 /* ubi_sb.c */,
|
|
||||||
8349A8F91FE6257E00E26435 /* vsf_tta.c */,
|
|
||||||
8349A9011FE6258000E26435 /* vxn.c */,
|
|
||||||
83345A4D1F8AEB2800B2EAA4 /* nsw_opus.c */,
|
|
||||||
83345A4B1F8AEB2700B2EAA4 /* nub_xma.c */,
|
|
||||||
83345A4C1F8AEB2700B2EAA4 /* pc_al2.c */,
|
|
||||||
83345A4E1F8AEB2800B2EAA4 /* xvag.c */,
|
|
||||||
83AA5D201F6E2F9B0020821C /* awc.c */,
|
|
||||||
83AA5D211F6E2F9C0020821C /* hca_keys.h */,
|
|
||||||
83AA5D231F6E2F9C0020821C /* stm.c */,
|
|
||||||
839E21EA1F2EDB0500EE54D7 /* sk_aud.c */,
|
|
||||||
830165971F256BD000CA0941 /* txth.c */,
|
|
||||||
830165981F256BD000CA0941 /* ea_schl_fixed.c */,
|
|
||||||
830165991F256BD000CA0941 /* nds_strm_ffta2.c */,
|
|
||||||
83CAB8DC1F0B0744001BC993 /* pc_xa30.c */,
|
|
||||||
83CAB8E11F0B0745001BC993 /* wii_04sw.c */,
|
|
||||||
831BD11F1EEE1CF200198540 /* ngc_ulw.c */,
|
|
||||||
8350270C1ED119D200C25929 /* ps3_mta2.c */,
|
|
||||||
833A7A2D1ED11961003EC53E /* xau.c */,
|
|
||||||
83709DFF1ECBC1A4005C03D3 /* gtd.c */,
|
|
||||||
83709E001ECBC1A4005C03D3 /* mc3.c */,
|
|
||||||
83709E011ECBC1A4005C03D3 /* mss.c */,
|
|
||||||
83709E021ECBC1A4005C03D3 /* ps2_rxws.c */,
|
|
||||||
83709E031ECBC1A4005C03D3 /* ta_aac.c */,
|
|
||||||
83709E041ECBC1A4005C03D3 /* waa_wac_wad_wam.c */,
|
|
||||||
831BA60E1EAC61A500CF89B0 /* adx.c */,
|
|
||||||
831BA60F1EAC61A500CF89B0 /* ogl.c */,
|
|
||||||
831BA6101EAC61A500CF89B0 /* ps2_vds_vdm.c */,
|
|
||||||
831BA6111EAC61A500CF89B0 /* sgxd.c */,
|
|
||||||
831BA6121EAC61A500CF89B0 /* sxd.c */,
|
|
||||||
831BA6131EAC61A500CF89B0 /* ubi_raki.c */,
|
|
||||||
831BA6141EAC61A500CF89B0 /* vawx.c */,
|
|
||||||
831BA6151EAC61A500CF89B0 /* x360_cxs.c */,
|
|
||||||
831BA6171EAC61A500CF89B0 /* x360_pasx.c */,
|
|
||||||
83FF0EBB1E93282100C58054 /* wwise.c */,
|
|
||||||
83AB8C731E8072A100086084 /* nub_vag.c */,
|
|
||||||
83AB8C741E8072A100086084 /* x360_ast.c */,
|
|
||||||
83299FCE1E7660C7003A3242 /* bik.c */,
|
|
||||||
83299FCF1E7660C7003A3242 /* dsp_adx.c */,
|
|
||||||
8350C0591E071990009E0A93 /* ps2_svag_snk.c */,
|
|
||||||
8350C0541E071881009E0A93 /* xma.c */,
|
|
||||||
838BDB6D1D3B043C0022CA6F /* ffmpeg.c */,
|
|
||||||
8323894F1D2246C300482226 /* hca.c */,
|
|
||||||
83EDE5D61A70951A005F5D84 /* mca.c */,
|
|
||||||
83EDE5D71A70951A005F5D84 /* btsnd.c */,
|
|
||||||
834D3A6D19F47C98001C54F6 /* g1l.c */,
|
|
||||||
83BAFB6B19F45EB3005DAB60 /* bfstm.c */,
|
|
||||||
83A5F75E198DF021009AF94C /* bfwav.c */,
|
|
||||||
83F5F8821908D0A400C8E65F /* fsb5.c */,
|
|
||||||
836F6E2918BDC2180095E648 /* 2dx9.c */,
|
836F6E2918BDC2180095E648 /* 2dx9.c */,
|
||||||
|
8349A9041FE6258100E26435 /* aax_streamfile.h */,
|
||||||
836F6E2A18BDC2180095E648 /* aax.c */,
|
836F6E2A18BDC2180095E648 /* aax.c */,
|
||||||
836F6E2B18BDC2180095E648 /* acm.c */,
|
836F6E2B18BDC2180095E648 /* acm.c */,
|
||||||
836F6E2C18BDC2180095E648 /* ads.c */,
|
836F6E2C18BDC2180095E648 /* ads.c */,
|
||||||
|
8349A9021FE6258100E26435 /* adx_keys.h */,
|
||||||
|
831BA60E1EAC61A500CF89B0 /* adx.c */,
|
||||||
|
8349A9001FE6258000E26435 /* afc.c */,
|
||||||
836F6E2F18BDC2180095E648 /* agsc.c */,
|
836F6E2F18BDC2180095E648 /* agsc.c */,
|
||||||
836F6E3018BDC2180095E648 /* ahx.c */,
|
836F6E3018BDC2180095E648 /* ahx.c */,
|
||||||
836F6E3118BDC2180095E648 /* aifc.c */,
|
836F6E3118BDC2180095E648 /* aifc.c */,
|
||||||
|
8349A8F61FE6257E00E26435 /* aix_streamfile.h */,
|
||||||
836F6E3218BDC2180095E648 /* aix.c */,
|
836F6E3218BDC2180095E648 /* aix.c */,
|
||||||
836F6E3318BDC2180095E648 /* akb.c */,
|
836F6E3318BDC2180095E648 /* akb.c */,
|
||||||
836F6E3418BDC2180095E648 /* apple_caff.c */,
|
836F6E3418BDC2180095E648 /* apple_caff.c */,
|
||||||
836F6E3518BDC2180095E648 /* ast.c */,
|
836F6E3518BDC2180095E648 /* ast.c */,
|
||||||
|
83A21F80201D8980000F04B9 /* atsl3.c */,
|
||||||
|
83A21F7C201D897F000F04B9 /* atx.c */,
|
||||||
|
83AA5D201F6E2F9B0020821C /* awc.c */,
|
||||||
836F6E3618BDC2180095E648 /* baf.c */,
|
836F6E3618BDC2180095E648 /* baf.c */,
|
||||||
|
8349A8F81FE6257E00E26435 /* bar_streamfile.h */,
|
||||||
|
8349A9051FE6258100E26435 /* bar.c */,
|
||||||
836F6E3718BDC2180095E648 /* bcstm.c */,
|
836F6E3718BDC2180095E648 /* bcstm.c */,
|
||||||
|
83BAFB6B19F45EB3005DAB60 /* bfstm.c */,
|
||||||
|
83A5F75E198DF021009AF94C /* bfwav.c */,
|
||||||
836F6E3818BDC2180095E648 /* bgw.c */,
|
836F6E3818BDC2180095E648 /* bgw.c */,
|
||||||
|
83299FCE1E7660C7003A3242 /* bik.c */,
|
||||||
836F6E3918BDC2180095E648 /* bnsf.c */,
|
836F6E3918BDC2180095E648 /* bnsf.c */,
|
||||||
836F6E3A18BDC2180095E648 /* brstm.c */,
|
836F6E3A18BDC2180095E648 /* brstm.c */,
|
||||||
|
83EDE5D71A70951A005F5D84 /* btsnd.c */,
|
||||||
836F6E3B18BDC2180095E648 /* capdsp.c */,
|
836F6E3B18BDC2180095E648 /* capdsp.c */,
|
||||||
836F6E3C18BDC2180095E648 /* Cstr.c */,
|
836F6E3C18BDC2180095E648 /* Cstr.c */,
|
||||||
836F6E3D18BDC2180095E648 /* dc_asd.c */,
|
836F6E3D18BDC2180095E648 /* dc_asd.c */,
|
||||||
|
@ -1342,43 +1299,66 @@
|
||||||
836F6E3F18BDC2180095E648 /* dc_idvi.c */,
|
836F6E3F18BDC2180095E648 /* dc_idvi.c */,
|
||||||
836F6E4018BDC2180095E648 /* dc_kcey.c */,
|
836F6E4018BDC2180095E648 /* dc_kcey.c */,
|
||||||
836F6E4118BDC2180095E648 /* dc_str.c */,
|
836F6E4118BDC2180095E648 /* dc_str.c */,
|
||||||
|
8349A8EE1FE6257C00E26435 /* dec.c */,
|
||||||
836F6E4318BDC2180095E648 /* dmsg_segh.c */,
|
836F6E4318BDC2180095E648 /* dmsg_segh.c */,
|
||||||
|
83299FCF1E7660C7003A3242 /* dsp_adx.c */,
|
||||||
836F6E4418BDC2180095E648 /* dsp_bdsp.c */,
|
836F6E4418BDC2180095E648 /* dsp_bdsp.c */,
|
||||||
836F6E4518BDC2180095E648 /* dsp_sth_str.c */,
|
836F6E4518BDC2180095E648 /* dsp_sth_str.c */,
|
||||||
|
8349A8FF1FE6258000E26435 /* ea_1snh.c */,
|
||||||
|
8349A8F71FE6257E00E26435 /* ea_eaac.c */,
|
||||||
|
830165981F256BD000CA0941 /* ea_schl_fixed.c */,
|
||||||
836F6E4618BDC2180095E648 /* ea_schl.c */,
|
836F6E4618BDC2180095E648 /* ea_schl.c */,
|
||||||
836F6E4818BDC2180095E648 /* emff.c */,
|
836F6E4818BDC2180095E648 /* emff.c */,
|
||||||
836F6E4918BDC2180095E648 /* exakt_sc.c */,
|
836F6E4918BDC2180095E648 /* exakt_sc.c */,
|
||||||
836F6E4A18BDC2180095E648 /* excitebots.c */,
|
836F6E4A18BDC2180095E648 /* excitebots.c */,
|
||||||
|
8349A8EF1FE6257C00E26435 /* ezw.c */,
|
||||||
|
838BDB6D1D3B043C0022CA6F /* ffmpeg.c */,
|
||||||
836F6E4B18BDC2180095E648 /* ffw.c */,
|
836F6E4B18BDC2180095E648 /* ffw.c */,
|
||||||
|
8349A8FD1FE6257F00E26435 /* flx.c */,
|
||||||
|
83A21F81201D8981000F04B9 /* fsb_encrypted.c */,
|
||||||
|
83A21F7E201D8980000F04B9 /* fsb_keys.h */,
|
||||||
836F6E4C18BDC2180095E648 /* fsb.c */,
|
836F6E4C18BDC2180095E648 /* fsb.c */,
|
||||||
|
83F5F8821908D0A400C8E65F /* fsb5.c */,
|
||||||
|
834D3A6D19F47C98001C54F6 /* g1l.c */,
|
||||||
836F6E4D18BDC2180095E648 /* gca.c */,
|
836F6E4D18BDC2180095E648 /* gca.c */,
|
||||||
836F6E4E18BDC2180095E648 /* gcsw.c */,
|
836F6E4E18BDC2180095E648 /* gcsw.c */,
|
||||||
836F6E4F18BDC2180095E648 /* genh.c */,
|
836F6E4F18BDC2180095E648 /* genh.c */,
|
||||||
836F6E5118BDC2180095E648 /* gsp_gsb.c */,
|
836F6E5118BDC2180095E648 /* gsp_gsb.c */,
|
||||||
|
83709DFF1ECBC1A4005C03D3 /* gtd.c */,
|
||||||
836F6E5218BDC2180095E648 /* halpst.c */,
|
836F6E5218BDC2180095E648 /* halpst.c */,
|
||||||
|
83AA5D211F6E2F9C0020821C /* hca_keys.h */,
|
||||||
|
8323894F1D2246C300482226 /* hca.c */,
|
||||||
836F6E5318BDC2180095E648 /* his.c */,
|
836F6E5318BDC2180095E648 /* his.c */,
|
||||||
836F6E5418BDC2180095E648 /* idsp.c */,
|
836F6E5418BDC2180095E648 /* idsp.c */,
|
||||||
836F6E5518BDC2180095E648 /* ios_psnd.c */,
|
836F6E5518BDC2180095E648 /* ios_psnd.c */,
|
||||||
836F6E5618BDC2180095E648 /* ish_isd.c */,
|
836F6E5618BDC2180095E648 /* ish_isd.c */,
|
||||||
836F6E5718BDC2180095E648 /* ivaud.c */,
|
836F6E5718BDC2180095E648 /* ivaud.c */,
|
||||||
836F6E5818BDC2180095E648 /* ivb.c */,
|
836F6E5818BDC2180095E648 /* ivb.c */,
|
||||||
|
83A21F83201D8981000F04B9 /* kma9.c */,
|
||||||
836F6E5918BDC2180095E648 /* kraw.c */,
|
836F6E5918BDC2180095E648 /* kraw.c */,
|
||||||
|
830EBE122004656E0023AA10 /* ktss.c */,
|
||||||
836F6E5A18BDC2180095E648 /* lsf.c */,
|
836F6E5A18BDC2180095E648 /* lsf.c */,
|
||||||
836F6E5C18BDC2180095E648 /* mattel_hyperscan.c */,
|
836F6E5C18BDC2180095E648 /* mattel_hyperscan.c */,
|
||||||
836F6E5D18BDC2180095E648 /* maxis_xa.c */,
|
836F6E5D18BDC2180095E648 /* maxis_xa.c */,
|
||||||
|
83709E001ECBC1A4005C03D3 /* mc3.c */,
|
||||||
|
83EDE5D61A70951A005F5D84 /* mca.c */,
|
||||||
836F6E5E18BDC2180095E648 /* meta.h */,
|
836F6E5E18BDC2180095E648 /* meta.h */,
|
||||||
836F6E5F18BDC2180095E648 /* mn_str.c */,
|
836F6E5F18BDC2180095E648 /* mn_str.c */,
|
||||||
|
8349A9031FE6258100E26435 /* mogg.c */,
|
||||||
836F6E6018BDC2180095E648 /* mp4.c */,
|
836F6E6018BDC2180095E648 /* mp4.c */,
|
||||||
|
83709E011ECBC1A4005C03D3 /* mss.c */,
|
||||||
836F6E6118BDC2180095E648 /* msvp.c */,
|
836F6E6118BDC2180095E648 /* msvp.c */,
|
||||||
836F6E6218BDC2180095E648 /* mus_acm.c */,
|
836F6E6218BDC2180095E648 /* mus_acm.c */,
|
||||||
836F6E6318BDC2180095E648 /* musc.c */,
|
836F6E6318BDC2180095E648 /* musc.c */,
|
||||||
836F6E6418BDC2180095E648 /* musx.c */,
|
836F6E6418BDC2180095E648 /* musx.c */,
|
||||||
836F6E6518BDC2180095E648 /* myspd.c */,
|
836F6E6518BDC2180095E648 /* myspd.c */,
|
||||||
|
8349A9061FE6258100E26435 /* naac.c */,
|
||||||
836F6E6618BDC2180095E648 /* naomi_adpcm.c */,
|
836F6E6618BDC2180095E648 /* naomi_adpcm.c */,
|
||||||
836F6E6718BDC2180095E648 /* naomi_spsd.c */,
|
836F6E6718BDC2180095E648 /* naomi_spsd.c */,
|
||||||
836F6E6818BDC2180095E648 /* nds_hwas.c */,
|
836F6E6818BDC2180095E648 /* nds_hwas.c */,
|
||||||
836F6E6918BDC2180095E648 /* nds_rrds.c */,
|
836F6E6918BDC2180095E648 /* nds_rrds.c */,
|
||||||
836F6E6A18BDC2180095E648 /* nds_sad.c */,
|
836F6E6A18BDC2180095E648 /* nds_sad.c */,
|
||||||
|
830165991F256BD000CA0941 /* nds_strm_ffta2.c */,
|
||||||
836F6E6B18BDC2180095E648 /* nds_strm.c */,
|
836F6E6B18BDC2180095E648 /* nds_strm.c */,
|
||||||
836F6E6C18BDC2180095E648 /* nds_swav.c */,
|
836F6E6C18BDC2180095E648 /* nds_swav.c */,
|
||||||
836F6E6D18BDC2180095E648 /* ngc_adpdtk.c */,
|
836F6E6D18BDC2180095E648 /* ngc_adpdtk.c */,
|
||||||
|
@ -1397,16 +1377,27 @@
|
||||||
836F6E7A18BDC2180095E648 /* ngc_sck_dsp.c */,
|
836F6E7A18BDC2180095E648 /* ngc_sck_dsp.c */,
|
||||||
836F6E7B18BDC2180095E648 /* ngc_ssm.c */,
|
836F6E7B18BDC2180095E648 /* ngc_ssm.c */,
|
||||||
836F6E7C18BDC2180095E648 /* ngc_tydsp.c */,
|
836F6E7C18BDC2180095E648 /* ngc_tydsp.c */,
|
||||||
|
831BD11F1EEE1CF200198540 /* ngc_ulw.c */,
|
||||||
|
8349A8FA1FE6257E00E26435 /* ngc_vid1.c */,
|
||||||
836F6E7E18BDC2180095E648 /* ngc_ymf.c */,
|
836F6E7E18BDC2180095E648 /* ngc_ymf.c */,
|
||||||
836F6E7F18BDC2180095E648 /* ngca.c */,
|
836F6E7F18BDC2180095E648 /* ngca.c */,
|
||||||
|
83345A4D1F8AEB2800B2EAA4 /* nsw_opus.c */,
|
||||||
|
83AB8C731E8072A100086084 /* nub_vag.c */,
|
||||||
|
83345A4B1F8AEB2700B2EAA4 /* nub_xma.c */,
|
||||||
836F6E8118BDC2180095E648 /* nwa.c */,
|
836F6E8118BDC2180095E648 /* nwa.c */,
|
||||||
836F6E8218BDC2180095E648 /* ogg_vorbis_file.c */,
|
83A21F7F201D8980000F04B9 /* ogg_vorbis.c */,
|
||||||
|
831BA60F1EAC61A500CF89B0 /* ogl.c */,
|
||||||
|
8349A8FB1FE6257F00E26435 /* omu.c */,
|
||||||
836F6E8318BDC2180095E648 /* otm.c */,
|
836F6E8318BDC2180095E648 /* otm.c */,
|
||||||
836F6E8418BDC2180095E648 /* p3d.c */,
|
836F6E8418BDC2180095E648 /* p3d.c */,
|
||||||
|
8349A8FE1FE6257F00E26435 /* pc_adp_otns.c */,
|
||||||
836F6E8518BDC2180095E648 /* pc_adp.c */,
|
836F6E8518BDC2180095E648 /* pc_adp.c */,
|
||||||
|
83345A4C1F8AEB2700B2EAA4 /* pc_al2.c */,
|
||||||
|
8349A8F01FE6257C00E26435 /* pc_ast.c */,
|
||||||
836F6E8618BDC2180095E648 /* pc_mxst.c */,
|
836F6E8618BDC2180095E648 /* pc_mxst.c */,
|
||||||
836F6E8718BDC2180095E648 /* pc_smp.c */,
|
836F6E8718BDC2180095E648 /* pc_smp.c */,
|
||||||
836F6E8818BDC2180095E648 /* pc_snds.c */,
|
836F6E8818BDC2180095E648 /* pc_snds.c */,
|
||||||
|
83CAB8DC1F0B0744001BC993 /* pc_xa30.c */,
|
||||||
836F6E8B18BDC2180095E648 /* pona.c */,
|
836F6E8B18BDC2180095E648 /* pona.c */,
|
||||||
836F6E8C18BDC2180095E648 /* pos.c */,
|
836F6E8C18BDC2180095E648 /* pos.c */,
|
||||||
836F6E8D18BDC2180095E648 /* ps2_2pfs.c */,
|
836F6E8D18BDC2180095E648 /* ps2_2pfs.c */,
|
||||||
|
@ -1446,12 +1437,13 @@
|
||||||
836F6EB018BDC2180095E648 /* ps2_mtaf.c */,
|
836F6EB018BDC2180095E648 /* ps2_mtaf.c */,
|
||||||
836F6EB118BDC2180095E648 /* ps2_npsf.c */,
|
836F6EB118BDC2180095E648 /* ps2_npsf.c */,
|
||||||
836F6EB218BDC2180095E648 /* ps2_p2bt.c */,
|
836F6EB218BDC2180095E648 /* ps2_p2bt.c */,
|
||||||
|
8349A8F21FE6257D00E26435 /* ps2_pcm.c */,
|
||||||
836F6EB318BDC2180095E648 /* ps2_pnb.c */,
|
836F6EB318BDC2180095E648 /* ps2_pnb.c */,
|
||||||
836F6EB418BDC2180095E648 /* ps2_psh.c */,
|
836F6EB418BDC2180095E648 /* ps2_psh.c */,
|
||||||
836F6EB518BDC2180095E648 /* ps2_psw.c */,
|
836F6EB518BDC2180095E648 /* ps2_psw.c */,
|
||||||
836F6EB618BDC2180095E648 /* ps2_rnd.c */,
|
836F6EB618BDC2180095E648 /* ps2_rnd.c */,
|
||||||
836F6EB718BDC2180095E648 /* ps2_rstm.c */,
|
836F6EB718BDC2180095E648 /* ps2_rstm.c */,
|
||||||
836F6EB818BDC2180095E648 /* rws.c */,
|
83709E021ECBC1A4005C03D3 /* ps2_rxws.c */,
|
||||||
836F6EBA18BDC2180095E648 /* ps2_sfs.c */,
|
836F6EBA18BDC2180095E648 /* ps2_sfs.c */,
|
||||||
836F6EBB18BDC2180095E648 /* ps2_sl3.c */,
|
836F6EBB18BDC2180095E648 /* ps2_sl3.c */,
|
||||||
836F6EBC18BDC2180095E648 /* ps2_smpl.c */,
|
836F6EBC18BDC2180095E648 /* ps2_smpl.c */,
|
||||||
|
@ -1461,12 +1453,14 @@
|
||||||
836F6EC018BDC2190095E648 /* ps2_ster.c */,
|
836F6EC018BDC2190095E648 /* ps2_ster.c */,
|
||||||
836F6EC218BDC2190095E648 /* ps2_str.c */,
|
836F6EC218BDC2190095E648 /* ps2_str.c */,
|
||||||
836F6EC318BDC2190095E648 /* ps2_strlr.c */,
|
836F6EC318BDC2190095E648 /* ps2_strlr.c */,
|
||||||
|
8350C0591E071990009E0A93 /* ps2_svag_snk.c */,
|
||||||
836F6EC418BDC2190095E648 /* ps2_svag.c */,
|
836F6EC418BDC2190095E648 /* ps2_svag.c */,
|
||||||
836F6EC518BDC2190095E648 /* ps2_tec.c */,
|
836F6EC518BDC2190095E648 /* ps2_tec.c */,
|
||||||
836F6EC618BDC2190095E648 /* ps2_tk5.c */,
|
836F6EC618BDC2190095E648 /* ps2_tk5.c */,
|
||||||
836F6EC718BDC2190095E648 /* ps2_vag.c */,
|
836F6EC718BDC2190095E648 /* ps2_vag.c */,
|
||||||
836F6EC818BDC2190095E648 /* ps2_vas.c */,
|
836F6EC818BDC2190095E648 /* ps2_vas.c */,
|
||||||
836F6EC918BDC2190095E648 /* ps2_vbk.c */,
|
836F6EC918BDC2190095E648 /* ps2_vbk.c */,
|
||||||
|
831BA6101EAC61A500CF89B0 /* ps2_vds_vdm.c */,
|
||||||
836F6ECA18BDC2190095E648 /* ps2_vgs.c */,
|
836F6ECA18BDC2190095E648 /* ps2_vgs.c */,
|
||||||
836F6ECB18BDC2190095E648 /* ps2_vgv.c */,
|
836F6ECB18BDC2190095E648 /* ps2_vgv.c */,
|
||||||
836F6ECC18BDC2190095E648 /* ps2_vms.c */,
|
836F6ECC18BDC2190095E648 /* ps2_vms.c */,
|
||||||
|
@ -1475,12 +1469,14 @@
|
||||||
836F6ECF18BDC2190095E648 /* ps2_wad.c */,
|
836F6ECF18BDC2190095E648 /* ps2_wad.c */,
|
||||||
836F6ED018BDC2190095E648 /* ps2_wb.c */,
|
836F6ED018BDC2190095E648 /* ps2_wb.c */,
|
||||||
836F6ED118BDC2190095E648 /* ps2_wmus.c */,
|
836F6ED118BDC2190095E648 /* ps2_wmus.c */,
|
||||||
|
8349A8FC1FE6257F00E26435 /* ps2_xa2_rrp.c */,
|
||||||
836F6ED218BDC2190095E648 /* ps2_xa2.c */,
|
836F6ED218BDC2190095E648 /* ps2_xa2.c */,
|
||||||
836F6ED318BDC2190095E648 /* ps2_xa30.c */,
|
836F6ED318BDC2190095E648 /* ps2_xa30.c */,
|
||||||
836F6ED518BDC2190095E648 /* ps3_cps.c */,
|
836F6ED518BDC2190095E648 /* ps3_cps.c */,
|
||||||
836F6ED618BDC2190095E648 /* ps3_ivag.c */,
|
836F6ED618BDC2190095E648 /* ps3_ivag.c */,
|
||||||
836F6ED718BDC2190095E648 /* ps3_klbs.c */,
|
836F6ED718BDC2190095E648 /* ps3_klbs.c */,
|
||||||
836F6ED818BDC2190095E648 /* ps3_msf.c */,
|
836F6ED818BDC2190095E648 /* ps3_msf.c */,
|
||||||
|
8350270C1ED119D200C25929 /* ps3_mta2.c */,
|
||||||
836F6ED918BDC2190095E648 /* ps3_past.c */,
|
836F6ED918BDC2190095E648 /* ps3_past.c */,
|
||||||
836F6EDD18BDC2190095E648 /* psx_cdxa.c */,
|
836F6EDD18BDC2190095E648 /* psx_cdxa.c */,
|
||||||
836F6EDE18BDC2190095E648 /* psx_fag.c */,
|
836F6EDE18BDC2190095E648 /* psx_fag.c */,
|
||||||
|
@ -1493,29 +1489,48 @@
|
||||||
836F6EE518BDC2190095E648 /* rs03.c */,
|
836F6EE518BDC2190095E648 /* rs03.c */,
|
||||||
836F6EE618BDC2190095E648 /* rsd.c */,
|
836F6EE618BDC2190095E648 /* rsd.c */,
|
||||||
836F6EE718BDC2190095E648 /* rsf.c */,
|
836F6EE718BDC2190095E648 /* rsf.c */,
|
||||||
|
836F6EB818BDC2180095E648 /* rws.c */,
|
||||||
836F6EE818BDC2190095E648 /* rwsd.c */,
|
836F6EE818BDC2190095E648 /* rwsd.c */,
|
||||||
836F6EE918BDC2190095E648 /* rwx.c */,
|
836F6EE918BDC2190095E648 /* rwx.c */,
|
||||||
836F6EEA18BDC2190095E648 /* s14_sss.c */,
|
836F6EEA18BDC2190095E648 /* s14_sss.c */,
|
||||||
|
8349A8F11FE6257D00E26435 /* sab.c */,
|
||||||
836F6EEB18BDC2190095E648 /* sat_baka.c */,
|
836F6EEB18BDC2190095E648 /* sat_baka.c */,
|
||||||
836F6EEC18BDC2190095E648 /* sat_dvi.c */,
|
836F6EEC18BDC2190095E648 /* sat_dvi.c */,
|
||||||
836F6EED18BDC2190095E648 /* sat_sap.c */,
|
836F6EED18BDC2190095E648 /* sat_sap.c */,
|
||||||
|
8349A8F51FE6257D00E26435 /* scd_pcm.c */,
|
||||||
836F6EEE18BDC2190095E648 /* sd9.c */,
|
836F6EEE18BDC2190095E648 /* sd9.c */,
|
||||||
836F6EEF18BDC2190095E648 /* sdt.c */,
|
836F6EEF18BDC2190095E648 /* sdt.c */,
|
||||||
836F6EF018BDC2190095E648 /* seg.c */,
|
836F6EF018BDC2190095E648 /* seg.c */,
|
||||||
836F6EF118BDC2190095E648 /* sfl.c */,
|
836F6EF118BDC2190095E648 /* sfl.c */,
|
||||||
|
831BA6111EAC61A500CF89B0 /* sgxd.c */,
|
||||||
|
839E21EA1F2EDB0500EE54D7 /* sk_aud.c */,
|
||||||
836F6EF218BDC2190095E648 /* sli.c */,
|
836F6EF218BDC2190095E648 /* sli.c */,
|
||||||
|
83A21F82201D8981000F04B9 /* sps_n1.c */,
|
||||||
836F6EF318BDC2190095E648 /* spt_spd.c */,
|
836F6EF318BDC2190095E648 /* spt_spd.c */,
|
||||||
|
8349A8F31FE6257D00E26435 /* sqex_scd_streamfile.h */,
|
||||||
836F6EF418BDC2190095E648 /* sqex_scd.c */,
|
836F6EF418BDC2190095E648 /* sqex_scd.c */,
|
||||||
|
83A21F84201D8981000F04B9 /* sqex_sead.c */,
|
||||||
|
83AA5D231F6E2F9C0020821C /* stm.c */,
|
||||||
836F6EF618BDC2190095E648 /* str_asr.c */,
|
836F6EF618BDC2190095E648 /* str_asr.c */,
|
||||||
836F6EF718BDC2190095E648 /* str_snds.c */,
|
836F6EF718BDC2190095E648 /* str_snds.c */,
|
||||||
836F6EF818BDC2190095E648 /* stx.c */,
|
836F6EF818BDC2190095E648 /* stx.c */,
|
||||||
836F6EF918BDC2190095E648 /* svs.c */,
|
836F6EF918BDC2190095E648 /* svs.c */,
|
||||||
|
831BA6121EAC61A500CF89B0 /* sxd.c */,
|
||||||
|
83709E031ECBC1A4005C03D3 /* ta_aac.c */,
|
||||||
836F6EFA18BDC2190095E648 /* thp.c */,
|
836F6EFA18BDC2190095E648 /* thp.c */,
|
||||||
836F6EFB18BDC2190095E648 /* tun.c */,
|
836F6EFB18BDC2190095E648 /* tun.c */,
|
||||||
|
830165971F256BD000CA0941 /* txth.c */,
|
||||||
836F6EFC18BDC2190095E648 /* ubi_ckd.c */,
|
836F6EFC18BDC2190095E648 /* ubi_ckd.c */,
|
||||||
|
831BA6131EAC61A500CF89B0 /* ubi_raki.c */,
|
||||||
|
8349A8F41FE6257D00E26435 /* ubi_sb.c */,
|
||||||
|
831BA6141EAC61A500CF89B0 /* vawx.c */,
|
||||||
836F6EFD18BDC2190095E648 /* vgs.c */,
|
836F6EFD18BDC2190095E648 /* vgs.c */,
|
||||||
836F6EFE18BDC2190095E648 /* vs.c */,
|
836F6EFE18BDC2190095E648 /* vs.c */,
|
||||||
|
8349A8F91FE6257E00E26435 /* vsf_tta.c */,
|
||||||
836F6EFF18BDC2190095E648 /* vsf.c */,
|
836F6EFF18BDC2190095E648 /* vsf.c */,
|
||||||
|
8349A9011FE6258000E26435 /* vxn.c */,
|
||||||
|
83709E041ECBC1A4005C03D3 /* waa_wac_wad_wam.c */,
|
||||||
|
83CAB8E11F0B0745001BC993 /* wii_04sw.c */,
|
||||||
836F6F0018BDC2190095E648 /* wii_bns.c */,
|
836F6F0018BDC2190095E648 /* wii_bns.c */,
|
||||||
836F6F0118BDC2190095E648 /* wii_mus.c */,
|
836F6F0118BDC2190095E648 /* wii_mus.c */,
|
||||||
836F6F0218BDC2190095E648 /* wii_ras.c */,
|
836F6F0218BDC2190095E648 /* wii_ras.c */,
|
||||||
|
@ -1526,15 +1541,24 @@
|
||||||
836F6F0718BDC2190095E648 /* wpd.c */,
|
836F6F0718BDC2190095E648 /* wpd.c */,
|
||||||
836F6F0818BDC2190095E648 /* ws_aud.c */,
|
836F6F0818BDC2190095E648 /* ws_aud.c */,
|
||||||
836F6F0918BDC2190095E648 /* wvs.c */,
|
836F6F0918BDC2190095E648 /* wvs.c */,
|
||||||
|
83FF0EBB1E93282100C58054 /* wwise.c */,
|
||||||
|
83AB8C741E8072A100086084 /* x360_ast.c */,
|
||||||
|
831BA6151EAC61A500CF89B0 /* x360_cxs.c */,
|
||||||
|
831BA6171EAC61A500CF89B0 /* x360_pasx.c */,
|
||||||
836F6F0A18BDC2190095E648 /* x360_tra.c */,
|
836F6F0A18BDC2190095E648 /* x360_tra.c */,
|
||||||
|
833A7A2D1ED11961003EC53E /* xau.c */,
|
||||||
836F6F0B18BDC2190095E648 /* xbox_hlwav.c */,
|
836F6F0B18BDC2190095E648 /* xbox_hlwav.c */,
|
||||||
836F6F0C18BDC2190095E648 /* xbox_ims.c */,
|
836F6F0C18BDC2190095E648 /* xbox_ims.c */,
|
||||||
836F6F0E18BDC2190095E648 /* xbox_wavm.c */,
|
836F6F0E18BDC2190095E648 /* xbox_wavm.c */,
|
||||||
836F6F0F18BDC2190095E648 /* xbox_xmu.c */,
|
836F6F0F18BDC2190095E648 /* xbox_xmu.c */,
|
||||||
836F6F1018BDC2190095E648 /* xbox_xvas.c */,
|
836F6F1018BDC2190095E648 /* xbox_xvas.c */,
|
||||||
836F6F1118BDC2190095E648 /* xbox_xwav.c */,
|
836F6F1118BDC2190095E648 /* xbox_xwav.c */,
|
||||||
|
8350C0541E071881009E0A93 /* xma.c */,
|
||||||
|
830EBE112004656E0023AA10 /* xnb.c */,
|
||||||
836F6F1218BDC2190095E648 /* xss.c */,
|
836F6F1218BDC2190095E648 /* xss.c */,
|
||||||
|
83345A4E1F8AEB2800B2EAA4 /* xvag.c */,
|
||||||
836F6F1318BDC2190095E648 /* xwb.c */,
|
836F6F1318BDC2190095E648 /* xwb.c */,
|
||||||
|
83A21F7D201D8980000F04B9 /* xwc.c */,
|
||||||
836F6F1418BDC2190095E648 /* ydsp.c */,
|
836F6F1418BDC2190095E648 /* ydsp.c */,
|
||||||
836F6F1518BDC2190095E648 /* zsd.c */,
|
836F6F1518BDC2190095E648 /* zsd.c */,
|
||||||
836F6F1618BDC2190095E648 /* zwdsp.c */,
|
836F6F1618BDC2190095E648 /* zwdsp.c */,
|
||||||
|
@ -1580,6 +1604,7 @@
|
||||||
836F6F1F18BDC2190095E648 /* acm_decoder.h in Headers */,
|
836F6F1F18BDC2190095E648 /* acm_decoder.h in Headers */,
|
||||||
836F6F3518BDC2190095E648 /* nwa_decoder.h in Headers */,
|
836F6F3518BDC2190095E648 /* nwa_decoder.h in Headers */,
|
||||||
8349A91D1FE6258200E26435 /* aax_streamfile.h in Headers */,
|
8349A91D1FE6258200E26435 /* aax_streamfile.h in Headers */,
|
||||||
|
83A21F87201D8981000F04B9 /* fsb_keys.h in Headers */,
|
||||||
8349A90F1FE6258200E26435 /* aix_streamfile.h in Headers */,
|
8349A90F1FE6258200E26435 /* aix_streamfile.h in Headers */,
|
||||||
8349A9111FE6258200E26435 /* bar_streamfile.h in Headers */,
|
8349A9111FE6258200E26435 /* bar_streamfile.h in Headers */,
|
||||||
836F6F2718BDC2190095E648 /* g72x_state.h in Headers */,
|
836F6F2718BDC2190095E648 /* g72x_state.h in Headers */,
|
||||||
|
@ -1775,9 +1800,9 @@
|
||||||
83CAB8E31F0B0755001BC993 /* pc_xa30.c in Sources */,
|
83CAB8E31F0B0755001BC993 /* pc_xa30.c in Sources */,
|
||||||
83CAB8E21F0B0752001BC993 /* wii_04sw.c in Sources */,
|
83CAB8E21F0B0752001BC993 /* wii_04sw.c in Sources */,
|
||||||
8349A8DF1FE6251F00E26435 /* vorbis_custom_utils_vid1.c in Sources */,
|
8349A8DF1FE6251F00E26435 /* vorbis_custom_utils_vid1.c in Sources */,
|
||||||
|
83A21F8D201D8982000F04B9 /* sqex_sead.c in Sources */,
|
||||||
839B54571EEE1DA000048A2D /* rws_blocked.c in Sources */,
|
839B54571EEE1DA000048A2D /* rws_blocked.c in Sources */,
|
||||||
839B54521EEE1D9600048A2D /* ngc_ulw.c in Sources */,
|
839B54521EEE1D9600048A2D /* ngc_ulw.c in Sources */,
|
||||||
8349A8E01FE6251F00E26435 /* ffmpeg_decoder_utils_bgw_atrac3.c in Sources */,
|
|
||||||
836F6FAD18BDC2190095E648 /* ngc_dsp_konami.c in Sources */,
|
836F6FAD18BDC2190095E648 /* ngc_dsp_konami.c in Sources */,
|
||||||
836F6FF818BDC2190095E648 /* ps2_smpl.c in Sources */,
|
836F6FF818BDC2190095E648 /* ps2_smpl.c in Sources */,
|
||||||
836F6F8118BDC2190095E648 /* dsp_sth_str.c in Sources */,
|
836F6F8118BDC2190095E648 /* dsp_sth_str.c in Sources */,
|
||||||
|
@ -1873,6 +1898,7 @@
|
||||||
836F6FEC18BDC2190095E648 /* ps2_mtaf.c in Sources */,
|
836F6FEC18BDC2190095E648 /* ps2_mtaf.c in Sources */,
|
||||||
83D7318C1A749EEE00CA1366 /* g719_decoder.c in Sources */,
|
83D7318C1A749EEE00CA1366 /* g719_decoder.c in Sources */,
|
||||||
836F701118BDC2190095E648 /* ps3_cps.c in Sources */,
|
836F701118BDC2190095E648 /* ps3_cps.c in Sources */,
|
||||||
|
83A21F85201D8981000F04B9 /* atx.c in Sources */,
|
||||||
836F701418BDC2190095E648 /* ps3_msf.c in Sources */,
|
836F701418BDC2190095E648 /* ps3_msf.c in Sources */,
|
||||||
836F6F6518BDC2190095E648 /* 2dx9.c in Sources */,
|
836F6F6518BDC2190095E648 /* 2dx9.c in Sources */,
|
||||||
830EBE102004655D0023AA10 /* atrac9_decoder.c in Sources */,
|
830EBE102004655D0023AA10 /* atrac9_decoder.c in Sources */,
|
||||||
|
@ -1997,6 +2023,7 @@
|
||||||
836F701518BDC2190095E648 /* ps3_past.c in Sources */,
|
836F701518BDC2190095E648 /* ps3_past.c in Sources */,
|
||||||
836F6F7C18BDC2190095E648 /* dc_kcey.c in Sources */,
|
836F6F7C18BDC2190095E648 /* dc_kcey.c in Sources */,
|
||||||
836F6FED18BDC2190095E648 /* ps2_npsf.c in Sources */,
|
836F6FED18BDC2190095E648 /* ps2_npsf.c in Sources */,
|
||||||
|
83A21F8B201D8982000F04B9 /* sps_n1.c in Sources */,
|
||||||
836F6F9E18BDC2190095E648 /* mus_acm.c in Sources */,
|
836F6F9E18BDC2190095E648 /* mus_acm.c in Sources */,
|
||||||
83709E0E1ECBC1C3005C03D3 /* psv_decoder.c in Sources */,
|
83709E0E1ECBC1C3005C03D3 /* psv_decoder.c in Sources */,
|
||||||
831BA6191EAC61A500CF89B0 /* ogl.c in Sources */,
|
831BA6191EAC61A500CF89B0 /* ogl.c in Sources */,
|
||||||
|
@ -2033,6 +2060,7 @@
|
||||||
836F6F8918BDC2190095E648 /* gca.c in Sources */,
|
836F6F8918BDC2190095E648 /* gca.c in Sources */,
|
||||||
836F6F5718BDC2190095E648 /* str_snds_blocked.c in Sources */,
|
836F6F5718BDC2190095E648 /* str_snds_blocked.c in Sources */,
|
||||||
836F6FA418BDC2190095E648 /* nds_hwas.c in Sources */,
|
836F6FA418BDC2190095E648 /* nds_hwas.c in Sources */,
|
||||||
|
83A21F8A201D8982000F04B9 /* fsb_encrypted.c in Sources */,
|
||||||
836F6FD018BDC2190095E648 /* ps2_b1s.c in Sources */,
|
836F6FD018BDC2190095E648 /* ps2_b1s.c in Sources */,
|
||||||
836F701218BDC2190095E648 /* ps3_ivag.c in Sources */,
|
836F701218BDC2190095E648 /* ps3_ivag.c in Sources */,
|
||||||
83AA5D181F6E2F600020821C /* mpeg_custom_utils_awc.c in Sources */,
|
83AA5D181F6E2F600020821C /* mpeg_custom_utils_awc.c in Sources */,
|
||||||
|
@ -2052,6 +2080,7 @@
|
||||||
836F6F9518BDC2190095E648 /* kraw.c in Sources */,
|
836F6F9518BDC2190095E648 /* kraw.c in Sources */,
|
||||||
836F6FB718BDC2190095E648 /* ngc_ssm.c in Sources */,
|
836F6FB718BDC2190095E648 /* ngc_ssm.c in Sources */,
|
||||||
83709E051ECBC1A4005C03D3 /* gtd.c in Sources */,
|
83709E051ECBC1A4005C03D3 /* gtd.c in Sources */,
|
||||||
|
83A21F86201D8981000F04B9 /* xwc.c in Sources */,
|
||||||
83AA5D1E1F6E2F800020821C /* blocked_awc.c in Sources */,
|
83AA5D1E1F6E2F800020821C /* blocked_awc.c in Sources */,
|
||||||
836F704A18BDC2190095E648 /* xbox_wavm.c in Sources */,
|
836F704A18BDC2190095E648 /* xbox_wavm.c in Sources */,
|
||||||
836F6F8618BDC2190095E648 /* excitebots.c in Sources */,
|
836F6F8618BDC2190095E648 /* excitebots.c in Sources */,
|
||||||
|
@ -2080,9 +2109,9 @@
|
||||||
8349A9081FE6258200E26435 /* ezw.c in Sources */,
|
8349A9081FE6258200E26435 /* ezw.c in Sources */,
|
||||||
836F6FE118BDC2190095E648 /* ps2_jstm.c in Sources */,
|
836F6FE118BDC2190095E648 /* ps2_jstm.c in Sources */,
|
||||||
836F6FD918BDC2190095E648 /* ps2_gcm.c in Sources */,
|
836F6FD918BDC2190095E648 /* ps2_gcm.c in Sources */,
|
||||||
|
83A21F88201D8981000F04B9 /* ogg_vorbis.c in Sources */,
|
||||||
836F6F8E18BDC2190095E648 /* halpst.c in Sources */,
|
836F6F8E18BDC2190095E648 /* halpst.c in Sources */,
|
||||||
836F6FEE18BDC2190095E648 /* ps2_p2bt.c in Sources */,
|
836F6FEE18BDC2190095E648 /* ps2_p2bt.c in Sources */,
|
||||||
836F6FBE18BDC2190095E648 /* ogg_vorbis_file.c in Sources */,
|
|
||||||
836F702618BDC2190095E648 /* s14_sss.c in Sources */,
|
836F702618BDC2190095E648 /* s14_sss.c in Sources */,
|
||||||
836F6F4818BDC2190095E648 /* halpst_blocked.c in Sources */,
|
836F6F4818BDC2190095E648 /* halpst_blocked.c in Sources */,
|
||||||
83AA5D1D1F6E2F800020821C /* blocked_vgs.c in Sources */,
|
83AA5D1D1F6E2F800020821C /* blocked_vgs.c in Sources */,
|
||||||
|
@ -2111,6 +2140,7 @@
|
||||||
836F6FBF18BDC2190095E648 /* otm.c in Sources */,
|
836F6FBF18BDC2190095E648 /* otm.c in Sources */,
|
||||||
836F6FDD18BDC2190095E648 /* ps2_ikm.c in Sources */,
|
836F6FDD18BDC2190095E648 /* ps2_ikm.c in Sources */,
|
||||||
836F6FBD18BDC2190095E648 /* nwa.c in Sources */,
|
836F6FBD18BDC2190095E648 /* nwa.c in Sources */,
|
||||||
|
83A21F8C201D8982000F04B9 /* kma9.c in Sources */,
|
||||||
836F6FC418BDC2190095E648 /* pc_snds.c in Sources */,
|
836F6FC418BDC2190095E648 /* pc_snds.c in Sources */,
|
||||||
836F704E18BDC2190095E648 /* xss.c in Sources */,
|
836F704E18BDC2190095E648 /* xss.c in Sources */,
|
||||||
836F6FD118BDC2190095E648 /* ps2_bg00.c in Sources */,
|
836F6FD118BDC2190095E648 /* ps2_bg00.c in Sources */,
|
||||||
|
@ -2127,7 +2157,9 @@
|
||||||
836F703518BDC2190095E648 /* svs.c in Sources */,
|
836F703518BDC2190095E648 /* svs.c in Sources */,
|
||||||
836F6FA318BDC2190095E648 /* naomi_spsd.c in Sources */,
|
836F6FA318BDC2190095E648 /* naomi_spsd.c in Sources */,
|
||||||
836F6F9D18BDC2190095E648 /* msvp.c in Sources */,
|
836F6F9D18BDC2190095E648 /* msvp.c in Sources */,
|
||||||
|
83A21F7B201D895B000F04B9 /* blocked_xvag.c in Sources */,
|
||||||
836F6FBA18BDC2190095E648 /* ngc_ymf.c in Sources */,
|
836F6FBA18BDC2190095E648 /* ngc_ymf.c in Sources */,
|
||||||
|
83A21F89201D8982000F04B9 /* atsl3.c in Sources */,
|
||||||
836F705018BDC2190095E648 /* ydsp.c in Sources */,
|
836F705018BDC2190095E648 /* ydsp.c in Sources */,
|
||||||
836F702718BDC2190095E648 /* sat_baka.c in Sources */,
|
836F702718BDC2190095E648 /* sat_baka.c in Sources */,
|
||||||
83345A4A1F8AEAF900B2EAA4 /* ffmpeg_decoder_utils_switch_opus.c in Sources */,
|
83345A4A1F8AEAF900B2EAA4 /* ffmpeg_decoder_utils_switch_opus.c in Sources */,
|
||||||
|
|
|
@ -119,7 +119,9 @@ void decode_atrac9(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do,
|
||||||
|
|
||||||
/* postadjust */ //todo improve
|
/* postadjust */ //todo improve
|
||||||
switch(data->config.type) {
|
switch(data->config.type) {
|
||||||
case ATRAC9_XVAG: /* skip other subsong blocks in XVAG */
|
case ATRAC9_XVAG:
|
||||||
|
case ATRAC9_KMA9:
|
||||||
|
/* skip other subsong blocks */
|
||||||
if (data->config.interleave_skip && ((stream->offset - stream->channel_start_offset) % data->config.interleave_skip == 0)) {
|
if (data->config.interleave_skip && ((stream->offset - stream->channel_start_offset) % data->config.interleave_skip == 0)) {
|
||||||
stream->offset += data->config.interleave_skip * (data->config.subsong_skip - 1);
|
stream->offset += data->config.interleave_skip * (data->config.subsong_skip - 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,7 +222,6 @@ static int ffmpeg_read(void *opaque, uint8_t *buf, int buf_size) {
|
||||||
switch(data->config.type) {
|
switch(data->config.type) {
|
||||||
case FFMPEG_EA_XMA: ret = ffmpeg_custom_read_eaxma(data, buf, buf_size); break;
|
case FFMPEG_EA_XMA: ret = ffmpeg_custom_read_eaxma(data, buf, buf_size); break;
|
||||||
case FFMPEG_SWITCH_OPUS: ret = ffmpeg_custom_read_switch_opus(data, buf, buf_size); break;
|
case FFMPEG_SWITCH_OPUS: ret = ffmpeg_custom_read_switch_opus(data, buf, buf_size); break;
|
||||||
case FFMPEG_BGW_ATRAC3: ret = ffmpeg_custom_read_bgw_atrac3(data, buf, buf_size); break;
|
|
||||||
//case FFMPEG_EA_SCHL: ret = ffmpeg_custom_read_ea_schl(data, buf, buf_size); break;
|
//case FFMPEG_EA_SCHL: ret = ffmpeg_custom_read_ea_schl(data, buf, buf_size); break;
|
||||||
//case FFMPEG_SFH: ret = ffmpeg_custom_read_sfh(data, buf, buf_size); break;
|
//case FFMPEG_SFH: ret = ffmpeg_custom_read_sfh(data, buf, buf_size); break;
|
||||||
default: ret = ffmpeg_custom_read_standard(data, buf, buf_size); break;
|
default: ret = ffmpeg_custom_read_standard(data, buf, buf_size); break;
|
||||||
|
@ -291,7 +290,6 @@ static int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) {
|
||||||
switch(data->config.type) {
|
switch(data->config.type) {
|
||||||
case FFMPEG_EA_XMA: offset = ffmpeg_custom_seek_eaxma(data, offset); break;
|
case FFMPEG_EA_XMA: offset = ffmpeg_custom_seek_eaxma(data, offset); break;
|
||||||
case FFMPEG_SWITCH_OPUS: offset = ffmpeg_custom_seek_switch_opus(data, offset); break;
|
case FFMPEG_SWITCH_OPUS: offset = ffmpeg_custom_seek_switch_opus(data, offset); break;
|
||||||
case FFMPEG_BGW_ATRAC3: offset = ffmpeg_custom_seek_bgw_atrac3(data, offset); break;
|
|
||||||
//case FFMPEG_EA_SCHL: offset = ffmpeg_custom_seek_ea_schl(data, offset); break;
|
//case FFMPEG_EA_SCHL: offset = ffmpeg_custom_seek_ea_schl(data, offset); break;
|
||||||
//case FFMPEG_SFH: offset = ffmpeg_custom_seek_sfh(data, offset); break;
|
//case FFMPEG_SFH: offset = ffmpeg_custom_seek_sfh(data, offset); break;
|
||||||
default: offset = ffmpeg_custom_seek_standard(data, offset); break;
|
default: offset = ffmpeg_custom_seek_standard(data, offset); break;
|
||||||
|
@ -309,7 +307,6 @@ static int64_t ffmpeg_size(ffmpeg_codec_data * data) {
|
||||||
switch(data->config.type) {
|
switch(data->config.type) {
|
||||||
case FFMPEG_EA_XMA: bytes = ffmpeg_custom_size_eaxma(data); break;
|
case FFMPEG_EA_XMA: bytes = ffmpeg_custom_size_eaxma(data); break;
|
||||||
case FFMPEG_SWITCH_OPUS: bytes = ffmpeg_custom_size_switch_opus(data); break;
|
case FFMPEG_SWITCH_OPUS: bytes = ffmpeg_custom_size_switch_opus(data); break;
|
||||||
case FFMPEG_BGW_ATRAC3: bytes = ffmpeg_custom_size_bgw_atrac3(data); break;
|
|
||||||
//case FFMPEG_EA_SCHL: bytes = ffmpeg_custom_size_ea_schl(data); break;
|
//case FFMPEG_EA_SCHL: bytes = ffmpeg_custom_size_ea_schl(data); break;
|
||||||
//case FFMPEG_SFH: bytes = ffmpeg_custom_size_sfh(data); break;
|
//case FFMPEG_SFH: bytes = ffmpeg_custom_size_sfh(data); break;
|
||||||
default: bytes = ffmpeg_custom_size_standard(data); break;
|
default: bytes = ffmpeg_custom_size_standard(data); break;
|
||||||
|
@ -806,9 +803,6 @@ void free_ffmpeg(ffmpeg_codec_data *data) {
|
||||||
close_streamfile(data->streamfile);
|
close_streamfile(data->streamfile);
|
||||||
data->streamfile = NULL;
|
data->streamfile = NULL;
|
||||||
}
|
}
|
||||||
if (data->config.key) {
|
|
||||||
free(data->config.key);
|
|
||||||
}
|
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,6 @@ int ffmpeg_custom_read_switch_opus(ffmpeg_codec_data *data, uint8_t *buf, int bu
|
||||||
int64_t ffmpeg_custom_seek_switch_opus(ffmpeg_codec_data *data, int64_t virtual_offset);
|
int64_t ffmpeg_custom_seek_switch_opus(ffmpeg_codec_data *data, int64_t virtual_offset);
|
||||||
int64_t ffmpeg_custom_size_switch_opus(ffmpeg_codec_data *data);
|
int64_t ffmpeg_custom_size_switch_opus(ffmpeg_codec_data *data);
|
||||||
|
|
||||||
int ffmpeg_custom_read_bgw_atrac3(ffmpeg_codec_data *data, uint8_t *buf, int buf_size);
|
|
||||||
int64_t ffmpeg_custom_seek_bgw_atrac3(ffmpeg_codec_data *data, int64_t virtual_offset);
|
|
||||||
int64_t ffmpeg_custom_size_bgw_atrac3(ffmpeg_codec_data *data);
|
|
||||||
|
|
||||||
//int ffmpeg_custom_read_ea_schl(ffmpeg_codec_data *data, uint8_t *buf, int buf_size);
|
//int ffmpeg_custom_read_ea_schl(ffmpeg_codec_data *data, uint8_t *buf, int buf_size);
|
||||||
//int64_t ffmpeg_custom_seek_ea_schl(ffmpeg_codec_data *data, int64_t virtual_offset);
|
//int64_t ffmpeg_custom_seek_ea_schl(ffmpeg_codec_data *data, int64_t virtual_offset);
|
||||||
//int64_t ffmpeg_custom_size_ea_schl(ffmpeg_codec_data *data);
|
//int64_t ffmpeg_custom_size_ea_schl(ffmpeg_codec_data *data);
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
#if 1
|
|
||||||
#include "coding.h"
|
|
||||||
#include "ffmpeg_decoder_utils.h"
|
|
||||||
|
|
||||||
#ifdef VGM_USE_FFMPEG
|
|
||||||
|
|
||||||
#define BGM_ATRAC3_FRAME_SIZE 0xC0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encrypted ATRAC3 used in BGW (Final Fantasy XI PC).
|
|
||||||
* Info from Moogle Toolbox: https://sourceforge.net/projects/mogbox/
|
|
||||||
*/
|
|
||||||
|
|
||||||
int ffmpeg_custom_read_bgw_atrac3(ffmpeg_codec_data *data, uint8_t *buf, int buf_size) {
|
|
||||||
int i, ch;
|
|
||||||
size_t bytes;
|
|
||||||
size_t block_align = BGM_ATRAC3_FRAME_SIZE * data->config.channels;
|
|
||||||
|
|
||||||
|
|
||||||
/* init key: first frame + modified channel header */
|
|
||||||
if (data->config.key == NULL) {
|
|
||||||
data->config.key = malloc(block_align);
|
|
||||||
if (!data->config.key) return 0;
|
|
||||||
|
|
||||||
read_streamfile(data->config.key, data->real_start, block_align, data->streamfile);
|
|
||||||
for (ch = 0; ch < data->config.channels; ch++) {
|
|
||||||
uint32_t xor = get_32bitBE(data->config.key + ch*BGM_ATRAC3_FRAME_SIZE);
|
|
||||||
put_32bitBE(data->config.key + ch*BGM_ATRAC3_FRAME_SIZE, xor ^ 0xA0024E9F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* read normally and unXOR the data */
|
|
||||||
bytes = read_streamfile(buf, data->real_offset, buf_size, data->streamfile);
|
|
||||||
for (i = 0; i < bytes; i++) {
|
|
||||||
int key_pos = (data->real_offset - data->real_start + i) % block_align;
|
|
||||||
buf[i] = buf[i] ^ data->config.key[key_pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
data->real_offset += bytes;
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t ffmpeg_custom_seek_bgw_atrac3(ffmpeg_codec_data *data, int64_t virtual_offset) {
|
|
||||||
int64_t seek_virtual_offset = virtual_offset - data->header_size;
|
|
||||||
|
|
||||||
data->real_offset = data->real_start + seek_virtual_offset;
|
|
||||||
return virtual_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t ffmpeg_custom_size_bgw_atrac3(ffmpeg_codec_data *data) {
|
|
||||||
return data->real_size + data->header_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
|
@ -47,7 +47,7 @@ int vorbis_custom_setup_init_wwise(STREAMFILE *streamFile, off_t start_offset, v
|
||||||
size_t header_size, packet_size;
|
size_t header_size, packet_size;
|
||||||
vorbis_custom_config cfg = data->config;
|
vorbis_custom_config cfg = data->config;
|
||||||
|
|
||||||
if (cfg.setup_type == HEADER_TRIAD) {
|
if (cfg.setup_type == WWV_HEADER_TRIAD) {
|
||||||
/* read 3 Wwise packets with triad (id/comment/setup), each with a Wwise header */
|
/* read 3 Wwise packets with triad (id/comment/setup), each with a Wwise header */
|
||||||
off_t offset = start_offset;
|
off_t offset = start_offset;
|
||||||
|
|
||||||
|
@ -132,17 +132,17 @@ static int get_packet_header(STREAMFILE *streamFile, off_t offset, wwise_header_
|
||||||
|
|
||||||
/* packet size doesn't include header size */
|
/* packet size doesn't include header size */
|
||||||
switch(header_type) {
|
switch(header_type) {
|
||||||
case TYPE_8: /* size 4+4 */
|
case WWV_TYPE_8: /* size 4+4 */
|
||||||
*packet_size = (uint32_t)read_32bit(offset, streamFile);
|
*packet_size = (uint32_t)read_32bit(offset, streamFile);
|
||||||
*granulepos = read_32bit(offset+4, streamFile);
|
*granulepos = read_32bit(offset+4, streamFile);
|
||||||
return 8;
|
return 8;
|
||||||
|
|
||||||
case TYPE_6: /* size 4+2 */
|
case WWV_TYPE_6: /* size 4+2 */
|
||||||
*packet_size = (uint16_t)read_16bit(offset, streamFile);
|
*packet_size = (uint16_t)read_16bit(offset, streamFile);
|
||||||
*granulepos = read_32bit(offset+2, streamFile);
|
*granulepos = read_32bit(offset+2, streamFile);
|
||||||
return 6;
|
return 6;
|
||||||
|
|
||||||
case TYPE_2: /* size 2 */
|
case WWV_TYPE_2: /* size 2 */
|
||||||
*packet_size = (uint16_t)read_16bit(offset, streamFile);
|
*packet_size = (uint16_t)read_16bit(offset, streamFile);
|
||||||
*granulepos = 0; /* granule is an arbitrary unit so we could use offset instead; libvorbis has no actually need it actually */
|
*granulepos = 0; /* granule is an arbitrary unit so we could use offset instead; libvorbis has no actually need it actually */
|
||||||
return 2;
|
return 2;
|
||||||
|
@ -306,7 +306,7 @@ static int ww2ogg_generate_vorbis_packet(vgm_bitstream * ow, vgm_bitstream * iw,
|
||||||
//VGM_ASSERT(granule < 0, "Wwise Vorbis: negative granule %i @ 0x%lx\n", granule, offset);
|
//VGM_ASSERT(granule < 0, "Wwise Vorbis: negative granule %i @ 0x%lx\n", granule, offset);
|
||||||
|
|
||||||
|
|
||||||
if (data->config.packet_type == MODIFIED) {
|
if (data->config.packet_type == WWV_MODIFIED) {
|
||||||
/* rebuild first bits of packet type and window info (for the i-MDCT) */
|
/* rebuild first bits of packet type and window info (for the i-MDCT) */
|
||||||
uint32_t packet_type = 0, mode_number = 0, remainder = 0;
|
uint32_t packet_type = 0, mode_number = 0, remainder = 0;
|
||||||
|
|
||||||
|
@ -423,13 +423,13 @@ static int ww2ogg_generate_vorbis_setup(vgm_bitstream * ow, vgm_bitstream * iw,
|
||||||
w_bits(ow, 8, codebook_count_less1);
|
w_bits(ow, 8, codebook_count_less1);
|
||||||
codebook_count = codebook_count_less1 + 1;
|
codebook_count = codebook_count_less1 + 1;
|
||||||
|
|
||||||
if (data->config.setup_type == FULL_SETUP) {
|
if (data->config.setup_type == WWV_FULL_SETUP) {
|
||||||
/* rebuild Wwise codebooks: untouched */
|
/* rebuild Wwise codebooks: untouched */
|
||||||
for (i = 0; i < codebook_count; i++) {
|
for (i = 0; i < codebook_count; i++) {
|
||||||
if(!ww2ogg_codebook_library_copy(ow, iw)) goto fail;
|
if(!ww2ogg_codebook_library_copy(ow, iw)) goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (data->config.setup_type == INLINE_CODEBOOKS) {
|
else if (data->config.setup_type == WWV_INLINE_CODEBOOKS) {
|
||||||
/* rebuild Wwise codebooks: inline in simplified format */
|
/* rebuild Wwise codebooks: inline in simplified format */
|
||||||
for (i = 0; i < codebook_count; i++) {
|
for (i = 0; i < codebook_count; i++) {
|
||||||
if(!ww2ogg_codebook_library_rebuild(ow, iw, 0, streamFile)) goto fail;
|
if(!ww2ogg_codebook_library_rebuild(ow, iw, 0, streamFile)) goto fail;
|
||||||
|
@ -456,7 +456,7 @@ static int ww2ogg_generate_vorbis_setup(vgm_bitstream * ow, vgm_bitstream * iw,
|
||||||
w_bits(ow, 16, dummy_time_value);
|
w_bits(ow, 16, dummy_time_value);
|
||||||
|
|
||||||
|
|
||||||
if (data->config.setup_type == FULL_SETUP) {
|
if (data->config.setup_type == WWV_FULL_SETUP) {
|
||||||
/* rest of setup is untouched, copy bits */
|
/* rest of setup is untouched, copy bits */
|
||||||
uint32_t bitly = 0;
|
uint32_t bitly = 0;
|
||||||
uint32_t total_bits_read = iw->b_off;
|
uint32_t total_bits_read = iw->b_off;
|
||||||
|
@ -1174,11 +1174,11 @@ static int load_wvc_array(uint8_t * buf, size_t bufsize, uint32_t codebook_id, w
|
||||||
const wvc_info * wvc_list;
|
const wvc_info * wvc_list;
|
||||||
|
|
||||||
switch (setup_type) {
|
switch (setup_type) {
|
||||||
case EXTERNAL_CODEBOOKS:
|
case WWV_EXTERNAL_CODEBOOKS:
|
||||||
wvc_list = wvc_list_standard;
|
wvc_list = wvc_list_standard;
|
||||||
list_length = sizeof(wvc_list_standard) / sizeof(wvc_info);
|
list_length = sizeof(wvc_list_standard) / sizeof(wvc_info);
|
||||||
break;
|
break;
|
||||||
case AOTUV603_CODEBOOKS:
|
case WWV_AOTUV603_CODEBOOKS:
|
||||||
wvc_list = wvc_list_aotuv603;
|
wvc_list = wvc_list_aotuv603;
|
||||||
list_length = sizeof(wvc_list_standard) / sizeof(wvc_info);
|
list_length = sizeof(wvc_list_standard) / sizeof(wvc_info);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -17,7 +17,7 @@ static const char* extension_list[] = {
|
||||||
"aaap",
|
"aaap",
|
||||||
"aax",
|
"aax",
|
||||||
//"ac3", //FFmpeg, not parsed //common?
|
//"ac3", //FFmpeg, not parsed //common?
|
||||||
"ace", //fake, for tri-Ace's formats
|
"ace", //fake, for tri-Ace's formats (to be removed)
|
||||||
"acm",
|
"acm",
|
||||||
"adm",
|
"adm",
|
||||||
"adp",
|
"adp",
|
||||||
|
@ -33,7 +33,7 @@ static const char* extension_list[] = {
|
||||||
"aix",
|
"aix",
|
||||||
"akb",
|
"akb",
|
||||||
"al2",
|
"al2",
|
||||||
"amts", //fake extension (to be removed)
|
"amts", //fake extension/header id for .stm (to be removed)
|
||||||
"ao", //txth/reserved [Cloudphobia (PC)]
|
"ao", //txth/reserved [Cloudphobia (PC)]
|
||||||
"as4",
|
"as4",
|
||||||
"asd",
|
"asd",
|
||||||
|
@ -43,6 +43,8 @@ static const char* extension_list[] = {
|
||||||
"ast",
|
"ast",
|
||||||
"at3",
|
"at3",
|
||||||
"at9",
|
"at9",
|
||||||
|
"atsl3",
|
||||||
|
"atx",
|
||||||
"aud",
|
"aud",
|
||||||
"aus",
|
"aus",
|
||||||
"awc",
|
"awc",
|
||||||
|
@ -138,7 +140,7 @@ static const char* extension_list[] = {
|
||||||
"iab",
|
"iab",
|
||||||
"iadp",
|
"iadp",
|
||||||
"idsp",
|
"idsp",
|
||||||
"idvi", //fake extension (to be removed)
|
"idvi", //fake extension for .pcm (to be removed)
|
||||||
"ikm",
|
"ikm",
|
||||||
"ild",
|
"ild",
|
||||||
"int",
|
"int",
|
||||||
|
@ -153,9 +155,10 @@ static const char* extension_list[] = {
|
||||||
"jstm",
|
"jstm",
|
||||||
|
|
||||||
"kces",
|
"kces",
|
||||||
"kcey", //fake extension (to be removed)
|
"kcey", //fake extension/header id (to be removed)
|
||||||
"khv",
|
"khv",
|
||||||
"kovs",
|
"km9",
|
||||||
|
"kovs", //.kvs header id
|
||||||
"kraw",
|
"kraw",
|
||||||
"ktss",
|
"ktss",
|
||||||
"kvs",
|
"kvs",
|
||||||
|
@ -172,6 +175,7 @@ static const char* extension_list[] = {
|
||||||
"lstm", //fake extension, for STMs
|
"lstm", //fake extension, for STMs
|
||||||
"lwav", //fake extension, for WAVs
|
"lwav", //fake extension, for WAVs
|
||||||
|
|
||||||
|
"mab",
|
||||||
"matx",
|
"matx",
|
||||||
"mc3",
|
"mc3",
|
||||||
"mca",
|
"mca",
|
||||||
|
@ -205,8 +209,9 @@ static const char* extension_list[] = {
|
||||||
"naac",
|
"naac",
|
||||||
"ndp",
|
"ndp",
|
||||||
"ngca",
|
"ngca",
|
||||||
|
"nop",
|
||||||
"nps",
|
"nps",
|
||||||
"npsf", //fake extension (to be removed)
|
"npsf", //fake extension/header id for .nps (to be removed)
|
||||||
"nus3bank",
|
"nus3bank",
|
||||||
"nwa",
|
"nwa",
|
||||||
|
|
||||||
|
@ -226,7 +231,7 @@ static const char* extension_list[] = {
|
||||||
"pnb",
|
"pnb",
|
||||||
"pona",
|
"pona",
|
||||||
"pos",
|
"pos",
|
||||||
"ps2stm", //fake extension (to be removed)
|
"ps2stm", //fake extension for .stm (to be removed)
|
||||||
"psh",
|
"psh",
|
||||||
"psnd",
|
"psnd",
|
||||||
"psw",
|
"psw",
|
||||||
|
@ -261,6 +266,7 @@ static const char* extension_list[] = {
|
||||||
"sb5",
|
"sb5",
|
||||||
"sb6",
|
"sb6",
|
||||||
"sb7",
|
"sb7",
|
||||||
|
"sbin",
|
||||||
"sc",
|
"sc",
|
||||||
"scd",
|
"scd",
|
||||||
"sck",
|
"sck",
|
||||||
|
@ -282,6 +288,7 @@ static const char* extension_list[] = {
|
||||||
"snd",
|
"snd",
|
||||||
"snds",
|
"snds",
|
||||||
"sng",
|
"sng",
|
||||||
|
"sngw",
|
||||||
"snr",
|
"snr",
|
||||||
"sns",
|
"sns",
|
||||||
"snu",
|
"snu",
|
||||||
|
@ -374,6 +381,7 @@ static const char* extension_list[] = {
|
||||||
"xvas",
|
"xvas",
|
||||||
"xwav",
|
"xwav",
|
||||||
"xwb",
|
"xwb",
|
||||||
|
"xwc",
|
||||||
"xwm", //FFmpeg, not parsed (XWMA)
|
"xwm", //FFmpeg, not parsed (XWMA)
|
||||||
"xwma", //FFmpeg, not parsed (XWMA)
|
"xwma", //FFmpeg, not parsed (XWMA)
|
||||||
"xws",
|
"xws",
|
||||||
|
@ -471,7 +479,7 @@ static const coding_info coding_info_list[] = {
|
||||||
{coding_APPLE_IMA4, "Apple Quicktime 4-bit IMA ADPCM"},
|
{coding_APPLE_IMA4, "Apple Quicktime 4-bit IMA ADPCM"},
|
||||||
{coding_SNDS_IMA, "Heavy Iron .snds 4-bit IMA ADPCM"},
|
{coding_SNDS_IMA, "Heavy Iron .snds 4-bit IMA ADPCM"},
|
||||||
{coding_OTNS_IMA, "Omikron: The Nomad Soul 4-bit IMA ADPCM"},
|
{coding_OTNS_IMA, "Omikron: The Nomad Soul 4-bit IMA ADPCM"},
|
||||||
{coding_FSB_IMA, "FSB multichannel 4-bit IMA ADPCM"},
|
{coding_FSB_IMA, "FSB 4-bit IMA ADPCM"},
|
||||||
{coding_WWISE_IMA, "Audiokinetic Wwise 4-bit IMA ADPCM"},
|
{coding_WWISE_IMA, "Audiokinetic Wwise 4-bit IMA ADPCM"},
|
||||||
{coding_REF_IMA, "Reflections 4-bit IMA ADPCM"},
|
{coding_REF_IMA, "Reflections 4-bit IMA ADPCM"},
|
||||||
{coding_AWC_IMA, "Rockstar AWC 4-bit IMA ADPCM"},
|
{coding_AWC_IMA, "Rockstar AWC 4-bit IMA ADPCM"},
|
||||||
|
@ -574,6 +582,7 @@ static const layout_info layout_info_list[] = {
|
||||||
{layout_blocked_awc, "blocked (AWC)"},
|
{layout_blocked_awc, "blocked (AWC)"},
|
||||||
{layout_blocked_vgs, "blocked (VGS)"},
|
{layout_blocked_vgs, "blocked (VGS)"},
|
||||||
{layout_blocked_vawx, "blocked (VAWX)"},
|
{layout_blocked_vawx, "blocked (VAWX)"},
|
||||||
|
{layout_blocked_xvag_subsong, "blocked (XVAG subsong)"},
|
||||||
#ifdef VGM_USE_VORBIS
|
#ifdef VGM_USE_VORBIS
|
||||||
{layout_ogg_vorbis, "Ogg"},
|
{layout_ogg_vorbis, "Ogg"},
|
||||||
#endif
|
#endif
|
||||||
|
@ -933,16 +942,20 @@ static const meta_info meta_info_list[] = {
|
||||||
{meta_NGC_VID1, "Neversoft VID1 header"},
|
{meta_NGC_VID1, "Neversoft VID1 header"},
|
||||||
{meta_PC_FLX, "Ultima IX .FLX header"},
|
{meta_PC_FLX, "Ultima IX .FLX header"},
|
||||||
{meta_MOGG, "Harmonix Music Systems MOGG Vorbis"},
|
{meta_MOGG, "Harmonix Music Systems MOGG Vorbis"},
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
{meta_OGG_VORBIS, "Ogg Vorbis"},
|
{meta_OGG_VORBIS, "Ogg Vorbis"},
|
||||||
{meta_OGG_SLI, "Ogg Vorbis with .sli (start,length) for looping"},
|
{meta_OGG_SLI, "Ogg Vorbis with .sli (start,length) for looping"},
|
||||||
{meta_OGG_SLI2, "Ogg Vorbis with .sli (from,to) for looping"},
|
{meta_OGG_SLI2, "Ogg Vorbis with .sli (from,to) for looping"},
|
||||||
{meta_OGG_SFL, "Ogg Vorbis with SFPL for looping"},
|
{meta_OGG_SFL, "Ogg Vorbis with SFPL for looping"},
|
||||||
{meta_OGG_UM3, "Ogg Vorbis, Ultramarine3 'encryption'"},
|
{meta_OGG_UM3, "Ogg Vorbis (Ultramarine3)"},
|
||||||
{meta_OGG_KOVS, "Ogg Vorbis, KOVS header"},
|
{meta_OGG_KOVS, "Ogg Vorbis (KOVS header)"},
|
||||||
{meta_OGG_PSYCH, "Ogg Vorbis, Psychic Software obfuscation"},
|
{meta_OGG_PSYCHIC, "Ogg Vorbis (Psychic Software)"},
|
||||||
#endif
|
{meta_OGG_SNGW, "Ogg Vorbis (Capcom)"},
|
||||||
|
{meta_OGG_ISD, "Ogg Vorbis (ISD)"},
|
||||||
|
{meta_KMA9, "Koei Tecmo KMA9 header"},
|
||||||
|
{meta_XWC, "Starbreeze XWC header"},
|
||||||
|
{meta_SQEX_SAB, "Square-Enix SAB header"},
|
||||||
|
{meta_SQEX_MAB, "Square-Enix MAB header"},
|
||||||
|
|
||||||
#ifdef VGM_USE_MP4V2
|
#ifdef VGM_USE_MP4V2
|
||||||
{meta_MP4, "AAC header"},
|
{meta_MP4, "AAC header"},
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -164,6 +164,9 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
||||||
case layout_blocked_vawx:
|
case layout_blocked_vawx:
|
||||||
block_update_vawx(vgmstream->next_block_offset,vgmstream);
|
block_update_vawx(vgmstream->next_block_offset,vgmstream);
|
||||||
break;
|
break;
|
||||||
|
case layout_blocked_xvag_subsong:
|
||||||
|
block_update_xvag_subsong(vgmstream->next_block_offset,vgmstream);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,7 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||||
|
|
||||||
/* id, size, samples, hists-per-channel, stereo/interleaved data */
|
/* id, size, samples, hists-per-channel, stereo/interleaved data */
|
||||||
case coding_EA_XA:
|
case coding_EA_XA:
|
||||||
|
//case coding_EA_XA_V2: /* handled in default */
|
||||||
case coding_EA_XA_int:
|
case coding_EA_XA_int:
|
||||||
for (i = 0; i < vgmstream->channels; i++) {
|
for (i = 0; i < vgmstream->channels; i++) {
|
||||||
int is_interleaved = vgmstream->coding_type == coding_EA_XA_int;
|
int is_interleaved = vgmstream->coding_type == coding_EA_XA_int;
|
||||||
|
@ -106,7 +107,9 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||||
|
|
||||||
/* the block can have padding so find the channel size from num_samples */
|
/* the block can have padding so find the channel size from num_samples */
|
||||||
interleave = is_interleaved ? (block_samples / 28 * 0x0f) : 0;
|
interleave = is_interleaved ? (block_samples / 28 * 0x0f) : 0;
|
||||||
vgmstream->ch[i].offset = block_offset + 0x0c + vgmstream->channels*0x04 + i*interleave;
|
|
||||||
|
/* NOT channels*0x04, as seen in Superbike 2000 (PC) EA-XA v1 mono vids */
|
||||||
|
vgmstream->ch[i].offset = block_offset + 0x0c + 2*0x04 + i*interleave;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -146,6 +149,7 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||||
for (i = 0; i < vgmstream->channels; i++) {
|
for (i = 0; i < vgmstream->channels; i++) {
|
||||||
off_t channel_start = read_32bit(block_offset + 0x0C + (0x04*i),streamFile);
|
off_t channel_start = read_32bit(block_offset + 0x0C + (0x04*i),streamFile);
|
||||||
vgmstream->ch[i].offset = block_offset + 0x0C + (0x04*vgmstream->channels) + channel_start;
|
vgmstream->ch[i].offset = block_offset + 0x0C + (0x04*vgmstream->channels) + channel_start;
|
||||||
|
VGM_LOG("ch=%x, off=%lx\n", i, vgmstream->ch[i].offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read ADPCM history before each channel if needed (not actually read in sx.exe) */
|
/* read ADPCM history before each channel if needed (not actually read in sx.exe) */
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
#include "layout.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
#include "../vgmstream.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* XVAG with subsongs layers, interleaves chunks of each subsong (a hack to support them) */
|
||||||
|
void block_update_xvag_subsong(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||||
|
int i;
|
||||||
|
size_t channel_size = 0x10;
|
||||||
|
|
||||||
|
/* set offsets */
|
||||||
|
for (i = 0; i < vgmstream->channels; i++) {
|
||||||
|
vgmstream->ch[i].offset = block_offset + channel_size*i;
|
||||||
|
}
|
||||||
|
|
||||||
|
//vgmstream->current_block_size = ; /* fixed */
|
||||||
|
vgmstream->current_block_offset = block_offset;
|
||||||
|
vgmstream->next_block_offset = block_offset + vgmstream->full_block_size;
|
||||||
|
}
|
|
@ -66,6 +66,7 @@ void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream);
|
void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
void block_update_vgs(off_t block_offset, VGMSTREAM * vgmstream);
|
void block_update_vgs(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
void block_update_vawx(off_t block_offset, VGMSTREAM * vgmstream);
|
void block_update_vawx(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
|
void block_update_xvag_subsong(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
|
|
||||||
/* other layouts */
|
/* other layouts */
|
||||||
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||||
|
|
|
@ -72,10 +72,6 @@ static STREAMFILE *open_aax_with_STREAMFILE(STREAMFILE *file,off_t start_offset,
|
||||||
streamfile->sf.get_realname = (void*)get_name_aax;
|
streamfile->sf.get_realname = (void*)get_name_aax;
|
||||||
streamfile->sf.open = (void*)open_aax_impl;
|
streamfile->sf.open = (void*)open_aax_impl;
|
||||||
streamfile->sf.close = (void*)close_aax;
|
streamfile->sf.close = (void*)close_aax;
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
streamfile->sf.get_bytes_read = NULL;
|
|
||||||
streamfile->sf.get_error_count = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
streamfile->real_file = file;
|
streamfile->real_file = file;
|
||||||
streamfile->start_physical_offset = start_offset;
|
streamfile->start_physical_offset = start_offset;
|
||||||
|
|
|
@ -249,7 +249,7 @@ static int find_key(STREAMFILE *file, uint8_t type, uint16_t *xor_start, uint16_
|
||||||
{
|
{
|
||||||
uint8_t keybuf[6];
|
uint8_t keybuf[6];
|
||||||
|
|
||||||
if ( read_key_file(keybuf, 6, file) ) {
|
if (read_key_file(keybuf, 6, file) == 6) {
|
||||||
*xor_start = get_16bitBE(keybuf+0);
|
*xor_start = get_16bitBE(keybuf+0);
|
||||||
*xor_mult = get_16bitBE(keybuf+2);
|
*xor_mult = get_16bitBE(keybuf+2);
|
||||||
*xor_add = get_16bitBE(keybuf+4);
|
*xor_add = get_16bitBE(keybuf+4);
|
||||||
|
|
|
@ -176,6 +176,9 @@ static const adxkey_info adxkey8_list[] = {
|
||||||
/* Storm Lover Natsu Koi!! (2011-08-04)(Vridge)(D3 Publisher)[PSP] */
|
/* Storm Lover Natsu Koi!! (2011-08-04)(Vridge)(D3 Publisher)[PSP] */
|
||||||
{0x4133,0x5a01,0x5723, NULL,0}, // ?
|
{0x4133,0x5a01,0x5723, NULL,0}, // ?
|
||||||
|
|
||||||
|
/* Shounen Onmyouji: Tsubasa yo Ima, Sora e Kaere [PS2] */
|
||||||
|
{0x55d9,0x46d3,0x5b01, "SONMYOJI",0},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const adxkey_info adxkey9_list[] = {
|
static const adxkey_info adxkey9_list[] = {
|
||||||
|
|
|
@ -56,7 +56,7 @@ VGMSTREAM * init_vgmstream_ahx(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
if (cfg.encryption) {
|
if (cfg.encryption) {
|
||||||
uint8_t keybuf[6];
|
uint8_t keybuf[6];
|
||||||
if (read_key_file(keybuf, 6, streamFile)) {
|
if (read_key_file(keybuf, 6, streamFile) == 6) {
|
||||||
cfg.cri_key1 = get_16bitBE(keybuf+0);
|
cfg.cri_key1 = get_16bitBE(keybuf+0);
|
||||||
cfg.cri_key2 = get_16bitBE(keybuf+2);
|
cfg.cri_key2 = get_16bitBE(keybuf+2);
|
||||||
cfg.cri_key3 = get_16bitBE(keybuf+4);
|
cfg.cri_key3 = get_16bitBE(keybuf+4);
|
||||||
|
|
|
@ -151,10 +151,6 @@ static STREAMFILE *open_aix_impl(AIXSTREAMFILE *streamfile,const char * const fi
|
||||||
streamfile->sf.get_realname = (void*)get_name_aix;
|
streamfile->sf.get_realname = (void*)get_name_aix;
|
||||||
streamfile->sf.open = (void*)open_aix_impl;
|
streamfile->sf.open = (void*)open_aix_impl;
|
||||||
streamfile->sf.close = (void*)close_aix;
|
streamfile->sf.close = (void*)close_aix;
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
streamfile->sf.get_bytes_read = NULL;
|
|
||||||
streamfile->sf.get_error_count = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
streamfile->real_file = file;
|
streamfile->real_file = file;
|
||||||
streamfile->current_physical_offset = start_offset;
|
streamfile->current_physical_offset = start_offset;
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
#include "meta.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
|
static STREAMFILE* setup_atsl3_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size);
|
||||||
|
|
||||||
|
/* .ATSL3 - Koei Tecmo container of multiple .AT3 [One Piece Pirate Warriors (PS3)] */
|
||||||
|
VGMSTREAM * init_vgmstream_atsl3(STREAMFILE *streamFile) {
|
||||||
|
VGMSTREAM *vgmstream = NULL;
|
||||||
|
STREAMFILE *temp_streamFile = NULL;
|
||||||
|
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||||
|
off_t subfile_offset;
|
||||||
|
size_t subfile_size, header_size, entry_size;
|
||||||
|
|
||||||
|
/* check extensions */
|
||||||
|
if ( !check_extensions(streamFile,"atsl3"))
|
||||||
|
goto fail;
|
||||||
|
if (read_32bitBE(0x00,streamFile) != 0x4154534C) /* "ATSL" */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* main header (LE) */
|
||||||
|
header_size = read_32bitLE(0x04,streamFile);
|
||||||
|
/* 0x08/0c: flags?, 0x10: some size? */
|
||||||
|
total_subsongs = read_32bitLE(0x14,streamFile);
|
||||||
|
entry_size = read_32bitLE(0x18,streamFile);
|
||||||
|
/* 0x1c: null, 0x20: subheader size, 0x24/28: null */
|
||||||
|
|
||||||
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
|
if (target_subsong > total_subsongs || total_subsongs <= 0) goto fail;
|
||||||
|
|
||||||
|
/* entry header (BE) */
|
||||||
|
/* 0x00: id */
|
||||||
|
subfile_offset = read_32bitBE(header_size + (target_subsong-1)*entry_size + 0x04,streamFile);
|
||||||
|
subfile_size = read_32bitBE(header_size + (target_subsong-1)*entry_size + 0x08,streamFile);
|
||||||
|
/* 0x08+: sample rate/num_samples/loop_start/etc, matching subfile header */
|
||||||
|
/* some kind of seek/switch table follows */
|
||||||
|
|
||||||
|
temp_streamFile = setup_atsl3_streamfile(streamFile, subfile_offset,subfile_size);
|
||||||
|
if (!temp_streamFile) goto fail;
|
||||||
|
|
||||||
|
/* init the VGMSTREAM */
|
||||||
|
vgmstream = init_vgmstream_riff(temp_streamFile);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
vgmstream->num_streams = total_subsongs;
|
||||||
|
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static STREAMFILE* setup_atsl3_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size) {
|
||||||
|
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||||
|
|
||||||
|
/* setup subfile */
|
||||||
|
new_streamFile = open_wrap_streamfile(streamFile);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"at3");
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
return temp_streamFile;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
#include "meta.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
|
#define ATX_MAX_SEGMENTS 2
|
||||||
|
|
||||||
|
static STREAMFILE* setup_atx_streamfile(STREAMFILE *streamFile);
|
||||||
|
|
||||||
|
/* .ATX - Media.Vision's segmented RIFF AT3 wrapper [Senjo no Valkyria 3 (PSP), Shining Blade (PSP)] */
|
||||||
|
VGMSTREAM * init_vgmstream_atx(STREAMFILE *streamFile) {
|
||||||
|
VGMSTREAM *vgmstream = NULL;
|
||||||
|
STREAMFILE *temp_streamFile = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/* check extensions */
|
||||||
|
if ( !check_extensions(streamFile,"atx"))
|
||||||
|
goto fail;
|
||||||
|
if (read_32bitBE(0x00,streamFile) != 0x41504133) /* "APA3" */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* .ATX is made of subfile segments, handled by the streamFile.
|
||||||
|
* Each segment has a header/footer, and part of the whole data
|
||||||
|
* (i.e. ATRAC3 data ends in a subfile and continues in the next) */
|
||||||
|
temp_streamFile = setup_atx_streamfile(streamFile);
|
||||||
|
if (!temp_streamFile) goto fail;
|
||||||
|
|
||||||
|
vgmstream = init_vgmstream_riff(temp_streamFile);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static STREAMFILE* setup_atx_streamfile(STREAMFILE *streamFile) {
|
||||||
|
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||||
|
STREAMFILE *segment_streamFiles[ATX_MAX_SEGMENTS] = {0};
|
||||||
|
char filename[PATH_LIMIT];
|
||||||
|
size_t filename_len;
|
||||||
|
int i, num_segments = 0;
|
||||||
|
size_t riff_size;
|
||||||
|
VGM_LOG("1\n");
|
||||||
|
|
||||||
|
if (read_16bitLE(0x1c,streamFile) != 0) goto fail; /* this must be first segment */
|
||||||
|
if (read_16bitLE(0x1e,streamFile) < 1 || read_16bitLE(0x1e,streamFile) > ATX_MAX_SEGMENTS) goto fail;
|
||||||
|
num_segments = read_16bitLE(0x1e,streamFile);
|
||||||
|
|
||||||
|
/* expected segment name: X_XXX_XXX_0n.ATX, starting from n=1 */
|
||||||
|
get_streamfile_name(streamFile, filename,PATH_LIMIT);
|
||||||
|
filename_len = strlen(filename);
|
||||||
|
if (filename_len < 7 || filename[filename_len - 5] != '1') goto fail;
|
||||||
|
|
||||||
|
/* setup segments (could avoid reopening first segment but meh) */
|
||||||
|
for (i = 0; i < num_segments; i++) {
|
||||||
|
off_t subfile_offset;
|
||||||
|
size_t subfile_size;
|
||||||
|
VGM_LOG("loop\n");
|
||||||
|
filename[filename_len - 5] = ('0'+i+1); /* ghetto digit conversion */
|
||||||
|
new_streamFile = open_stream_name(streamFile, filename);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
segment_streamFiles[i] = new_streamFile;
|
||||||
|
|
||||||
|
if (read_32bitBE(0x00,segment_streamFiles[i]) != 0x41504133) /* "APA3" */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* parse block/segment header (other Media.Vision's files use it too) */
|
||||||
|
subfile_offset = read_32bitLE(0x08,segment_streamFiles[i]); /* header size */
|
||||||
|
subfile_size = read_32bitLE(0x14,segment_streamFiles[i]); /* can be 0 in other containers */
|
||||||
|
VGM_LOG("subfile: %lx, %x\n", subfile_offset, subfile_size);
|
||||||
|
if (read_16bitLE(0x1c,segment_streamFiles[i]) != i)
|
||||||
|
goto fail; /* segment sequence */
|
||||||
|
/* 0x04: block size (should match subfile_size in .ATX) */
|
||||||
|
/* 0x0c: flags? also in other files, 0x10/18: null, 0x1e: segments */
|
||||||
|
|
||||||
|
/* clamp to ignore header/footer during next reads */
|
||||||
|
new_streamFile = open_clamp_streamfile(segment_streamFiles[i], subfile_offset,subfile_size);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
segment_streamFiles[i] = new_streamFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup with all segments and clamp further using riff_size (last segment has padding) */
|
||||||
|
riff_size = read_32bitLE(read_32bitLE(0x08,streamFile) + 0x04,streamFile) + 0x08;
|
||||||
|
|
||||||
|
new_streamFile = open_multifile_streamfile(segment_streamFiles, num_segments);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_clamp_streamfile(temp_streamFile, 0,riff_size);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL, "at3");
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
return temp_streamFile;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (!temp_streamFile) {
|
||||||
|
for (i = 0; i < num_segments; i++)
|
||||||
|
close_streamfile(segment_streamFiles[i]);
|
||||||
|
} else {
|
||||||
|
close_streamfile(temp_streamFile); /* closes all segments */
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ typedef struct {
|
||||||
int is_encrypted;
|
int is_encrypted;
|
||||||
int is_music;
|
int is_music;
|
||||||
|
|
||||||
int total_streams;
|
int total_subsongs;
|
||||||
|
|
||||||
int channel_count;
|
int channel_count;
|
||||||
int sample_rate;
|
int sample_rate;
|
||||||
|
@ -47,7 +47,8 @@ VGMSTREAM * init_vgmstream_awc(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
vgmstream->sample_rate = awc.sample_rate;
|
vgmstream->sample_rate = awc.sample_rate;
|
||||||
vgmstream->num_samples = awc.num_samples;
|
vgmstream->num_samples = awc.num_samples;
|
||||||
vgmstream->num_streams = awc.total_streams;
|
vgmstream->num_streams = awc.total_subsongs;
|
||||||
|
vgmstream->stream_size = awc.stream_size;
|
||||||
vgmstream->meta_type = meta_AWC;
|
vgmstream->meta_type = meta_AWC;
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,7 +114,7 @@ static int parse_awc_header(STREAMFILE* streamFile, awc_header* awc) {
|
||||||
int i, ch, entries;
|
int i, ch, entries;
|
||||||
uint32_t flags, info_header, tag_count = 0, tags_skip = 0;
|
uint32_t flags, info_header, tag_count = 0, tags_skip = 0;
|
||||||
off_t off;
|
off_t off;
|
||||||
int target_stream = streamFile->stream_index;
|
int target_subsong = streamFile->stream_index;
|
||||||
|
|
||||||
memset(awc,0,sizeof(awc_header));
|
memset(awc,0,sizeof(awc_header));
|
||||||
|
|
||||||
|
@ -161,13 +162,13 @@ static int parse_awc_header(STREAMFILE* streamFile, awc_header* awc) {
|
||||||
* Music seems layered (N-1/2 stereo pairs), maybe set with events? */
|
* Music seems layered (N-1/2 stereo pairs), maybe set with events? */
|
||||||
awc->is_music = (read_32bit(off + 0x00,streamFile) & 0x1FFFFFFF) == 0x00000000;
|
awc->is_music = (read_32bit(off + 0x00,streamFile) & 0x1FFFFFFF) == 0x00000000;
|
||||||
if (awc->is_music) { /* all streams except id 0 is a channel */
|
if (awc->is_music) { /* all streams except id 0 is a channel */
|
||||||
awc->total_streams = 1;
|
awc->total_subsongs = 1;
|
||||||
target_stream = 1; /* we only need id 0, though channels may have its own tags/chunks */
|
target_subsong = 1; /* we only need id 0, though channels may have its own tags/chunks */
|
||||||
}
|
}
|
||||||
else { /* each stream is a single sound */
|
else { /* each stream is a single sound */
|
||||||
awc->total_streams = entries;
|
awc->total_subsongs = entries;
|
||||||
if (target_stream == 0) target_stream = 1;
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
if (target_stream < 0 || target_stream > awc->total_streams || awc->total_streams < 1) goto fail;
|
if (target_subsong < 0 || target_subsong > awc->total_subsongs || awc->total_subsongs < 1) goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -176,7 +177,7 @@ static int parse_awc_header(STREAMFILE* streamFile, awc_header* awc) {
|
||||||
info_header = read_32bit(off + 0x04*i, streamFile);
|
info_header = read_32bit(off + 0x04*i, streamFile);
|
||||||
tag_count = (info_header >> 29) & 0x7; /* 3b */
|
tag_count = (info_header >> 29) & 0x7; /* 3b */
|
||||||
//id = (info_header >> 0) & 0x1FFFFFFF; /* 29b */
|
//id = (info_header >> 0) & 0x1FFFFFFF; /* 29b */
|
||||||
if (target_stream-1 == i)
|
if (target_subsong-1 == i)
|
||||||
break;
|
break;
|
||||||
tags_skip += tag_count; /* tags to skip to reach target's tags, in the next header */
|
tags_skip += tag_count; /* tags to skip to reach target's tags, in the next header */
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,15 +62,6 @@ static void close_bar(BARSTREAMFILE *streamFile) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
size_t get_bytes_read_bar(BARSTREAMFILE *streamFile) {
|
|
||||||
return streamFile->real_file->get_bytes_read(streamFile->real_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
int (*get_error_count)(BARSTREAMFILE *streamFile) {
|
|
||||||
return streamFile->real_file->get_error_count(streamFile->real_file);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*static*/ STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file) {
|
/*static*/ STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file) {
|
||||||
BARSTREAMFILE *streamfile = malloc(sizeof(BARSTREAMFILE));
|
BARSTREAMFILE *streamfile = malloc(sizeof(BARSTREAMFILE));
|
||||||
|
@ -87,10 +78,6 @@ int (*get_error_count)(BARSTREAMFILE *streamFile) {
|
||||||
streamfile->sf.get_realname = (void*)get_realname_bar;
|
streamfile->sf.get_realname = (void*)get_realname_bar;
|
||||||
streamfile->sf.open = (void*)open_bar;
|
streamfile->sf.open = (void*)open_bar;
|
||||||
streamfile->sf.close = (void*)close_bar;
|
streamfile->sf.close = (void*)close_bar;
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
streamfile->sf.get_bytes_read = get_bytes_read_bar;
|
|
||||||
streamfile->sf.get_error_count = get_error_count_bar;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
streamfile->real_file = file;
|
streamfile->real_file = file;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
|
|
||||||
|
static STREAMFILE* setup_bgw_atrac3_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, size_t frame_size, int channels);
|
||||||
|
|
||||||
|
|
||||||
/* BGW - from Final Fantasy XI (PC) music files */
|
/* BGW - from Final Fantasy XI (PC) music files */
|
||||||
VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
|
STREAMFILE *temp_streamFile = NULL;
|
||||||
uint32_t codec, file_size, block_size, sample_rate, block_align;
|
uint32_t codec, file_size, block_size, sample_rate, block_align;
|
||||||
int32_t loop_start;
|
int32_t loop_start;
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
|
@ -32,18 +37,15 @@ VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) {
|
||||||
channel_count = read_8bit(0x2e,streamFile);
|
channel_count = read_8bit(0x2e,streamFile);
|
||||||
block_align = read_8bit(0x2f,streamFile);
|
block_align = read_8bit(0x2f,streamFile);
|
||||||
|
|
||||||
|
|
||||||
/* check file size with header value */
|
|
||||||
if (file_size != get_streamfile_size(streamFile))
|
if (file_size != get_streamfile_size(streamFile))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
loop_flag = (loop_start > 0);
|
loop_flag = (loop_start > 0);
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
/* fill in the vital statistics */
|
|
||||||
vgmstream->meta_type = meta_FFXI_BGW;
|
vgmstream->meta_type = meta_FFXI_BGW;
|
||||||
vgmstream->sample_rate = sample_rate;
|
vgmstream->sample_rate = sample_rate;
|
||||||
|
|
||||||
|
@ -65,7 +67,7 @@ VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) {
|
||||||
case 3: { /* ATRAC3 (encrypted) */
|
case 3: { /* ATRAC3 (encrypted) */
|
||||||
uint8_t buf[0x100];
|
uint8_t buf[0x100];
|
||||||
int bytes, joint_stereo, skip_samples;
|
int bytes, joint_stereo, skip_samples;
|
||||||
ffmpeg_custom_config cfg;
|
size_t data_size = file_size - start_offset;
|
||||||
|
|
||||||
vgmstream->num_samples = block_size; /* atrac3_bytes_to_samples gives the same value */
|
vgmstream->num_samples = block_size; /* atrac3_bytes_to_samples gives the same value */
|
||||||
if (loop_flag) {
|
if (loop_flag) {
|
||||||
|
@ -77,18 +79,18 @@ VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) {
|
||||||
joint_stereo = 0;
|
joint_stereo = 0;
|
||||||
skip_samples = 0;
|
skip_samples = 0;
|
||||||
|
|
||||||
bytes = ffmpeg_make_riff_atrac3(buf, 0x100, vgmstream->num_samples, file_size - start_offset, vgmstream->channels, vgmstream->sample_rate, block_align, joint_stereo, skip_samples);
|
bytes = ffmpeg_make_riff_atrac3(buf, 0x100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_align, joint_stereo, skip_samples);
|
||||||
if (bytes <= 0) goto fail;
|
if (bytes <= 0) goto fail;
|
||||||
|
|
||||||
memset(&cfg, 0, sizeof(ffmpeg_custom_config));
|
temp_streamFile = setup_bgw_atrac3_streamfile(streamFile, start_offset,data_size, 0xC0,channel_count);
|
||||||
cfg.type = FFMPEG_BGW_ATRAC3;
|
if (!temp_streamFile) goto fail;
|
||||||
cfg.channels = vgmstream->channels;
|
|
||||||
|
|
||||||
vgmstream->codec_data = init_ffmpeg_config(streamFile, buf,bytes, start_offset,file_size - start_offset, &cfg);
|
vgmstream->codec_data = init_ffmpeg_header_offset(temp_streamFile, buf,bytes, 0,data_size);
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
|
|
||||||
vgmstream->coding_type = coding_FFmpeg;
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -98,17 +100,17 @@ VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* open the file for reading */
|
|
||||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* SPW (SEWave) - from PlayOnline viewer for Final Fantasy XI (PC) */
|
/* SPW (SEWave) - from PlayOnline viewer for Final Fantasy XI (PC) */
|
||||||
VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
|
@ -118,8 +120,8 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
int channel_count, loop_flag = 0;
|
int channel_count, loop_flag = 0;
|
||||||
|
|
||||||
/* check extensions */
|
/* check extensions */
|
||||||
if ( !check_extensions(streamFile, "spw") )
|
if ( !check_extensions(streamFile, "spw") )
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* check header */
|
/* check header */
|
||||||
|
@ -127,10 +129,6 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
|
||||||
read_32bitBE(4,streamFile) != 0x76650000) /* "ve\0\0" */
|
read_32bitBE(4,streamFile) != 0x76650000) /* "ve\0\0" */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* check file size with header value */
|
|
||||||
if (read_32bitLE(0x8,streamFile) != get_streamfile_size(streamFile))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
file_size = read_32bitLE(0x08,streamFile);
|
file_size = read_32bitLE(0x08,streamFile);
|
||||||
codec = read_32bitLE(0x0c,streamFile);
|
codec = read_32bitLE(0x0c,streamFile);
|
||||||
/*file_id = read_32bitLE(0x10,streamFile);*/
|
/*file_id = read_32bitLE(0x10,streamFile);*/
|
||||||
|
@ -144,17 +142,15 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
|
||||||
block_align = read_8bit(0x2b,streamFile);
|
block_align = read_8bit(0x2b,streamFile);
|
||||||
/*0x2c: unk (0x01 when PCM, 0x10 when VAG?) */
|
/*0x2c: unk (0x01 when PCM, 0x10 when VAG?) */
|
||||||
|
|
||||||
/* check file size with header value */
|
|
||||||
if (file_size != get_streamfile_size(streamFile))
|
if (file_size != get_streamfile_size(streamFile))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
loop_flag = (loop_start > 0);
|
loop_flag = (loop_start > 0);
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
/* fill in the vital statistics */
|
|
||||||
vgmstream->meta_type = meta_FFXI_SPW;
|
vgmstream->meta_type = meta_FFXI_SPW;
|
||||||
vgmstream->sample_rate = sample_rate;
|
vgmstream->sample_rate = sample_rate;
|
||||||
|
|
||||||
|
@ -171,7 +167,7 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: /* PCM */
|
case 1: /* PCM */
|
||||||
vgmstream->coding_type = coding_PCM16LE;
|
vgmstream->coding_type = coding_PCM16LE;
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
|
@ -182,8 +178,9 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
|
||||||
vgmstream->loop_start_sample = (loop_start-1);
|
vgmstream->loop_start_sample = (loop_start-1);
|
||||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -199,3 +196,61 @@ fail:
|
||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define BGW_KEY_MAX (0xC0*2)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t key[BGW_KEY_MAX];
|
||||||
|
size_t key_size;
|
||||||
|
} bgw_decryption_data;
|
||||||
|
|
||||||
|
/* Encrypted ATRAC3 info from Moogle Toolbox (https://sourceforge.net/projects/mogbox/) */
|
||||||
|
static size_t bgw_decryption_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, bgw_decryption_data* data) {
|
||||||
|
size_t bytes_read;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
bytes_read = streamfile->read(streamfile, dest, offset, length);
|
||||||
|
|
||||||
|
/* decrypt data (xor) */
|
||||||
|
for (i = 0; i < bytes_read; i++) {
|
||||||
|
dest[i] ^= data->key[(offset + i) % data->key_size];
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
static STREAMFILE* setup_bgw_atrac3_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, size_t frame_size, int channels) {
|
||||||
|
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||||
|
bgw_decryption_data io_data = {0};
|
||||||
|
size_t io_data_size = sizeof(bgw_decryption_data);
|
||||||
|
int ch;
|
||||||
|
|
||||||
|
/* setup decryption with key (first frame + modified channel header) */
|
||||||
|
if (frame_size*channels == 0 || frame_size*channels > BGW_KEY_MAX) goto fail;
|
||||||
|
|
||||||
|
io_data.key_size = read_streamfile(io_data.key, subfile_offset, frame_size*channels, streamFile);
|
||||||
|
for (ch = 0; ch < channels; ch++) {
|
||||||
|
uint32_t xor = get_32bitBE(io_data.key + frame_size*ch);
|
||||||
|
put_32bitBE(io_data.key + frame_size*ch, xor ^ 0xA0024E9F);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup subfile */
|
||||||
|
new_streamFile = open_wrap_streamfile(streamFile);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, bgw_decryption_read);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
return temp_streamFile;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
|
@ -2,13 +2,14 @@
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
|
|
||||||
static int bink_get_info(STREAMFILE *streamFile, int * out_total_streams, int * out_channel_count, int * out_sample_rate, int * out_num_samples);
|
static int bink_get_info(STREAMFILE *streamFile, int * out_total_streams, size_t *out_stream_size, int * out_channel_count, int * out_sample_rate, int * out_num_samples);
|
||||||
|
|
||||||
/* BINK 1/2 - RAD Game Tools movies (audio/video format) */
|
/* BINK 1/2 - RAD Game Tools movies (audio/video format) */
|
||||||
VGMSTREAM * init_vgmstream_bik(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_bik(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
int channel_count = 0, loop_flag = 0, sample_rate = 0, num_samples = 0, total_streams = 0;
|
int channel_count = 0, loop_flag = 0, sample_rate = 0, num_samples = 0;
|
||||||
int stream_index = streamFile->stream_index;
|
int total_subsongs = 0, stream_index = streamFile->stream_index;
|
||||||
|
size_t stream_size;
|
||||||
|
|
||||||
|
|
||||||
/* check extension, case insensitive (bika = manually demuxed audio) */
|
/* check extension, case insensitive (bika = manually demuxed audio) */
|
||||||
|
@ -19,7 +20,7 @@ VGMSTREAM * init_vgmstream_bik(STREAMFILE *streamFile) {
|
||||||
(read_32bitBE(0x00,streamFile) & 0xffffff00) != 0x4B423200 ) goto fail;
|
(read_32bitBE(0x00,streamFile) & 0xffffff00) != 0x4B423200 ) goto fail;
|
||||||
|
|
||||||
/* find target stream info and samples */
|
/* find target stream info and samples */
|
||||||
if (!bink_get_info(streamFile, &total_streams, &channel_count, &sample_rate, &num_samples))
|
if (!bink_get_info(streamFile, &total_subsongs, &stream_size, &channel_count, &sample_rate, &num_samples))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
|
@ -29,7 +30,8 @@ VGMSTREAM * init_vgmstream_bik(STREAMFILE *streamFile) {
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
vgmstream->sample_rate = sample_rate;
|
vgmstream->sample_rate = sample_rate;
|
||||||
vgmstream->num_samples = num_samples;
|
vgmstream->num_samples = num_samples;
|
||||||
vgmstream->num_streams = total_streams;
|
vgmstream->num_streams = total_subsongs;
|
||||||
|
vgmstream->stream_size = stream_size;
|
||||||
vgmstream->meta_type = meta_BINK;
|
vgmstream->meta_type = meta_BINK;
|
||||||
|
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
|
@ -58,12 +60,13 @@ fail:
|
||||||
* as they are not in the main header. The header for BINK1 and 2 is the same.
|
* as they are not in the main header. The header for BINK1 and 2 is the same.
|
||||||
* (a ~3 min movie needs ~6000-7000 frames = fseeks, should be fast enough)
|
* (a ~3 min movie needs ~6000-7000 frames = fseeks, should be fast enough)
|
||||||
*/
|
*/
|
||||||
static int bink_get_info(STREAMFILE *streamFile, int * out_total_streams, int * out_channel_count, int * out_sample_rate, int * out_num_samples) {
|
static int bink_get_info(STREAMFILE *streamFile, int * out_total_subsongs, size_t * out_stream_size, int * out_channel_count, int * out_sample_rate, int * out_num_samples) {
|
||||||
uint32_t *offsets = NULL;
|
uint32_t *offsets = NULL;
|
||||||
uint32_t num_frames, num_samples_b = 0;
|
uint32_t num_frames, num_samples_b = 0;
|
||||||
off_t cur_offset;
|
off_t cur_offset;
|
||||||
int i, j, sample_rate, channel_count;
|
int i, j, sample_rate, channel_count;
|
||||||
int total_streams, target_stream = streamFile->stream_index;
|
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||||
|
size_t stream_size = 0;
|
||||||
|
|
||||||
size_t filesize = get_streamfile_size(streamFile);
|
size_t filesize = get_streamfile_size(streamFile);
|
||||||
uint32_t signature = (read_32bitBE(0x00,streamFile) & 0xffffff00);
|
uint32_t signature = (read_32bitBE(0x00,streamFile) & 0xffffff00);
|
||||||
|
@ -76,20 +79,20 @@ static int bink_get_info(STREAMFILE *streamFile, int * out_total_streams, int *
|
||||||
if (num_frames == 0 || num_frames > 0x100000) goto fail; /* something must be off (avoids big allocs below) */
|
if (num_frames == 0 || num_frames > 0x100000) goto fail; /* something must be off (avoids big allocs below) */
|
||||||
|
|
||||||
/* multichannel/multilanguage audio is usually N streams of stereo/mono, no way to know channel layout */
|
/* multichannel/multilanguage audio is usually N streams of stereo/mono, no way to know channel layout */
|
||||||
total_streams = read_32bitLE(0x28,streamFile);
|
total_subsongs = read_32bitLE(0x28,streamFile);
|
||||||
if (target_stream == 0) target_stream = 1;
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
if (target_stream < 0 || target_stream > total_streams || total_streams < 1 || total_streams > 255) goto fail;
|
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1 || total_subsongs > 255) goto fail;
|
||||||
|
|
||||||
/* find stream info and position in offset table */
|
/* find stream info and position in offset table */
|
||||||
cur_offset = 0x2c;
|
cur_offset = 0x2c;
|
||||||
if ((signature == 0x42494B00 && (revision == 0x6b)) || /* k */
|
if ((signature == 0x42494B00 && (revision == 0x6b)) || /* k */
|
||||||
(signature == 0x4B423200 && (revision == 0x69 || revision == 0x6a || revision == 0x6b))) /* i,j,k */
|
(signature == 0x4B423200 && (revision == 0x69 || revision == 0x6a || revision == 0x6b))) /* i,j,k */
|
||||||
cur_offset += 0x04; /* unknown v2 header field */
|
cur_offset += 0x04; /* unknown v2 header field */
|
||||||
cur_offset += 0x04*total_streams; /* skip streams max packet bytes */
|
cur_offset += 0x04*total_subsongs; /* skip streams max packet bytes */
|
||||||
sample_rate = (uint16_t)read_16bitLE(cur_offset+0x04*(target_stream-1)+0x00,streamFile);
|
sample_rate = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x00,streamFile);
|
||||||
channel_count = (uint16_t)read_16bitLE(cur_offset+0x04*(target_stream-1)+0x02,streamFile) & 0x2000 ? 2 : 1; /* stereo flag */
|
channel_count = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x02,streamFile) & 0x2000 ? 2 : 1; /* stereo flag */
|
||||||
cur_offset += 0x04*total_streams; /* skip streams info */
|
cur_offset += 0x04*total_subsongs; /* skip streams info */
|
||||||
cur_offset += 0x04*total_streams; /* skip streams ids */
|
cur_offset += 0x04*total_subsongs; /* skip streams ids */
|
||||||
|
|
||||||
|
|
||||||
/* read frame offsets in a buffer, to avoid fseeking to the table back and forth */
|
/* read frame offsets in a buffer, to avoid fseeking to the table back and forth */
|
||||||
|
@ -111,10 +114,11 @@ static int bink_get_info(STREAMFILE *streamFile, int * out_total_streams, int *
|
||||||
cur_offset = offsets[i];
|
cur_offset = offsets[i];
|
||||||
|
|
||||||
/* read audio packet headers per stream */
|
/* read audio packet headers per stream */
|
||||||
for (j=0; j < total_streams; j++) {
|
for (j=0; j < total_subsongs; j++) {
|
||||||
uint32_t ap_size = read_32bitLE(cur_offset+0x00,streamFile); /* not counting this int */
|
uint32_t ap_size = read_32bitLE(cur_offset+0x00,streamFile); /* not counting this int */
|
||||||
|
|
||||||
if (j == target_stream-1) {
|
if (j == target_subsong-1) {
|
||||||
|
stream_size += 0x04 + ap_size;
|
||||||
if (ap_size > 0)
|
if (ap_size > 0)
|
||||||
num_samples_b += read_32bitLE(cur_offset+0x04,streamFile); /* decoded samples in bytes */
|
num_samples_b += read_32bitLE(cur_offset+0x04,streamFile); /* decoded samples in bytes */
|
||||||
break; /* next frame */
|
break; /* next frame */
|
||||||
|
@ -128,7 +132,8 @@ static int bink_get_info(STREAMFILE *streamFile, int * out_total_streams, int *
|
||||||
free(offsets);
|
free(offsets);
|
||||||
|
|
||||||
|
|
||||||
if (out_total_streams) *out_total_streams = total_streams;
|
if (out_total_subsongs) *out_total_subsongs = total_subsongs;
|
||||||
|
if (out_stream_size) *out_stream_size = stream_size;
|
||||||
if (out_sample_rate) *out_sample_rate = sample_rate;
|
if (out_sample_rate) *out_sample_rate = sample_rate;
|
||||||
if (out_channel_count) *out_channel_count = channel_count;
|
if (out_channel_count) *out_channel_count = channel_count;
|
||||||
//todo returns a few more samples (~48) than binkconv.exe?
|
//todo returns a few more samples (~48) than binkconv.exe?
|
||||||
|
|
|
@ -7,7 +7,8 @@ VGMSTREAM * init_vgmstream_flx(STREAMFILE *streamFile) {
|
||||||
off_t start_offset, stream_offset = 0;
|
off_t start_offset, stream_offset = 0;
|
||||||
size_t data_size;
|
size_t data_size;
|
||||||
int loop_flag, channel_count, codec;
|
int loop_flag, channel_count, codec;
|
||||||
int total_streams = 0, target_stream = streamFile->stream_index;
|
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) */
|
/* check extensions (.flx: name of archive, files inside don't have extensions) */
|
||||||
|
@ -24,23 +25,26 @@ VGMSTREAM * init_vgmstream_flx(STREAMFILE *streamFile) {
|
||||||
|| read_32bitLE(0x58,streamFile) != get_streamfile_size(streamFile))
|
|| read_32bitLE(0x58,streamFile) != get_streamfile_size(streamFile))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (target_stream == 0) target_stream = 1;
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
|
|
||||||
for (i = 0; i < entries; i++) {
|
for (i = 0; i < entries; i++) {
|
||||||
off_t entry_offset = read_32bitLE(offset + 0x00, streamFile);
|
off_t entry_offset = read_32bitLE(offset + 0x00, streamFile);
|
||||||
/* 0x04: stream size */
|
size_t entry_size = read_32bitLE(offset + 0x04, streamFile);
|
||||||
offset += 0x08;
|
offset += 0x08;
|
||||||
|
|
||||||
if (entry_offset != 0x00)
|
if (entry_offset != 0x00)
|
||||||
total_streams++; /* many entries are empty */
|
total_subsongs++; /* many entries are empty */
|
||||||
if (total_streams == target_stream && stream_offset == 0)
|
if (total_subsongs == target_subsong && stream_offset == 0) {
|
||||||
stream_offset = entry_offset; /* found but let's keep adding total_streams */
|
stream_offset = entry_offset; /* found but let's keep adding total_streams */
|
||||||
|
stream_size = entry_size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (target_stream < 0 || target_stream > total_streams || total_streams < 1) goto fail;
|
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||||
if (stream_offset == 0x00) goto fail;
|
if (stream_offset == 0x00) goto fail;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
stream_offset = 0x00;
|
stream_offset = 0x00;
|
||||||
|
stream_size = get_streamfile_size(streamFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_32bitLE(stream_offset + 0x30,streamFile) != 0x10)
|
if (read_32bitLE(stream_offset + 0x30,streamFile) != 0x10)
|
||||||
|
@ -57,7 +61,8 @@ VGMSTREAM * init_vgmstream_flx(STREAMFILE *streamFile) {
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
vgmstream->sample_rate = read_32bitLE(stream_offset + 0x2c,streamFile);
|
vgmstream->sample_rate = read_32bitLE(stream_offset + 0x2c,streamFile);
|
||||||
vgmstream->num_streams = total_streams;
|
vgmstream->num_streams = total_subsongs;
|
||||||
|
vgmstream->stream_size = stream_size;
|
||||||
vgmstream->meta_type = meta_PC_FLX;
|
vgmstream->meta_type = meta_PC_FLX;
|
||||||
|
|
||||||
switch(codec) {
|
switch(codec) {
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
#define FAKE_RIFF_BUFFER_SIZE 100
|
|
||||||
|
|
||||||
static VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset);
|
|
||||||
|
|
||||||
/* ************************************************************************************************************
|
/* ************************************************************************************************************
|
||||||
* FSB defines, copied from the public spec (https://www.fmod.org/questions/question/forum-4928/)
|
* FSB defines, copied from the public spec (https://www.fmod.org/questions/question/forum-4928/)
|
||||||
|
@ -65,9 +62,7 @@ static VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offse
|
||||||
#define FSOUND_CHANNELMODE_MASK (FSOUND_CHANNELMODE_ALLMONO | FSOUND_CHANNELMODE_ALLSTEREO | FSOUND_CHANNELMODE_PROTOOLS)
|
#define FSOUND_CHANNELMODE_MASK (FSOUND_CHANNELMODE_ALLMONO | FSOUND_CHANNELMODE_ALLSTEREO | FSOUND_CHANNELMODE_PROTOOLS)
|
||||||
#define FSOUND_CHANNELMODE_DEFAULT 0x00000000 /* Determine channel assignment automatically from channel count. */
|
#define FSOUND_CHANNELMODE_DEFAULT 0x00000000 /* Determine channel assignment automatically from channel count. */
|
||||||
#define FSOUND_CHANNELMODE_RESERVED 0x00000C00
|
#define FSOUND_CHANNELMODE_RESERVED 0x00000C00
|
||||||
|
|
||||||
#define FSOUND_NORMAL (FSOUND_16BITS | FSOUND_SIGNED | FSOUND_MONO)
|
#define FSOUND_NORMAL (FSOUND_16BITS | FSOUND_SIGNED | FSOUND_MONO)
|
||||||
|
|
||||||
#define FSB_SAMPLE_DATA_ALIGN 32
|
#define FSB_SAMPLE_DATA_ALIGN 32
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,23 +70,22 @@ static VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offse
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* main header */
|
/* main header */
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
int32_t numsamples; /* number of samples(streams) in the file */
|
int32_t total_subsongs;
|
||||||
uint32_t shdrsize; /* size in bytes of all of the sample headers including extended information */
|
uint32_t sample_header_size; /* all of the sample headers including extended information */
|
||||||
uint32_t datasize; /* size in bytes of compressed sample data */
|
uint32_t data_size;
|
||||||
/* main header: FSB 3/3.1/4 */
|
uint32_t version; /* extended fsb version (in FSB 3/3.1/4) */
|
||||||
uint32_t version; /* extended fsb version */
|
uint32_t flags; /* flags common to all streams (in FSB 3/3.1/4)*/
|
||||||
uint32_t flags; /* flags that apply to all samples(streams) in the fsb */
|
|
||||||
/* sample header */
|
/* sample header */
|
||||||
uint32_t lengthsamples;
|
uint32_t num_samples;
|
||||||
uint32_t lengthcompressedbytes;
|
uint32_t stream_size;
|
||||||
uint32_t loopstart;
|
uint32_t loop_start;
|
||||||
uint32_t loopend;
|
uint32_t loop_end;
|
||||||
uint32_t mode;
|
uint32_t mode;
|
||||||
int32_t deffreq;
|
int32_t sample_rate;
|
||||||
uint16_t numchannels;
|
uint16_t channels;
|
||||||
/* extra */
|
/* extra */
|
||||||
uint32_t hdrsize;
|
uint32_t base_header_size;
|
||||||
uint32_t shdrsize_min;
|
uint32_t sample_header_min;
|
||||||
|
|
||||||
meta_t meta_type;
|
meta_t meta_type;
|
||||||
off_t name_offset;
|
off_t name_offset;
|
||||||
|
@ -102,294 +96,328 @@ typedef struct {
|
||||||
|
|
||||||
/* FSB4 */
|
/* FSB4 */
|
||||||
VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
|
||||||
return init_vgmstream_fsb_offset(streamFile, 0x0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FSB4 with "\0WAV" Header, found in Deadly Creatures (Wii)
|
|
||||||
* 16 byte header which holds the filesize
|
|
||||||
* (unsure if this is from a proper rip) */
|
|
||||||
VGMSTREAM * init_vgmstream_fsb4_wav(STREAMFILE *streamFile) {
|
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x00574156) /* "\0WAV" */
|
|
||||||
return NULL;
|
|
||||||
return init_vgmstream_fsb_offset(streamFile, 0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) {
|
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
size_t custom_data_offset;
|
size_t custom_data_offset;
|
||||||
int loop_flag = 0;
|
int loop_flag = 0;
|
||||||
int target_stream = streamFile->stream_index;
|
int target_subsong = streamFile->stream_index;
|
||||||
|
fsb_header fsb = {0};
|
||||||
|
|
||||||
fsb_header fsbh;
|
|
||||||
|
|
||||||
/* check extensions (.bnk = Hard Corps Uprising PS3) */
|
/* check extensions (.bnk = Hard Corps Uprising PS3) */
|
||||||
if ( !check_extensions(streamFile, "fsb,wii,bnk") )
|
if ( !check_extensions(streamFile, "fsb,bnk") )
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* check header */
|
/* check header */
|
||||||
fsbh.id = read_32bitBE(offset+0x00,streamFile);
|
fsb.id = read_32bitBE(0x00,streamFile);
|
||||||
if (fsbh.id == 0x46534231) { /* "FSB1" (somewhat different from other fsbs) */
|
if (fsb.id == 0x46534231) { /* "FSB1" (somewhat different from other fsbs) */
|
||||||
fsbh.meta_type = meta_FSB1;
|
fsb.meta_type = meta_FSB1;
|
||||||
fsbh.hdrsize = 0x10;
|
fsb.base_header_size = 0x10;
|
||||||
fsbh.shdrsize_min = 0x40;
|
fsb.sample_header_min = 0x40;
|
||||||
|
|
||||||
/* main header */
|
/* main header */
|
||||||
fsbh.numsamples = read_32bitLE(offset+0x04,streamFile);
|
fsb.total_subsongs = read_32bitLE(0x04,streamFile);
|
||||||
fsbh.datasize = read_32bitLE(offset+0x08,streamFile);
|
fsb.data_size = read_32bitLE(0x08,streamFile);
|
||||||
fsbh.shdrsize = 0x40;
|
fsb.sample_header_size = 0x40;
|
||||||
fsbh.version = 0;
|
fsb.version = 0;
|
||||||
fsbh.flags = 0;
|
fsb.flags = 0;
|
||||||
|
|
||||||
if (fsbh.numsamples > 1) goto fail;
|
if (fsb.total_subsongs > 1) goto fail;
|
||||||
|
|
||||||
/* sample header (first stream only, not sure if there are multi-FSB1) */
|
/* sample header (first stream only, not sure if there are multi-FSB1) */
|
||||||
{
|
{
|
||||||
off_t s_off = offset+fsbh.hdrsize;
|
off_t s_off = fsb.base_header_size;
|
||||||
|
|
||||||
fsbh.name_offset = s_off;
|
fsb.name_offset = s_off;
|
||||||
fsbh.name_size = 0x20;
|
fsb.name_size = 0x20;
|
||||||
fsbh.lengthsamples = read_32bitLE(s_off+0x20,streamFile);
|
fsb.num_samples = read_32bitLE(s_off+0x20,streamFile);
|
||||||
fsbh.lengthcompressedbytes = read_32bitLE(s_off+0x24,streamFile);
|
fsb.stream_size = read_32bitLE(s_off+0x24,streamFile);
|
||||||
fsbh.deffreq = read_32bitLE(s_off+0x28,streamFile);
|
fsb.sample_rate = read_32bitLE(s_off+0x28,streamFile);
|
||||||
/* 0x2c:? 0x2e:? 0x30:? 0x32:? */
|
/* 0x2c:? 0x2e:? 0x30:? 0x32:? */
|
||||||
fsbh.mode = read_32bitLE(s_off+0x34,streamFile);
|
fsb.mode = read_32bitLE(s_off+0x34,streamFile);
|
||||||
fsbh.loopstart = read_32bitLE(s_off+0x38,streamFile);
|
fsb.loop_start = read_32bitLE(s_off+0x38,streamFile);
|
||||||
fsbh.loopend = read_32bitLE(s_off+0x3c,streamFile);
|
fsb.loop_end = read_32bitLE(s_off+0x3c,streamFile);
|
||||||
|
|
||||||
fsbh.numchannels = (fsbh.mode & FSOUND_STEREO) ? 2 : 1;
|
fsb.channels = (fsb.mode & FSOUND_STEREO) ? 2 : 1;
|
||||||
if (fsbh.loopend > fsbh.lengthsamples) /* this seems common... */
|
if (fsb.loop_end > fsb.num_samples) /* this seems common... */
|
||||||
fsbh.lengthsamples = fsbh.loopend;
|
fsb.num_samples = fsb.loop_end;
|
||||||
|
|
||||||
start_offset = offset + fsbh.hdrsize + fsbh.shdrsize;
|
start_offset = fsb.base_header_size + fsb.sample_header_size;
|
||||||
custom_data_offset = offset + fsbh.hdrsize + fsbh.shdrsize_min; /* DSP coefs, seek tables, etc */
|
custom_data_offset = fsb.base_header_size + fsb.sample_header_min; /* DSP coefs, seek tables, etc */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { /* other FSBs (common/extended format) */
|
else { /* other FSBs (common/extended format) */
|
||||||
if (fsbh.id == 0x46534232) { /* "FSB2" */
|
if (fsb.id == 0x46534232) { /* "FSB2" */
|
||||||
fsbh.meta_type = meta_FSB2;
|
fsb.meta_type = meta_FSB2;
|
||||||
fsbh.hdrsize = 0x10;
|
fsb.base_header_size = 0x10;
|
||||||
fsbh.shdrsize_min = 0x40; /* guessed */
|
fsb.sample_header_min = 0x40; /* guessed */
|
||||||
} else if (fsbh.id == 0x46534233) { /* "FSB3" */
|
} else if (fsb.id == 0x46534233) { /* "FSB3" */
|
||||||
fsbh.meta_type = meta_FSB3;
|
fsb.meta_type = meta_FSB3;
|
||||||
fsbh.hdrsize = 0x18;
|
fsb.base_header_size = 0x18;
|
||||||
fsbh.shdrsize_min = 0x40;
|
fsb.sample_header_min = 0x40;
|
||||||
} else if (fsbh.id == 0x46534234) { /* "FSB4" */
|
} else if (fsb.id == 0x46534234) { /* "FSB4" */
|
||||||
fsbh.meta_type = meta_FSB4;
|
fsb.meta_type = meta_FSB4;
|
||||||
fsbh.hdrsize = 0x30;
|
fsb.base_header_size = 0x30;
|
||||||
fsbh.shdrsize_min = 0x50;
|
fsb.sample_header_min = 0x50;
|
||||||
} else {
|
} else {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* main header */
|
/* main header */
|
||||||
fsbh.numsamples = read_32bitLE(offset+0x04,streamFile);
|
fsb.total_subsongs = read_32bitLE(0x04,streamFile);
|
||||||
fsbh.shdrsize = read_32bitLE(offset+0x08,streamFile);
|
fsb.sample_header_size = read_32bitLE(0x08,streamFile);
|
||||||
fsbh.datasize = read_32bitLE(offset+0x0c,streamFile);
|
fsb.data_size = read_32bitLE(0x0c,streamFile);
|
||||||
if (fsbh.hdrsize > 0x10) {
|
if (fsb.base_header_size > 0x10) {
|
||||||
fsbh.version = read_32bitLE(offset+0x10,streamFile);
|
fsb.version = read_32bitLE(0x10,streamFile);
|
||||||
fsbh.flags = read_32bitLE(offset+0x14,streamFile);
|
fsb.flags = read_32bitLE(0x14,streamFile);
|
||||||
/* FSB4: 0x18:hash 0x20:guid */
|
/* FSB4: 0x18:hash 0x20:guid */
|
||||||
} else {
|
} else {
|
||||||
fsbh.version = 0;
|
fsb.version = 0;
|
||||||
fsbh.flags = 0;
|
fsb.flags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fsbh.version == FMOD_FSB_VERSION_3_1) {
|
if (fsb.version == FMOD_FSB_VERSION_3_1) {
|
||||||
fsbh.shdrsize_min = 0x50;
|
fsb.sample_header_min = 0x50;
|
||||||
} else if (fsbh.version != 0 /* FSB2 */
|
} else if (fsb.version != 0 /* FSB2 */
|
||||||
&& fsbh.version != FMOD_FSB_VERSION_3_0
|
&& fsb.version != FMOD_FSB_VERSION_3_0
|
||||||
&& fsbh.version != FMOD_FSB_VERSION_4_0) {
|
&& fsb.version != FMOD_FSB_VERSION_4_0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fsbh.shdrsize < fsbh.shdrsize_min) goto fail;
|
if (fsb.sample_header_size < fsb.sample_header_min) goto fail;
|
||||||
if (target_stream == 0) target_stream = 1;
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
if (target_stream < 0 || target_stream > fsbh.numsamples || fsbh.numsamples < 1) goto fail;
|
if (target_subsong < 0 || target_subsong > fsb.total_subsongs || fsb.total_subsongs < 1) goto fail;
|
||||||
|
|
||||||
/* sample header (N-stream) */
|
/* sample header (N-stream) */
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
off_t s_off = offset + fsbh.hdrsize;
|
off_t s_off = fsb.base_header_size;
|
||||||
off_t d_off = offset + fsbh.hdrsize + fsbh.shdrsize;
|
off_t d_off = fsb.base_header_size + fsb.sample_header_size;
|
||||||
|
|
||||||
/* find target_stream header (variable sized) */
|
/* find target_stream header (variable sized) */
|
||||||
for(i = 0; i < fsbh.numsamples; i++) {
|
for (i = 0; i < fsb.total_subsongs; i++) {
|
||||||
size_t stream_header_size = (uint16_t)read_16bitLE(s_off+0x00,streamFile);
|
size_t stream_header_size = (uint16_t)read_16bitLE(s_off+0x00,streamFile);
|
||||||
fsbh.name_offset = s_off+0x02;
|
fsb.name_offset = s_off+0x02;
|
||||||
fsbh.name_size = 0x20-0x02;
|
fsb.name_size = 0x20-0x02;
|
||||||
fsbh.lengthsamples = read_32bitLE(s_off+0x20,streamFile);
|
fsb.num_samples = read_32bitLE(s_off+0x20,streamFile);
|
||||||
fsbh.lengthcompressedbytes = read_32bitLE(s_off+0x24,streamFile);
|
fsb.stream_size = read_32bitLE(s_off+0x24,streamFile);
|
||||||
fsbh.loopstart = read_32bitLE(s_off+0x28,streamFile);
|
fsb.loop_start = read_32bitLE(s_off+0x28,streamFile);
|
||||||
fsbh.loopend = read_32bitLE(s_off+0x2c,streamFile);
|
fsb.loop_end = read_32bitLE(s_off+0x2c,streamFile);
|
||||||
fsbh.mode = read_32bitLE(s_off+0x30,streamFile);
|
fsb.mode = read_32bitLE(s_off+0x30,streamFile);
|
||||||
fsbh.deffreq = read_32bitLE(s_off+0x34,streamFile);
|
fsb.sample_rate = read_32bitLE(s_off+0x34,streamFile);
|
||||||
/* 0x38:defvol 0x3a:defpan 0x3c:defpri */
|
/* 0x38:defvol 0x3a:defpan 0x3c:defpri */
|
||||||
fsbh.numchannels = read_16bitLE(s_off+0x3e,streamFile);
|
fsb.channels = read_16bitLE(s_off+0x3e,streamFile);
|
||||||
/* FSB3.1/4: 0x40:mindistance 0x44:maxdistance 0x48:varfreq/size_32bits 0x4c:varvol 0x4e:fsbh.varpan */
|
/* FSB3.1/4: 0x40:mindistance 0x44:maxdistance 0x48:varfreq/size_32bits 0x4c:varvol 0x4e:fsb.varpan */
|
||||||
/* FSB3/4: 0x50:extended_data size_32bits (not always given) */
|
/* FSB3/4: 0x50:extended_data size_32bits (not always given) */
|
||||||
|
|
||||||
if (i+1 == target_stream) /* d_off found */
|
if (i+1 == target_subsong) /* d_off found */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
s_off += stream_header_size;
|
s_off += stream_header_size;
|
||||||
d_off += fsbh.lengthcompressedbytes; /* there is no offset so manually count */
|
d_off += fsb.stream_size; /* there is no offset so manually count */
|
||||||
|
|
||||||
/* IMAs streams have weird end padding (maybe: FSB3=no padding, FSB4=always padding) */
|
/* IMAs streams have weird end padding (maybe: FSB3=no padding, FSB4=always padding) */
|
||||||
if ((fsbh.mode & FSOUND_IMAADPCM) && (fsbh.flags & FMOD_FSB_SOURCE_MPEG_PADDED4)) {
|
if ((fsb.mode & FSOUND_IMAADPCM) && (fsb.flags & FMOD_FSB_SOURCE_MPEG_PADDED4)) {
|
||||||
if (d_off % 0x20)
|
if (d_off % 0x20)
|
||||||
d_off += 0x20 - (d_off % 0x20);
|
d_off += 0x20 - (d_off % 0x20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i > fsbh.numsamples) goto fail; /* not found */
|
if (i > fsb.total_subsongs) goto fail; /* not found */
|
||||||
|
|
||||||
start_offset = d_off;
|
start_offset = d_off;
|
||||||
custom_data_offset = s_off + fsbh.shdrsize_min; /* DSP coefs, seek tables, etc */
|
custom_data_offset = s_off + fsb.sample_header_min; /* DSP coefs, seek tables, etc */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* XOR encryption for some FSB4, though the flag is only seen after decrypting */
|
/* XOR encryption for some FSB4, though the flag is only seen after decrypting */
|
||||||
//VGM_ASSERT(fsbh.flags & FMOD_FSB_SOURCE_ENCRYPTED, "FSB ENCRYPTED found\n");
|
//VGM_ASSERT(fsb.flags & FMOD_FSB_SOURCE_ENCRYPTED, "FSB ENCRYPTED found\n");
|
||||||
|
|
||||||
/* sometimes there is garbage at the end or missing bytes due to improper demuxing */
|
/* sometimes there is garbage at the end or missing bytes due to improper demuxing */
|
||||||
VGM_ASSERT(fsbh.hdrsize + fsbh.shdrsize + fsbh.datasize != streamFile->get_size(streamFile) - offset,
|
VGM_ASSERT(fsb.base_header_size + fsb.sample_header_size + fsb.data_size != streamFile->get_size(streamFile),
|
||||||
"FSB wrong head/datasize found (expected 0x%x vs 0x%lx)\n",
|
"FSB wrong head/data_size found (expected 0x%x vs 0x%x)\n",
|
||||||
fsbh.hdrsize + fsbh.shdrsize + fsbh.datasize, streamFile->get_size(streamFile) - offset);
|
fsb.base_header_size + fsb.sample_header_size + fsb.data_size, streamFile->get_size(streamFile));
|
||||||
|
|
||||||
/* Loops unless disabled. FMOD default seems full loops (0/num_samples-1) without flags, for repeating tracks
|
/* Loops unless disabled. FMOD default seems full loops (0/num_samples-1) without flags, for repeating tracks
|
||||||
* that should loop and jingles/sfx that shouldn't. We'll try to disable looping is it looks jingly enough. */
|
* that should loop and jingles/sfx that shouldn't. We'll try to disable looping if it looks jingly enough. */
|
||||||
loop_flag = !(fsbh.mode & FSOUND_LOOP_OFF);
|
loop_flag = !(fsb.mode & FSOUND_LOOP_OFF);
|
||||||
if(!(fsbh.mode & FSOUND_LOOP_NORMAL) /* rarely set */
|
if(!(fsb.mode & FSOUND_LOOP_NORMAL) /* rarely set */
|
||||||
&& fsbh.loopstart+fsbh.loopend+1 == fsbh.lengthsamples /* full loop */
|
&& fsb.loop_start+fsb.loop_end+1 == fsb.num_samples /* full loop */
|
||||||
&& fsbh.lengthsamples < 20*fsbh.deffreq) /* seconds, lame but no other way to know */
|
&& fsb.num_samples < 20*fsb.sample_rate) /* seconds, lame but no other way to know */
|
||||||
loop_flag = 0;
|
loop_flag = 0;
|
||||||
|
|
||||||
/* ping-pong looping = no looping? (forward > reverse > forward) */
|
/* ping-pong looping = no looping? (forward > reverse > forward) */
|
||||||
VGM_ASSERT(fsbh.mode & FSOUND_LOOP_BIDI, "FSB BIDI looping found\n");
|
VGM_ASSERT(fsb.mode & FSOUND_LOOP_BIDI, "FSB BIDI looping found\n");
|
||||||
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
vgmstream = allocate_vgmstream(fsbh.numchannels,loop_flag);
|
vgmstream = allocate_vgmstream(fsb.channels,loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
vgmstream->sample_rate = fsbh.deffreq;
|
vgmstream->sample_rate = fsb.sample_rate;
|
||||||
vgmstream->num_samples = fsbh.lengthsamples;
|
vgmstream->num_samples = fsb.num_samples;
|
||||||
vgmstream->loop_start_sample = fsbh.loopstart;
|
vgmstream->loop_start_sample = fsb.loop_start;
|
||||||
vgmstream->loop_end_sample = fsbh.loopend;
|
vgmstream->loop_end_sample = fsb.loop_end;
|
||||||
vgmstream->num_streams = fsbh.numsamples;
|
vgmstream->num_streams = fsb.total_subsongs;
|
||||||
vgmstream->meta_type = fsbh.meta_type;
|
vgmstream->stream_size = fsb.stream_size;
|
||||||
if (fsbh.name_offset)
|
vgmstream->meta_type = fsb.meta_type;
|
||||||
read_string(vgmstream->stream_name,fsbh.name_size+1, fsbh.name_offset,streamFile);
|
if (fsb.name_offset)
|
||||||
|
read_string(vgmstream->stream_name,fsb.name_size+1, fsb.name_offset,streamFile);
|
||||||
|
|
||||||
|
|
||||||
/* parse format */
|
/* parse codec */
|
||||||
if (fsbh.mode & FSOUND_MPEG) {
|
if (fsb.mode & FSOUND_MPEG) { /* FSB4: Shatter, Way of the Samurai 3/4 (PS3) */
|
||||||
/* FSB3: ?; FSB4: Shatter, Way of the Samurai 3/4, Forza Horizon 1/2, Dragon Age Origins */
|
|
||||||
#if defined(VGM_USE_MPEG)
|
#if defined(VGM_USE_MPEG)
|
||||||
mpeg_custom_config cfg = {0};
|
mpeg_custom_config cfg = {0};
|
||||||
|
|
||||||
cfg.fsb_padding = (vgmstream->channels > 2 ? 16 :
|
cfg.fsb_padding = (vgmstream->channels > 2 ? 16 :
|
||||||
(fsbh.flags & FMOD_FSB_SOURCE_MPEG_PADDED4 ? 4 :
|
(fsb.flags & FMOD_FSB_SOURCE_MPEG_PADDED4 ? 4 :
|
||||||
(fsbh.flags & FMOD_FSB_SOURCE_MPEG_PADDED ? 2 : 0)));
|
(fsb.flags & FMOD_FSB_SOURCE_MPEG_PADDED ? 2 : 0)));
|
||||||
|
|
||||||
//VGM_ASSERT(fsbh.mode & FSOUND_MPEG_LAYER2, "FSB FSOUND_MPEG_LAYER2 found\n");/* not always set anyway */
|
//VGM_ASSERT(fsb.mode & FSOUND_MPEG_LAYER2, "FSB FSOUND_MPEG_LAYER2 found\n");/* not always set anyway */
|
||||||
VGM_ASSERT(fsbh.mode & FSOUND_IGNORETAGS, "FSB FSOUND_IGNORETAGS found\n");
|
VGM_ASSERT(fsb.mode & FSOUND_IGNORETAGS, "FSB FSOUND_IGNORETAGS found\n");
|
||||||
|
|
||||||
vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
|
vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
goto fail; /* FFmpeg can't properly read FSB4 or FMOD's 0-padded MPEG data @ start_offset */
|
goto fail; /* FFmpeg can't properly read FSB4 or FMOD's 0-padded MPEG data @ start_offset */
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (fsbh.mode & FSOUND_IMAADPCM) { /* (codec 0x69, Voxware Byte Aligned) */
|
else if (fsb.mode & FSOUND_IMAADPCM) { /* FSB3: Bioshock (PC); FSB4: Blade Kitten (PC) */
|
||||||
/* FSOUND_IMAADPCMSTEREO is "noninterleaved, true stereo IMA", but doesn't seem to be any different
|
/* FSOUND_IMAADPCMSTEREO is "noninterleaved, true stereo IMA", but doesn't seem to be any different
|
||||||
* (found in FSB4: Shatter, Blade Kitten (PC), Hard Corps: Uprising (PS3)) */
|
* (found in FSB4: Shatter, Blade Kitten (PC), Hard Corps: Uprising (PS3)) */
|
||||||
|
|
||||||
/* FSB3: Bioshock (PC); FSB4: Blade Kitten (PC) */
|
|
||||||
vgmstream->coding_type = coding_XBOX;
|
vgmstream->coding_type = coding_XBOX;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
/* "interleaved header" IMA, which seems only used with >2ch (ex. Blade Kitten 5.1) */
|
/* "interleaved header" IMA, only used with >2ch (ex. Blade Kitten 6ch)
|
||||||
if (vgmstream->channels > 2)
|
* or (seemingly) when flag is used (ex. Dead to Rights 2 (Xbox) 2ch in FSB3.1 */
|
||||||
|
if (vgmstream->channels > 2 || (fsb.mode & FSOUND_MULTICHANNEL))
|
||||||
vgmstream->coding_type = coding_FSB_IMA;
|
vgmstream->coding_type = coding_FSB_IMA;
|
||||||
}
|
}
|
||||||
else if (fsbh.mode & FSOUND_VAG) {
|
else if (fsb.mode & FSOUND_VAG) { /* FSB1: Jurassic Park Operation Genesis (PS2), FSB4: Spider Man Web of Shadows (PSP) */
|
||||||
/* FSB1: Jurassic Park Operation Genesis
|
|
||||||
* FSB3: ?; FSB4: Spider Man Web of Shadows, Speed Racer, Silent Hill: Shattered Memories (PS2) */
|
|
||||||
vgmstream->coding_type = coding_PSX;
|
vgmstream->coding_type = coding_PSX;
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = 0x10;
|
vgmstream->interleave_block_size = 0x10;
|
||||||
}
|
}
|
||||||
else if (fsbh.mode & FSOUND_XMA) {
|
else if (fsb.mode & FSOUND_XMA) { /* FSB4: Armored Core V (X360), Hard Corps (X360) */
|
||||||
#if defined(VGM_USE_FFMPEG)
|
#if defined(VGM_USE_FFMPEG)
|
||||||
/* FSB4: Xbox360 Armored Core V, Hard Corps, Halo Anniversary */
|
uint8_t buf[0x100];
|
||||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
|
||||||
uint8_t buf[FAKE_RIFF_BUFFER_SIZE];
|
|
||||||
size_t bytes, block_size, block_count;
|
size_t bytes, block_size, block_count;
|
||||||
/* not accurate but not needed by FFmpeg */
|
|
||||||
block_size = 0x8000; /* FSB default */
|
block_size = 0x8000; /* FSB default */
|
||||||
block_count = fsbh.datasize / block_size; /* read_32bitLE(custom_data_offset +0x14) -1? */
|
block_count = fsb.stream_size / block_size; /* not accurate but not needed (custom_data_offset+0x14 -1?) */
|
||||||
|
|
||||||
/* make a fake riff so FFmpeg can parse the XMA2 */
|
bytes = ffmpeg_make_riff_xma2(buf, 0x100, fsb.num_samples, fsb.stream_size, fsb.channels, fsb.sample_rate, block_count, block_size);
|
||||||
bytes = ffmpeg_make_riff_xma2(buf, FAKE_RIFF_BUFFER_SIZE, fsbh.lengthsamples, fsbh.datasize, fsbh.numchannels, fsbh.deffreq, block_count, block_size);
|
if (bytes <= 0) goto fail;
|
||||||
if (bytes <= 0)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,fsbh.datasize);
|
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,fsb.stream_size);
|
||||||
if ( !ffmpeg_data ) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
vgmstream->codec_data = ffmpeg_data;
|
|
||||||
vgmstream->coding_type = coding_FFmpeg;
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
goto fail;
|
goto fail;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (fsbh.mode & FSOUND_GCADPCM) {
|
else if (fsb.mode & FSOUND_GCADPCM) {
|
||||||
/* FSB3: ?; FSB4: de Blob (Wii), Night at the Museum, M. Night Shyamalan Avatar: The Last Airbender */
|
/* FSB3: ?; FSB4: de Blob (Wii), Night at the Museum, M. Night Shyamalan Avatar: The Last Airbender */
|
||||||
vgmstream->coding_type = coding_NGC_DSP_subint;
|
vgmstream->coding_type = coding_NGC_DSP_subint;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
vgmstream->interleave_block_size = 0x2;
|
vgmstream->interleave_block_size = 0x2;
|
||||||
dsp_read_coefs_be(vgmstream, streamFile, custom_data_offset, 0x2e);
|
dsp_read_coefs_be(vgmstream, streamFile, custom_data_offset, 0x2e);
|
||||||
}
|
}
|
||||||
else if (fsbh.mode & FSOUND_CELT) { /* || fsbh.mode & FSOUND_OGG (same flag, unused) */
|
else if (fsb.mode & FSOUND_CELT) { /* FSB4: War Thunder (PC), The Witcher 2 (PC) */
|
||||||
/* FSB4: War Thunder (PC), The Witcher 2 (PC) */
|
|
||||||
VGM_LOG("FSB4 FSOUND_CELT found\n");
|
VGM_LOG("FSB4 FSOUND_CELT found\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
else { /* PCM */
|
else { /* PCM */
|
||||||
if (fsbh.mode & FSOUND_8BITS) {
|
if (fsb.mode & FSOUND_8BITS) {
|
||||||
vgmstream->coding_type = (fsbh.mode & FSOUND_UNSIGNED) ? coding_PCM8_U : coding_PCM8;
|
vgmstream->coding_type = (fsb.mode & FSOUND_UNSIGNED) ? coding_PCM8_U : coding_PCM8;
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = 0x1;
|
vgmstream->interleave_block_size = 0x1;
|
||||||
}
|
}
|
||||||
else { /* Rocket Knight (PC), Another Century's Episode R (PS3), Toy Story 3 (Wii) */
|
else { /* Rocket Knight (PC), Another Century's Episode R (PS3), Toy Story 3 (Wii) */
|
||||||
/* sometimes FSOUND_STEREO/FSOUND_MONO is not set (ex. Dead Space iOS),
|
/* sometimes FSOUND_STEREO/FSOUND_MONO is not set (ex. Dead Space iOS),
|
||||||
* or only STEREO/MONO but not FSOUND_8BITS/FSOUND_16BITS is set */
|
* or only STEREO/MONO but not FSOUND_8BITS/FSOUND_16BITS is set */
|
||||||
vgmstream->coding_type = (fsbh.flags & FMOD_FSB_SOURCE_BIGENDIANPCM) ? coding_PCM16BE : coding_PCM16LE;
|
vgmstream->coding_type = (fsb.flags & FMOD_FSB_SOURCE_BIGENDIANPCM) ? coding_PCM16BE : coding_PCM16LE;
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = 0x2;
|
vgmstream->interleave_block_size = 0x2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* full channel interleave, used in short streams (ex. de Blob Wii SFXs) */
|
/* full channel interleave, used in short streams (ex. de Blob Wii SFXs) */
|
||||||
if (fsbh.numchannels > 1 && (fsbh.flags & FMOD_FSB_SOURCE_NOTINTERLEAVED)) {
|
if (fsb.channels > 1 && (fsb.flags & FMOD_FSB_SOURCE_NOTINTERLEAVED)) {
|
||||||
if (vgmstream->coding_type == coding_NGC_DSP_subint)
|
if (vgmstream->coding_type == coding_NGC_DSP_subint)
|
||||||
vgmstream->coding_type = coding_NGC_DSP;
|
vgmstream->coding_type = coding_NGC_DSP;
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = fsbh.lengthcompressedbytes / fsbh.numchannels;
|
vgmstream->interleave_block_size = fsb.stream_size / fsb.channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* open the file for reading */
|
/* open the file for reading */
|
||||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static STREAMFILE* setup_fsb4_wav_streamfile(STREAMFILE *streamfile, off_t subfile_offset, size_t subfile_size);
|
||||||
|
|
||||||
|
/* FSB4 with "\0WAV" Header, found in Deadly Creatures (Wii).
|
||||||
|
* Has a 0x10 BE header that holds the filesize (unsure if this is from a proper rip). */
|
||||||
|
VGMSTREAM * init_vgmstream_fsb4_wav(STREAMFILE *streamFile) {
|
||||||
|
VGMSTREAM * vgmstream = NULL;
|
||||||
|
STREAMFILE *test_streamFile = NULL;
|
||||||
|
off_t subfile_start = 0x10;
|
||||||
|
size_t subfile_size = get_streamfile_size(streamFile) - 0x10 - 0x10; //todo
|
||||||
|
|
||||||
|
/* check extensions */
|
||||||
|
if ( !check_extensions(streamFile, "fsb,wii") )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (read_32bitBE(0x00,streamFile) != 0x00574156) /* "\0WAV" */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* parse FSB subfile */
|
||||||
|
test_streamFile = setup_fsb4_wav_streamfile(streamFile, subfile_start,subfile_size);
|
||||||
|
if (!test_streamFile) goto fail;
|
||||||
|
|
||||||
|
vgmstream = init_vgmstream_fsb(test_streamFile);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
/* init the VGMSTREAM */
|
||||||
|
close_streamfile(test_streamFile);
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_streamfile(test_streamFile);
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static STREAMFILE* setup_fsb4_wav_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size) {
|
||||||
|
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||||
|
|
||||||
|
/* setup subfile */
|
||||||
|
new_streamFile = open_wrap_streamfile(streamFile);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"fsb");
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
return temp_streamFile;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
uint32_t NumSamples = 0, LoopStart = 0, LoopEnd = 0;
|
uint32_t NumSamples = 0, LoopStart = 0, LoopEnd = 0;
|
||||||
int LoopFlag = 0, ChannelCount = 0, Version, SampleRate = 0, CodingID;
|
int LoopFlag = 0, ChannelCount = 0, Version, SampleRate = 0, CodingID;
|
||||||
int TotalStreams, TargetStream = streamFile->stream_index;
|
int TotalSubsongs, TargetSubsong = streamFile->stream_index;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* check extension, case insensitive */
|
||||||
|
@ -25,7 +25,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
Version = read_32bitLE(0x04,streamFile);
|
Version = read_32bitLE(0x04,streamFile);
|
||||||
if (Version != 0x00 && Version != 0x01) goto fail;
|
if (Version != 0x00 && Version != 0x01) goto fail;
|
||||||
|
|
||||||
TotalStreams = read_32bitLE(0x08,streamFile);
|
TotalSubsongs = read_32bitLE(0x08,streamFile);
|
||||||
SampleHeaderLength = read_32bitLE(0x0C,streamFile);
|
SampleHeaderLength = read_32bitLE(0x0C,streamFile);
|
||||||
NameTableLength = read_32bitLE(0x10,streamFile);
|
NameTableLength = read_32bitLE(0x10,streamFile);
|
||||||
SampleDataLength = read_32bitLE(0x14,streamFile);
|
SampleDataLength = read_32bitLE(0x14,streamFile);
|
||||||
|
@ -37,14 +37,14 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
if ((SampleHeaderLength + NameTableLength + SampleDataLength + BaseHeaderLength) != get_streamfile_size(streamFile))
|
if ((SampleHeaderLength + NameTableLength + SampleDataLength + BaseHeaderLength) != get_streamfile_size(streamFile))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (TargetStream == 0) TargetStream = 1; /* default to 1 */
|
if (TargetSubsong == 0) TargetSubsong = 1; /* default to 1 */
|
||||||
if (TargetStream > TotalStreams || TotalStreams <= 0) goto fail;
|
if (TargetSubsong > TotalSubsongs || TotalSubsongs <= 0) goto fail;
|
||||||
|
|
||||||
SampleHeaderStart = BaseHeaderLength;
|
SampleHeaderStart = BaseHeaderLength;
|
||||||
|
|
||||||
/* find target stream header and data offset, and read all needed values for later use
|
/* find target stream header and data offset, and read all needed values for later use
|
||||||
* (reads one by one as the size of a single stream header is variable) */
|
* (reads one by one as the size of a single stream header is variable) */
|
||||||
for (i = 1; i <= TotalStreams; i++) {
|
for (i = 1; i <= TotalSubsongs; i++) {
|
||||||
off_t DataStart = 0;
|
off_t DataStart = 0;
|
||||||
size_t StreamHeaderLength = 0;
|
size_t StreamHeaderLength = 0;
|
||||||
uint32_t SampleMode1, SampleMode2;
|
uint32_t SampleMode1, SampleMode2;
|
||||||
|
@ -156,11 +156,11 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stream found */
|
/* stream found */
|
||||||
if (i == TargetStream) {
|
if (i == TargetSubsong) {
|
||||||
StartOffset = BaseHeaderLength + SampleHeaderLength + NameTableLength + DataStart;
|
StartOffset = BaseHeaderLength + SampleHeaderLength + NameTableLength + DataStart;
|
||||||
|
|
||||||
/* get stream size from next stream or datasize if there is only one */
|
/* get stream size from next stream or datasize if there is only one */
|
||||||
if (i == TotalStreams) {
|
if (i == TotalSubsongs) {
|
||||||
StreamSize = SampleDataLength - DataStart;
|
StreamSize = SampleDataLength - DataStart;
|
||||||
} else {
|
} else {
|
||||||
uint32_t NextSampleMode = (uint32_t)read_32bitLE(SampleHeaderStart+StreamHeaderLength+0x00,streamFile);
|
uint32_t NextSampleMode = (uint32_t)read_32bitLE(SampleHeaderStart+StreamHeaderLength+0x00,streamFile);
|
||||||
|
@ -178,7 +178,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
/* get stream name */
|
/* get stream name */
|
||||||
if (NameTableLength) {
|
if (NameTableLength) {
|
||||||
NameOffset = BaseHeaderLength + SampleHeaderLength + read_32bitLE(BaseHeaderLength + SampleHeaderLength + 0x04*(TargetStream-1),streamFile);
|
NameOffset = BaseHeaderLength + SampleHeaderLength + read_32bitLE(BaseHeaderLength + SampleHeaderLength + 0x04*(TargetSubsong-1),streamFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -187,12 +187,13 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
vgmstream->sample_rate = SampleRate;
|
vgmstream->sample_rate = SampleRate;
|
||||||
vgmstream->num_streams = TotalStreams;
|
|
||||||
vgmstream->num_samples = NumSamples;
|
vgmstream->num_samples = NumSamples;
|
||||||
if (LoopFlag) {
|
if (LoopFlag) {
|
||||||
vgmstream->loop_start_sample = LoopStart;
|
vgmstream->loop_start_sample = LoopStart;
|
||||||
vgmstream->loop_end_sample = LoopEnd;
|
vgmstream->loop_end_sample = LoopEnd;
|
||||||
}
|
}
|
||||||
|
vgmstream->num_streams = TotalSubsongs;
|
||||||
|
vgmstream->stream_size = StreamSize;
|
||||||
vgmstream->meta_type = meta_FSB5;
|
vgmstream->meta_type = meta_FSB5;
|
||||||
if (NameOffset)
|
if (NameOffset)
|
||||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, NameOffset,streamFile);
|
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, NameOffset,streamFile);
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
#include "meta.h"
|
||||||
|
#include "fsb_keys.h"
|
||||||
|
|
||||||
|
#define FSB_KEY_MAX 128 /* probably 32 */
|
||||||
|
|
||||||
|
static STREAMFILE* setup_fsb_streamfile(STREAMFILE *streamFile, const uint8_t * key, size_t key_size, int is_alt);
|
||||||
|
|
||||||
|
|
||||||
|
/* fully encrypted FSBs */
|
||||||
|
VGMSTREAM * init_vgmstream_fsb_encrypted(STREAMFILE * streamFile) {
|
||||||
|
VGMSTREAM * vgmstream = NULL;
|
||||||
|
|
||||||
|
/* check extensions */
|
||||||
|
if ( !check_extensions(streamFile, "fsb") )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* ignore non-encrypted FSB */
|
||||||
|
if ((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) == 0x46534200) /* "FSB\0" */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
|
/* try fsbkey + all combinations of FSB4/5 and decryption algorithms */
|
||||||
|
{
|
||||||
|
STREAMFILE *temp_streamFile = NULL;
|
||||||
|
uint8_t key[FSB_KEY_MAX];
|
||||||
|
size_t key_size = read_key_file(key, FSB_KEY_MAX, streamFile);
|
||||||
|
|
||||||
|
if (key_size) {
|
||||||
|
{
|
||||||
|
temp_streamFile = setup_fsb_streamfile(streamFile, key,key_size, 0);
|
||||||
|
if (!temp_streamFile) goto fail;
|
||||||
|
|
||||||
|
if (!vgmstream) vgmstream = init_vgmstream_fsb(temp_streamFile);
|
||||||
|
if (!vgmstream) vgmstream = init_vgmstream_fsb5(temp_streamFile);
|
||||||
|
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vgmstream) {
|
||||||
|
temp_streamFile = setup_fsb_streamfile(streamFile, key,key_size, 1);
|
||||||
|
if (!temp_streamFile) goto fail;
|
||||||
|
|
||||||
|
if (!vgmstream) vgmstream = init_vgmstream_fsb(temp_streamFile);
|
||||||
|
if (!vgmstream) vgmstream = init_vgmstream_fsb5(temp_streamFile);
|
||||||
|
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* try all keys until one works */
|
||||||
|
if (!vgmstream) {
|
||||||
|
int i;
|
||||||
|
STREAMFILE *temp_streamFile = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < fsbkey_list_count; i++) {
|
||||||
|
fsbkey_info entry = fsbkey_list[i];
|
||||||
|
;VGM_LOG("fsbkey: size=%i, is_fsb5=%i, is_alt=%i\n", entry.fsbkey_size,entry.is_fsb5, entry.is_alt);
|
||||||
|
|
||||||
|
temp_streamFile = setup_fsb_streamfile(streamFile, entry.fsbkey, entry.fsbkey_size, entry.is_alt);
|
||||||
|
if (!temp_streamFile) goto fail;
|
||||||
|
|
||||||
|
if (fsbkey_list[i].is_fsb5) {
|
||||||
|
vgmstream = init_vgmstream_fsb5(temp_streamFile);
|
||||||
|
} else {
|
||||||
|
vgmstream = init_vgmstream_fsb(temp_streamFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
if (vgmstream) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vgmstream)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t key[FSB_KEY_MAX];
|
||||||
|
size_t key_size;
|
||||||
|
int is_alt;
|
||||||
|
} fsb_decryption_data;
|
||||||
|
|
||||||
|
/* Encrypted FSB info from guessfsb and fsbext */
|
||||||
|
static size_t fsb_decryption_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, fsb_decryption_data* data) {
|
||||||
|
static const unsigned char reverse_bits_table[] = { /* LUT to simplify, could use some bitswap function */
|
||||||
|
0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
|
||||||
|
0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
|
||||||
|
0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
|
||||||
|
0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
|
||||||
|
0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
|
||||||
|
0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
|
||||||
|
0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
|
||||||
|
0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
|
||||||
|
0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
|
||||||
|
0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
|
||||||
|
0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
|
||||||
|
0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
|
||||||
|
0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
|
||||||
|
0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
|
||||||
|
0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
|
||||||
|
0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
|
||||||
|
};
|
||||||
|
size_t bytes_read;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
bytes_read = streamfile->read(streamfile, dest, offset, length);
|
||||||
|
|
||||||
|
/* decrypt data (inverted bits and xor) */
|
||||||
|
for (i = 0; i < bytes_read; i++) {
|
||||||
|
uint8_t xor = data->key[(offset + i) % data->key_size];
|
||||||
|
uint8_t val = dest[i];
|
||||||
|
if (data->is_alt) {
|
||||||
|
dest[i] = reverse_bits_table[val ^ xor];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dest[i] = reverse_bits_table[val] ^ xor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
static STREAMFILE* setup_fsb_streamfile(STREAMFILE *streamFile, const uint8_t * key, size_t key_size, int is_alt) {
|
||||||
|
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||||
|
fsb_decryption_data io_data = {0};
|
||||||
|
size_t io_data_size = sizeof(fsb_decryption_data);
|
||||||
|
|
||||||
|
/* setup decryption with key (external) */
|
||||||
|
if (!key_size || key_size > FSB_KEY_MAX) goto fail;
|
||||||
|
|
||||||
|
memcpy(io_data.key, key, key_size);
|
||||||
|
io_data.key_size = key_size;
|
||||||
|
io_data.is_alt = is_alt;
|
||||||
|
|
||||||
|
/* setup subfile */
|
||||||
|
new_streamFile = open_wrap_streamfile(streamFile);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, fsb_decryption_read);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
return temp_streamFile;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
#ifndef _FSB_KEYS_H_
|
||||||
|
#define _FSB_KEYS_H_
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int is_fsb5;
|
||||||
|
int is_alt;
|
||||||
|
size_t fsbkey_size;
|
||||||
|
const uint8_t *fsbkey;
|
||||||
|
} fsbkey_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of known keys, found in aluigi's site (http://aluigi.altervista.org), forums and with guessfsb.exe
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* DJ Hero 2 (X360) */ //"nos71RiT"
|
||||||
|
static const uint8_t key_dj2[] = { 0x6E,0x6F,0x73,0x37,0x31,0x52,0x69,0x54 };
|
||||||
|
|
||||||
|
/* Double Fine Productions: Brutal Legend, Massive Chalice, etc (multi) */ //"DFm3t4lFTW"
|
||||||
|
static const uint8_t key_dfp[] = { 0x44,0x46,0x6D,0x33,0x74,0x34,0x6C,0x46,0x54,0x57 };
|
||||||
|
|
||||||
|
/* N++ (PC?) */ //"H$#FJa%7gRZZOlxLiN50&g5Q"
|
||||||
|
static const uint8_t key_npp[] = { 0x48,0x24,0x23,0x46,0x4A,0x61,0x25,0x37,0x67,0x52,0x5A,0x5A,0x4F,0x6C,0x78,0x4C,0x69,0x4E,0x35,0x30,0x26,0x67,0x35,0x51 };
|
||||||
|
|
||||||
|
/* Slightly Mad Studios: Project CARS (PC?), World of Speed (PC) */ //"sTOoeJXI2LjK8jBMOk8h5IDRNZl3jq3I"
|
||||||
|
static const uint8_t key_sms[] = { 0x73,0x54,0x4F,0x6F,0x65,0x4A,0x58,0x49,0x32,0x4C,0x6A,0x4B,0x38,0x6A,0x42,0x4D,0x4F,0x6B,0x38,0x68,0x35,0x49,0x44,0x52,0x4E,0x5A,0x6C,0x33,0x6A,0x71,0x33,0x49 };
|
||||||
|
|
||||||
|
/* Ghost in the Shell: First Assault (PC) */ //"%lAn2{Pi*Lhw3T}@7*!kV=?qS$@iNlJ"
|
||||||
|
static const uint8_t key_gfs[] = { 0x25,0x6C,0x41,0x6E,0x32,0x7B,0x50,0x69,0x2A,0x4C,0x68,0x77,0x33,0x54,0x7D,0x40,0x37,0x2A,0x21,0x6B,0x56,0x3D,0x3F,0x71,0x53,0x24,0x40,0x69,0x4E,0x6C,0x4A };
|
||||||
|
|
||||||
|
/* RevHeadz Engine Sounds (Mobile) */ //"1^7%82#&5$~/8sz"
|
||||||
|
static const uint8_t key_rev[] = { 0x31,0x5E,0x37,0x25,0x38,0x32,0x23,0x26,0x35,0x24,0x7E,0x2F,0x38,0x73,0x7A };
|
||||||
|
|
||||||
|
/* Dark Souls 3 (PC) */ //"FDPrVuT4fAFvdHJYAgyMzRF4EcBAnKg"
|
||||||
|
static const uint8_t key_ds3[] = { 0x46,0x44,0x50,0x72,0x56,0x75,0x54,0x34,0x66,0x41,0x46,0x76,0x64,0x48,0x4A,0x59,0x41,0x67,0x79,0x4D,0x7A,0x52,0x46,0x34,0x45,0x63,0x42,0x41,0x6E,0x4B,0x67 };
|
||||||
|
|
||||||
|
/* Mortal Kombat X */
|
||||||
|
static const uint8_t key_mkx[] = { 0x99,0x61,0x64,0xB5,0xFC,0x0F,0x40,0x29,0x83,0xF6,0x1F,0x22,0x0B,0xB5,0x1D,0xC6 };
|
||||||
|
|
||||||
|
/* Xian Xia Chuan (PC) */ //"gat@tcqs2010"
|
||||||
|
static const uint8_t key_xxc[] = { 0x67,0x61,0x74,0x40,0x74,0x63,0x71,0x73,0x32,0x30,0x31,0x30 };
|
||||||
|
|
||||||
|
/* Mirror War Reincarnation of Holiness (PC) */ //"logicsounddesignmwsdev"
|
||||||
|
static const uint8_t key_mwr[] = { 0x6C,0x6F,0x67,0x69,0x63,0x73,0x6F,0x75,0x6E,0x64,0x64,0x65,0x73,0x69,0x67,0x6E,0x6D,0x77,0x73,0x64,0x65,0x76 };
|
||||||
|
|
||||||
|
/* Need for Speed Shift 2 Unleashed (PC demo?) */ //"p&oACY^c4LK5C2v^x5nIO6kg5vNH$tlj"
|
||||||
|
static const uint8_t key_n2u[] = { 0x70,0x26,0x6F,0x41,0x43,0x59,0x5E,0x63,0x34,0x4C,0x4B,0x35,0x43,0x32,0x76,0x5E,0x78,0x35,0x6E,0x49,0x4F,0x36,0x6B,0x67,0x35,0x76,0x4E,0x48,0x24,0x74,0x6C,0x6A };
|
||||||
|
|
||||||
|
/* Critter Crunch, Superbrothers: Sword & Sworcery */ //"j1$Mk0Libg3#apEr42mo"
|
||||||
|
static const uint8_t key_ccr[] = { 0x6A,0x31,0x24,0x4D,0x6B,0x30,0x4C,0x69,0x62,0x67,0x33,0x23,0x61,0x70,0x45,0x72,0x34,0x32,0x6D,0x6F };
|
||||||
|
|
||||||
|
/* Cyphers */ //"@kdj43nKDN^k*kj3ndf02hd95nsl(NJG"
|
||||||
|
static const uint8_t key_cyp[] = { 0x40,0x6B,0x64,0x6A,0x34,0x33,0x6E,0x4B,0x44,0x4E,0x5E,0x6B,0x2A,0x6B,0x6A,0x33,0x6E,0x64,0x66,0x30,0x32,0x68,0x64,0x39,0x35,0x6E,0x73,0x6C,0x28,0x4E,0x4A,0x47 };
|
||||||
|
|
||||||
|
/* Xuan Dou Zhi Wang / King of Combat */ //"Xiayuwu69252.Sonicli81223#$*@*0"
|
||||||
|
static const uint8_t key_xdz[] = { 0x58,0x69,0x61,0x79,0x75,0x77,0x75,0x36,0x39,0x32,0x35,0x32,0x2E,0x53,0x6F,0x6E,0x69,0x63,0x6C,0x69,0x38,0x31,0x32,0x32,0x33,0x23,0x24,0x2A,0x40,0x2A,0x30 };
|
||||||
|
|
||||||
|
/* Ji Feng Zhi Ren / Kritika Online */ //"kri_tika_5050_"
|
||||||
|
static const uint8_t key_jzz[] = { 0x6B,0x72,0x69,0x5F,0x74,0x69,0x6B,0x61,0x5F,0x35,0x30,0x35,0x30,0x5F };
|
||||||
|
|
||||||
|
/* Invisible Inc. */ //"mint78run52"
|
||||||
|
static const uint8_t key_inv[] = { 0x6D,0x69,0x6E,0x74,0x37,0x38,0x72,0x75,0x6E,0x35,0x32 };
|
||||||
|
|
||||||
|
/* Guitar Hero 3 */ //"5atu6w4zaw"
|
||||||
|
static const uint8_t key_gh3[] = { 0x35,0x61,0x74,0x75,0x36,0x77,0x34,0x7A,0x61,0x77 };
|
||||||
|
|
||||||
|
// Unknown:
|
||||||
|
// - Battle: Los Angeles
|
||||||
|
// - Guitar Hero: Warriors of Rock, DJ hero FSB
|
||||||
|
// - Longmenkezhan
|
||||||
|
// - Gas Guzzlers: Combat Carnage (PC?) "C5FA83EA64B34EC2BFE" hex or text? [FSB5]
|
||||||
|
|
||||||
|
static const fsbkey_info fsbkey_list[] = {
|
||||||
|
{ 0,0, sizeof(key_dj2),key_dj2 },
|
||||||
|
{ 0,0, sizeof(key_dfp),key_dfp },
|
||||||
|
{ 1,0, sizeof(key_dfp),key_dfp },//untested
|
||||||
|
{ 1,1, sizeof(key_dfp),key_dfp },//untested
|
||||||
|
{ 1,0, sizeof(key_npp),key_npp },
|
||||||
|
{ 1,0, sizeof(key_sms),key_sms },
|
||||||
|
{ 1,0, sizeof(key_gfs),key_gfs },
|
||||||
|
{ 1,0, sizeof(key_rev),key_rev },
|
||||||
|
{ 1,0, sizeof(key_ds3),key_ds3 },//untested
|
||||||
|
{ 1,1, sizeof(key_ds3),key_ds3 },
|
||||||
|
{ 1,0, sizeof(key_mkx),key_mkx },//untested
|
||||||
|
{ 1,1, sizeof(key_mkx),key_mkx },//untested
|
||||||
|
{ 0,0, sizeof(key_xxc),key_xxc },//untested
|
||||||
|
{ 0,1, sizeof(key_xxc),key_xxc },//untested
|
||||||
|
{ 1,0, sizeof(key_xxc),key_xxc },//untested
|
||||||
|
{ 1,1, sizeof(key_xxc),key_xxc },//untested
|
||||||
|
{ 0,0, sizeof(key_mwr),key_mwr },//untested
|
||||||
|
{ 0,1, sizeof(key_mwr),key_mwr },//untested
|
||||||
|
{ 1,0, sizeof(key_mwr),key_mwr },//untested
|
||||||
|
{ 1,1, sizeof(key_mwr),key_mwr },//untested
|
||||||
|
{ 0,0, sizeof(key_n2u),key_n2u },//untested
|
||||||
|
{ 0,1, sizeof(key_n2u),key_n2u },//untested
|
||||||
|
{ 1,0, sizeof(key_n2u),key_n2u },//untested
|
||||||
|
{ 1,1, sizeof(key_n2u),key_n2u },//untested
|
||||||
|
{ 0,0, sizeof(key_ccr),key_ccr },//untested
|
||||||
|
{ 0,1, sizeof(key_ccr),key_ccr },//untested
|
||||||
|
{ 1,0, sizeof(key_ccr),key_ccr },//untested
|
||||||
|
{ 1,1, sizeof(key_ccr),key_ccr },//untested
|
||||||
|
{ 0,0, sizeof(key_cyp),key_cyp },//untested
|
||||||
|
{ 0,1, sizeof(key_cyp),key_cyp },//untested
|
||||||
|
{ 1,0, sizeof(key_cyp),key_cyp },//untested
|
||||||
|
{ 1,1, sizeof(key_cyp),key_cyp },//untested
|
||||||
|
{ 0,0, sizeof(key_xdz),key_xdz },//untested
|
||||||
|
{ 0,1, sizeof(key_xdz),key_xdz },//untested
|
||||||
|
{ 1,0, sizeof(key_xdz),key_xdz },//untested
|
||||||
|
{ 1,1, sizeof(key_xdz),key_xdz },//untested
|
||||||
|
{ 0,0, sizeof(key_jzz),key_jzz },//untested
|
||||||
|
{ 0,1, sizeof(key_jzz),key_jzz },//untested
|
||||||
|
{ 1,0, sizeof(key_jzz),key_jzz },//untested
|
||||||
|
{ 1,1, sizeof(key_jzz),key_jzz },//untested
|
||||||
|
{ 0,0, sizeof(key_inv),key_inv },//untested
|
||||||
|
{ 0,1, sizeof(key_inv),key_inv },//untested
|
||||||
|
{ 1,0, sizeof(key_inv),key_inv },//untested
|
||||||
|
{ 1,1, sizeof(key_inv),key_inv },//untested
|
||||||
|
{ 0,0, sizeof(key_gh3),key_gh3 },//untested
|
||||||
|
{ 0,1, sizeof(key_gh3),key_gh3 },//untested
|
||||||
|
{ 1,0, sizeof(key_gh3),key_gh3 },//untested
|
||||||
|
{ 1,1, sizeof(key_gh3),key_gh3 },//untested
|
||||||
|
|
||||||
|
};
|
||||||
|
static const int fsbkey_list_count = sizeof(fsbkey_list) / sizeof(fsbkey_list[0]);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _FSB_KEYS_H_ */
|
|
@ -6,7 +6,7 @@ typedef enum { XMA2, ATRAC9 } gtd_codec;
|
||||||
/* GTD - found in Knights Contract (X360, PS3), Valhalla Knights 3 (PSV) */
|
/* GTD - found in Knights Contract (X360, PS3), Valhalla Knights 3 (PSV) */
|
||||||
VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
off_t start_offset, chunk_offset, stpr_offset, name_offset = 0;
|
off_t start_offset, chunk_offset, stpr_offset, name_offset = 0, loop_start_offset, loop_end_offset;
|
||||||
size_t data_size, chunk_size;
|
size_t data_size, chunk_size;
|
||||||
int loop_flag, channel_count, sample_rate;
|
int loop_flag, channel_count, sample_rate;
|
||||||
int num_samples, loop_start_sample, loop_end_sample;
|
int num_samples, loop_start_sample, loop_end_sample;
|
||||||
|
@ -48,6 +48,9 @@ VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile) {
|
||||||
start_offset = 0x34 + read_32bitLE(0x30,streamFile);
|
start_offset = 0x34 + read_32bitLE(0x30,streamFile);
|
||||||
channel_count = read_32bitLE(0x10,streamFile);
|
channel_count = read_32bitLE(0x10,streamFile);
|
||||||
sample_rate = read_32bitLE(0x14,streamFile);
|
sample_rate = read_32bitLE(0x14,streamFile);
|
||||||
|
loop_start_offset = read_32bitLE(0x1c, streamFile);
|
||||||
|
loop_end_offset = read_32bitLE(0x20, streamFile);
|
||||||
|
loop_flag = loop_end_offset > loop_start_offset;
|
||||||
at9_config_data = read_32bitBE(0x28,streamFile);
|
at9_config_data = read_32bitBE(0x28,streamFile);
|
||||||
/* 0x18-0x28: fixed/unknown values */
|
/* 0x18-0x28: fixed/unknown values */
|
||||||
|
|
||||||
|
@ -105,7 +108,10 @@ VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile) {
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
vgmstream->coding_type = coding_ATRAC9;
|
vgmstream->coding_type = coding_ATRAC9;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
if (loop_flag) {
|
||||||
|
vgmstream->loop_start_sample = atrac9_bytes_to_samples(loop_start_offset - start_offset, vgmstream->codec_data);
|
||||||
|
vgmstream->loop_end_sample = atrac9_bytes_to_samples(loop_end_offset - start_offset, vgmstream->codec_data);
|
||||||
|
}
|
||||||
vgmstream->num_samples = atrac9_bytes_to_samples(data_size, vgmstream->codec_data);
|
vgmstream->num_samples = atrac9_bytes_to_samples(data_size, vgmstream->codec_data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile) {
|
||||||
/* find decryption key in external file or preloaded list */
|
/* find decryption key in external file or preloaded list */
|
||||||
{
|
{
|
||||||
uint8_t keybuf[8];
|
uint8_t keybuf[8];
|
||||||
if ( read_key_file(keybuf, 8, streamFile) ) {
|
if (read_key_file(keybuf, 8, streamFile) == 8) {
|
||||||
ciphKey2 = get_32bitBE(keybuf+0);
|
ciphKey2 = get_32bitBE(keybuf+0);
|
||||||
ciphKey1 = get_32bitBE(keybuf+4);
|
ciphKey1 = get_32bitBE(keybuf+4);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -222,6 +222,12 @@ static const hcakey_info hcakey_list[] = {
|
||||||
// Shin Tennis no Ouji-sama: Rising Beat (iOS/Android)
|
// Shin Tennis no Ouji-sama: Rising Beat (iOS/Android)
|
||||||
{4902201417679}, // 0000047561F95FCF
|
{4902201417679}, // 0000047561F95FCF
|
||||||
|
|
||||||
|
// Kai-ri-Sei Million Arthur (Vita)
|
||||||
|
{1782351729464341796}, // 18BC2F7463867524
|
||||||
|
|
||||||
|
// Dx2 Shin Megami Tensei Liberation (iOS/Android)
|
||||||
|
{118714477}, // 000000000713706D
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif/*_HCA_KEYS_H_*/
|
#endif/*_HCA_KEYS_H_*/
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
#include "meta.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
|
/* KMA9 - Koei Tecmo's custom ATRAC9 [Nobunaga no Yabou - Souzou (Vita)] */
|
||||||
|
VGMSTREAM * init_vgmstream_kma9(STREAMFILE *streamFile) {
|
||||||
|
VGMSTREAM * vgmstream = NULL;
|
||||||
|
off_t start_offset;
|
||||||
|
size_t stream_size;
|
||||||
|
int loop_flag, channel_count;
|
||||||
|
int total_subsongs = 0, target_subsong = streamFile->stream_index;
|
||||||
|
|
||||||
|
|
||||||
|
/* check extension */
|
||||||
|
if ( !check_extensions(streamFile,"km9") )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* check header */
|
||||||
|
if (read_32bitBE(0x00,streamFile) != 0x4B4D4139) /* "KMA9" */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
start_offset = read_32bitLE(0x04,streamFile);
|
||||||
|
channel_count = read_16bitLE(0x32,streamFile);
|
||||||
|
loop_flag = (read_32bitLE(0x28,streamFile) != 0);
|
||||||
|
|
||||||
|
total_subsongs = read_32bitLE(0x08,streamFile);
|
||||||
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
|
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||||
|
/* 0x0c: unknown */
|
||||||
|
stream_size = read_32bitLE(0x14,streamFile); /* per subsong */
|
||||||
|
|
||||||
|
|
||||||
|
/* build the VGMSTREAM */
|
||||||
|
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
vgmstream->sample_rate = read_32bitLE(0x34,streamFile);
|
||||||
|
vgmstream->num_samples = read_32bitLE(0x18,streamFile); /* without skip_samples? */
|
||||||
|
vgmstream->loop_start_sample = read_32bitLE(0x24,streamFile); /* with skip_samples? */
|
||||||
|
vgmstream->loop_end_sample = vgmstream->num_samples; /* 0x28 looks like end samples but isn't, no idea */
|
||||||
|
vgmstream->num_streams = total_subsongs;
|
||||||
|
vgmstream->stream_size = stream_size;
|
||||||
|
vgmstream->meta_type = meta_KMA9;
|
||||||
|
|
||||||
|
#ifdef VGM_USE_ATRAC9
|
||||||
|
{
|
||||||
|
atrac9_config cfg = {0};
|
||||||
|
|
||||||
|
cfg.type = ATRAC9_KMA9;
|
||||||
|
cfg.channels = vgmstream->channels;
|
||||||
|
cfg.config_data = read_32bitBE(0x5c,streamFile);
|
||||||
|
cfg.encoder_delay = read_32bitLE(0x20,streamFile);
|
||||||
|
|
||||||
|
cfg.interleave_skip = read_32bitLE(0x10,streamFile); /* 1 superframe */
|
||||||
|
cfg.subsong_skip = total_subsongs;
|
||||||
|
start_offset += (target_subsong-1) * cfg.interleave_skip * (cfg.subsong_skip-1);
|
||||||
|
|
||||||
|
vgmstream->codec_data = init_atrac9(&cfg);
|
||||||
|
if (!vgmstream->codec_data) goto fail;
|
||||||
|
vgmstream->coding_type = coding_ATRAC9;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
|
if (loop_flag) { /* seems correct but must double check */
|
||||||
|
vgmstream->loop_start_sample -= cfg.encoder_delay;
|
||||||
|
//vgmstream->loop_end_sample -= cfg.encoder_delay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -6,7 +6,8 @@
|
||||||
VGMSTREAM * init_vgmstream_ktss(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_ktss(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
int loop_flag, channel_count;
|
int loop_flag, channel_count;
|
||||||
int32_t loop_length;
|
int8_t version;
|
||||||
|
int32_t loop_length, coef_start_offset, coef_spacing;
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
|
|
||||||
if (!check_extensions(streamFile, "ktss"))
|
if (!check_extensions(streamFile, "ktss"))
|
||||||
|
@ -15,6 +16,19 @@ VGMSTREAM * init_vgmstream_ktss(STREAMFILE *streamFile) {
|
||||||
if (read_32bitBE(0, streamFile) != 0x4B545353) /* "KTSS" */
|
if (read_32bitBE(0, streamFile) != 0x4B545353) /* "KTSS" */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
/* check type details */
|
||||||
|
version = read_8bit(0x22, streamFile);
|
||||||
|
if (version == 1) {
|
||||||
|
coef_start_offset = 0x40;
|
||||||
|
coef_spacing = 0x2e;
|
||||||
|
}
|
||||||
|
else if (version == 3) { // Fire Emblem Warriors (Switch)
|
||||||
|
coef_start_offset = 0x5c;
|
||||||
|
coef_spacing = 0x60;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto fail;
|
||||||
|
|
||||||
loop_length = read_32bitLE(0x38, streamFile);
|
loop_length = read_32bitLE(0x38, streamFile);
|
||||||
loop_flag = loop_length > 0;
|
loop_flag = loop_length > 0;
|
||||||
channel_count = read_8bit(0x29, streamFile);
|
channel_count = read_8bit(0x29, streamFile);
|
||||||
|
@ -35,7 +49,7 @@ VGMSTREAM * init_vgmstream_ktss(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
vgmstream->interleave_block_size = 0x8;
|
vgmstream->interleave_block_size = 0x8;
|
||||||
|
|
||||||
dsp_read_coefs_le(vgmstream, streamFile, 0x40, 0x2e);
|
dsp_read_coefs_le(vgmstream, streamFile, coef_start_offset, coef_spacing);
|
||||||
start_offset = read_32bitLE(0x24, streamFile) + 0x20;
|
start_offset = read_32bitLE(0x24, streamFile) + 0x20;
|
||||||
|
|
||||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
||||||
|
@ -46,4 +60,3 @@ fail:
|
||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,11 +99,14 @@ typedef struct {
|
||||||
meta_t meta_type;
|
meta_t meta_type;
|
||||||
layout_t layout_type;
|
layout_t layout_type;
|
||||||
|
|
||||||
/* XOR setup (SCD) */
|
off_t stream_size;
|
||||||
int decryption_enabled;
|
int total_subsongs;
|
||||||
void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read);
|
|
||||||
|
/* decryption setup */
|
||||||
|
void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource);
|
||||||
uint8_t scd_xor;
|
uint8_t scd_xor;
|
||||||
off_t scd_xor_length;
|
off_t scd_xor_length;
|
||||||
|
uint32_t sngw_xor;
|
||||||
|
|
||||||
} vgm_vorbis_info_t;
|
} vgm_vorbis_info_t;
|
||||||
|
|
||||||
|
@ -690,4 +693,17 @@ VGMSTREAM * init_vgmstream_flx(STREAMFILE * streamFile);
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_mogg(STREAMFILE * streamFile);
|
VGMSTREAM * init_vgmstream_mogg(STREAMFILE * streamFile);
|
||||||
|
|
||||||
|
VGMSTREAM * init_vgmstream_kma9(STREAMFILE * streamFile);
|
||||||
|
|
||||||
|
VGMSTREAM * init_vgmstream_fsb_encrypted(STREAMFILE * streamFile);
|
||||||
|
|
||||||
|
VGMSTREAM * init_vgmstream_xwc(STREAMFILE *streamFile);
|
||||||
|
|
||||||
|
VGMSTREAM * init_vgmstream_atsl3(STREAMFILE *streamFile);
|
||||||
|
|
||||||
|
VGMSTREAM * init_vgmstream_sps_n1(STREAMFILE *streamFile);
|
||||||
|
|
||||||
|
VGMSTREAM * init_vgmstream_atx(STREAMFILE *streamFile);
|
||||||
|
|
||||||
|
VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile);
|
||||||
#endif /*_META_H*/
|
#endif /*_META_H*/
|
||||||
|
|
|
@ -8,10 +8,11 @@ VGMSTREAM * init_vgmstream_nsw_opus(STREAMFILE *streamFile) {
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
int loop_flag = 0, channel_count;
|
int loop_flag = 0, channel_count;
|
||||||
int num_samples = 0, loop_start = 0, loop_end = 0;
|
int num_samples = 0, loop_start = 0, loop_end = 0;
|
||||||
off_t offset = 0;
|
off_t offset = 0, data_offset;
|
||||||
|
size_t data_size;
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* check extension, case insensitive */
|
||||||
if ( !check_extensions(streamFile,"opus,lopus")) /* no relation to Ogg Opus */
|
if ( !check_extensions(streamFile,"opus,lopus,nop")) /* no relation to Ogg Opus */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* variations, maybe custom */
|
/* variations, maybe custom */
|
||||||
|
@ -32,17 +33,33 @@ VGMSTREAM * init_vgmstream_nsw_opus(STREAMFILE *streamFile) {
|
||||||
loop_start = read_32bitLE(0x08,streamFile);
|
loop_start = read_32bitLE(0x08,streamFile);
|
||||||
loop_end = read_32bitLE(0x0c,streamFile);
|
loop_end = read_32bitLE(0x0c,streamFile);
|
||||||
}
|
}
|
||||||
|
else if (read_32bitBE(0x00, streamFile) == 0x73616466 && read_32bitBE(0x08, streamFile) == 0x6f707573) { /* Xenoblade Chronicles 2 */
|
||||||
|
offset = read_32bitLE(0x1c, streamFile);
|
||||||
|
|
||||||
|
num_samples = read_32bitLE(0x28, streamFile);
|
||||||
|
loop_flag = read_8bit(0x19, streamFile);
|
||||||
|
if (loop_flag) {
|
||||||
|
loop_start = read_32bitLE(0x2c, streamFile);
|
||||||
|
loop_end = read_32bitLE(0x30, streamFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
offset = 0x00;
|
offset = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_32bitBE(offset + 0x00,streamFile) != 0x01000080)
|
if ((uint32_t)read_32bitLE(offset + 0x00,streamFile) != 0x80000001)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
channel_count = read_8bit(offset + 0x09, streamFile);
|
||||||
|
/* 0x0a: packet size if CBR, 0 if VBR */
|
||||||
|
data_offset = offset + read_32bitLE(offset + 0x10, streamFile);
|
||||||
|
|
||||||
start_offset = offset + 0x28;
|
if ((uint32_t)read_32bitLE(data_offset, streamFile) != 0x80000004)
|
||||||
channel_count = read_8bit(offset + 0x09,streamFile); /* assumed */
|
goto fail;
|
||||||
/* 0x0a: packet size if CBR?, other values: no idea */
|
|
||||||
|
data_size = read_32bitLE(data_offset + 0x04, streamFile);
|
||||||
|
|
||||||
|
start_offset = data_offset + 0x08;
|
||||||
loop_flag = (loop_end > 0); /* -1 when not set */
|
loop_flag = (loop_end > 0); /* -1 when not set */
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,10 +77,9 @@ VGMSTREAM * init_vgmstream_nsw_opus(STREAMFILE *streamFile) {
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
{
|
{
|
||||||
uint8_t buf[0x100];
|
uint8_t buf[0x100];
|
||||||
size_t bytes, skip, data_size;
|
size_t bytes, skip;
|
||||||
ffmpeg_custom_config cfg;
|
ffmpeg_custom_config cfg;
|
||||||
|
|
||||||
data_size = get_streamfile_size(streamFile) - start_offset;
|
|
||||||
skip = 0; //todo
|
skip = 0; //todo
|
||||||
|
|
||||||
bytes = ffmpeg_make_opus_header(buf,0x100, vgmstream->channels, skip, vgmstream->sample_rate);
|
bytes = ffmpeg_make_opus_header(buf,0x100, vgmstream->channels, skip, vgmstream->sample_rate);
|
||||||
|
|
|
@ -0,0 +1,453 @@
|
||||||
|
#include "../vgmstream.h"
|
||||||
|
|
||||||
|
#ifdef VGM_USE_VORBIS
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "meta.h"
|
||||||
|
#include <vorbis/vorbisfile.h>
|
||||||
|
|
||||||
|
#define OGG_DEFAULT_BITSTREAM 0
|
||||||
|
|
||||||
|
static size_t ov_read_func(void *ptr, size_t size, size_t nmemb, void * datasource) {
|
||||||
|
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
||||||
|
size_t bytes_read, items_read;
|
||||||
|
|
||||||
|
off_t real_offset = ov_streamfile->start + ov_streamfile->offset;
|
||||||
|
size_t max_bytes = size * nmemb;
|
||||||
|
|
||||||
|
/* clamp for virtual filesize */
|
||||||
|
if (max_bytes > ov_streamfile->size - ov_streamfile->offset)
|
||||||
|
max_bytes = ov_streamfile->size - ov_streamfile->offset;
|
||||||
|
|
||||||
|
bytes_read = read_streamfile(ptr, real_offset, max_bytes, ov_streamfile->streamfile);
|
||||||
|
items_read = bytes_read / size;
|
||||||
|
|
||||||
|
/* may be encrypted */
|
||||||
|
if (ov_streamfile->decryption_callback) {
|
||||||
|
ov_streamfile->decryption_callback(ptr, size, items_read, ov_streamfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
ov_streamfile->offset += items_read * size;
|
||||||
|
|
||||||
|
return items_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ov_seek_func(void *datasource, ogg_int64_t offset, int whence) {
|
||||||
|
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
||||||
|
ogg_int64_t base_offset, new_offset;
|
||||||
|
|
||||||
|
switch (whence) {
|
||||||
|
case SEEK_SET:
|
||||||
|
base_offset = 0;
|
||||||
|
break;
|
||||||
|
case SEEK_CUR:
|
||||||
|
base_offset = ov_streamfile->offset;
|
||||||
|
break;
|
||||||
|
case SEEK_END:
|
||||||
|
base_offset = ov_streamfile->size;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
new_offset = base_offset + offset;
|
||||||
|
if (new_offset < 0 || new_offset > ov_streamfile->size) {
|
||||||
|
return -1; /* *must* return -1 if stream is unseekable */
|
||||||
|
} else {
|
||||||
|
ov_streamfile->offset = new_offset;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static long ov_tell_func(void * datasource) {
|
||||||
|
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
||||||
|
return ov_streamfile->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ov_close_func(void * datasource) {
|
||||||
|
/* needed as setting ov_close_func in ov_callbacks to NULL doesn't seem to work
|
||||||
|
* (closing the streamfile is done in free_ogg_vorbis) */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void um3_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
|
||||||
|
size_t bytes_read = size*nmemb;
|
||||||
|
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* first 0x800 bytes are xor'd with 0xff */
|
||||||
|
if (ov_streamfile->offset < 0x800) {
|
||||||
|
int num_crypt = 0x800 - ov_streamfile->offset;
|
||||||
|
if (num_crypt > bytes_read)
|
||||||
|
num_crypt = bytes_read;
|
||||||
|
|
||||||
|
for (i = 0; i < num_crypt; i++)
|
||||||
|
((uint8_t*)ptr)[i] ^= 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kovs_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
|
||||||
|
size_t bytes_read = size*nmemb;
|
||||||
|
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* first 0x100 bytes are xor'd with offset */
|
||||||
|
if (ov_streamfile->offset < 0x100) {
|
||||||
|
int max_offset = ov_streamfile->offset + bytes_read;
|
||||||
|
if (max_offset > 0x100)
|
||||||
|
max_offset = 0x100;
|
||||||
|
|
||||||
|
for (i = ov_streamfile->offset; i < max_offset; i++) {
|
||||||
|
((uint8_t*)ptr)[i-ov_streamfile->offset] ^= i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void psychic_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
|
||||||
|
size_t bytes_read = size*nmemb;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* add 0x23 ('#') */
|
||||||
|
{
|
||||||
|
for (i = 0; i < bytes_read; i++)
|
||||||
|
((uint8_t*)ptr)[i] += 0x23;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sngw_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
|
||||||
|
size_t bytes_read = size*nmemb;
|
||||||
|
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
||||||
|
int i;
|
||||||
|
char *header_id = "OggS";
|
||||||
|
uint8_t key[4];
|
||||||
|
|
||||||
|
put_32bitBE(key, ov_streamfile->sngw_xor);
|
||||||
|
|
||||||
|
/* bytes are xor'd with key and nibble-swapped */
|
||||||
|
{
|
||||||
|
for (i = 0; i < bytes_read; i++) {
|
||||||
|
if (ov_streamfile->offset+i < 0x04) {
|
||||||
|
/* replace key in the first 4 bytes with "OggS" */
|
||||||
|
((uint8_t*)ptr)[i] = (uint8_t)header_id[(ov_streamfile->offset + i) % 4];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint8_t val = ((uint8_t*)ptr)[i] ^ key[(ov_streamfile->offset + i) % 4];
|
||||||
|
((uint8_t*)ptr)[i] = ((val << 4) & 0xf0) | ((val >> 4) & 0x0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void isd_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
|
||||||
|
static const uint8_t key[16] = {
|
||||||
|
0xe0,0x00,0xe0,0x00,0xa0,0x00,0x00,0x00,0xe0,0x00,0xe0,0x80,0x40,0x40,0x40,0x00
|
||||||
|
};
|
||||||
|
size_t bytes_read = size*nmemb;
|
||||||
|
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* bytes are xor'd with key */
|
||||||
|
{
|
||||||
|
for (i = 0; i < bytes_read; i++)
|
||||||
|
((uint8_t*)ptr)[i] ^= key[(ov_streamfile->offset + i) % 16];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Ogg Vorbis, by way of libvorbisfile; may contain loop comments */
|
||||||
|
VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
|
||||||
|
char filename[PATH_LIMIT];
|
||||||
|
vgm_vorbis_info_t inf = {0};
|
||||||
|
off_t start_offset = 0;
|
||||||
|
|
||||||
|
int is_ogg = 0;
|
||||||
|
int is_um3 = 0;
|
||||||
|
int is_kovs = 0;
|
||||||
|
int is_psychic = 0;
|
||||||
|
int is_sngw = 0;
|
||||||
|
int is_isd = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* check extension */
|
||||||
|
if (check_extensions(streamFile,"ogg,logg")) { /* .ogg: standard/psychic, .logg: renamed for plugins */
|
||||||
|
is_ogg = 1;
|
||||||
|
} else if (check_extensions(streamFile,"um3")) {
|
||||||
|
is_um3 = 1;
|
||||||
|
} else if (check_extensions(streamFile,"kvs,kovs")) { /* .kvs: Atelier Sophie (PC), kovs: header id only? */
|
||||||
|
is_kovs = 1;
|
||||||
|
} else if (check_extensions(streamFile,"sngw")) { /* .sngw: Devil May Cry 4 SE (PC), Biohazard 6 (PC) */
|
||||||
|
is_sngw = 1;
|
||||||
|
} else if (check_extensions(streamFile,"isd")) { /* .isd: Azure Striker Gunvolt (PC) */
|
||||||
|
is_isd = 1;
|
||||||
|
} else {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||||
|
|
||||||
|
/* check standard Ogg Vorbis */
|
||||||
|
if (is_ogg) {
|
||||||
|
|
||||||
|
/* check Psychic Software obfuscation (Darkwind: War on Wheels PC) */
|
||||||
|
if (read_32bitBE(0x00,streamFile) == 0x2c444430) {
|
||||||
|
is_psychic = 1;
|
||||||
|
inf.decryption_callback = psychic_ogg_decryption_callback;
|
||||||
|
}
|
||||||
|
else if (read_32bitBE(0x00,streamFile) != 0x4f676753) { /* "OggS" */
|
||||||
|
goto fail; /* not known (ex. Wwise) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check "Ultramarine3" (???), may be encrypted */
|
||||||
|
if (is_um3) {
|
||||||
|
if (read_32bitBE(0x00,streamFile) != 0x4f676753) { /* "OggS" */
|
||||||
|
inf.decryption_callback = um3_ogg_decryption_callback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check KOVS (Koei Tecmo games), encrypted and has an actual header */
|
||||||
|
if (is_kovs) {
|
||||||
|
if (read_32bitBE(0x00,streamFile) != 0x4b4f5653) { /* "KOVS" */
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
inf.loop_start = read_32bitLE(0x08,streamFile);
|
||||||
|
inf.loop_flag = (inf.loop_start != 0);
|
||||||
|
inf.decryption_callback = kovs_ogg_decryption_callback;
|
||||||
|
|
||||||
|
start_offset = 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check SNGW (Capcom's MT Framework PC games), may be encrypted */
|
||||||
|
if (is_sngw) {
|
||||||
|
if (read_32bitBE(0x00,streamFile) != 0x4f676753) { /* "OggS" */
|
||||||
|
inf.sngw_xor = read_32bitBE(0x00,streamFile);
|
||||||
|
inf.decryption_callback = sngw_ogg_decryption_callback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check ISD (Gunvolt PC) */
|
||||||
|
if (is_isd) {
|
||||||
|
inf.decryption_callback = isd_ogg_decryption_callback;
|
||||||
|
|
||||||
|
//todo looping unknown, not in Ogg comments
|
||||||
|
// game has sound/GV_steam.* files with info about sound/stream/*.isd
|
||||||
|
//- .ish: constant id/names
|
||||||
|
//- .isl: unknown table, maybe looping?
|
||||||
|
//- .isf: format table, ordered like file numbers, 0x18 header with:
|
||||||
|
// 0x00(2): ?, 0x02(2): channels, 0x04: sample rate, 0x08: skip samples (in PCM bytes), always 32000
|
||||||
|
// 0x0c(2): PCM block size, 0x0e(2): PCM bps, 0x10: null, 0x18: samples (in PCM bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (is_um3) {
|
||||||
|
inf.meta_type = meta_OGG_UM3;
|
||||||
|
} else if (is_kovs) {
|
||||||
|
inf.meta_type = meta_OGG_KOVS;
|
||||||
|
} else if (is_psychic) {
|
||||||
|
inf.meta_type = meta_OGG_PSYCHIC;
|
||||||
|
} else if (is_sngw) {
|
||||||
|
inf.meta_type = meta_OGG_SNGW;
|
||||||
|
} else if (is_isd) {
|
||||||
|
inf.meta_type = meta_OGG_ISD;
|
||||||
|
} else {
|
||||||
|
inf.meta_type = meta_OGG_VORBIS;
|
||||||
|
}
|
||||||
|
inf.layout_type = layout_ogg_vorbis;
|
||||||
|
|
||||||
|
return init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const char * filename, ov_callbacks *callbacks_p, off_t start, const vgm_vorbis_info_t *vgm_inf) {
|
||||||
|
VGMSTREAM * vgmstream = NULL;
|
||||||
|
ogg_vorbis_codec_data * data = NULL;
|
||||||
|
OggVorbis_File *ovf = NULL;
|
||||||
|
vorbis_info *vi;
|
||||||
|
|
||||||
|
int loop_flag = vgm_inf->loop_flag;
|
||||||
|
int32_t loop_start = vgm_inf->loop_start;
|
||||||
|
int loop_length_found = vgm_inf->loop_length_found;
|
||||||
|
int32_t loop_length = vgm_inf->loop_length;
|
||||||
|
int loop_end_found = vgm_inf->loop_end_found;
|
||||||
|
int32_t loop_end = vgm_inf->loop_end;
|
||||||
|
size_t stream_size = vgm_inf->stream_size ?
|
||||||
|
vgm_inf->stream_size :
|
||||||
|
get_streamfile_size(streamFile) - start;
|
||||||
|
|
||||||
|
ov_callbacks default_callbacks;
|
||||||
|
|
||||||
|
if (!callbacks_p) {
|
||||||
|
default_callbacks.read_func = ov_read_func;
|
||||||
|
default_callbacks.seek_func = ov_seek_func;
|
||||||
|
default_callbacks.close_func = ov_close_func;
|
||||||
|
default_callbacks.tell_func = ov_tell_func;
|
||||||
|
|
||||||
|
callbacks_p = &default_callbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* test if this is a proper Ogg Vorbis file, with the current (from init_x) STREAMFILE */
|
||||||
|
{
|
||||||
|
OggVorbis_File temp_ovf;
|
||||||
|
ogg_vorbis_streamfile temp_streamfile;
|
||||||
|
|
||||||
|
temp_streamfile.streamfile = streamFile;
|
||||||
|
|
||||||
|
temp_streamfile.start = start;
|
||||||
|
temp_streamfile.offset = 0;
|
||||||
|
temp_streamfile.size = stream_size;
|
||||||
|
|
||||||
|
temp_streamfile.decryption_callback = vgm_inf->decryption_callback;
|
||||||
|
temp_streamfile.scd_xor = vgm_inf->scd_xor;
|
||||||
|
temp_streamfile.scd_xor_length = vgm_inf->scd_xor_length;
|
||||||
|
temp_streamfile.sngw_xor = vgm_inf->sngw_xor;
|
||||||
|
|
||||||
|
/* open the ogg vorbis file for testing */
|
||||||
|
memset(&temp_ovf, 0, sizeof(temp_ovf));
|
||||||
|
if (ov_test_callbacks(&temp_streamfile, &temp_ovf, NULL, 0, *callbacks_p))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* we have to close this as it has the init_vgmstream meta-reading STREAMFILE */
|
||||||
|
ov_clear(&temp_ovf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* proceed to init codec_data and reopen a STREAMFILE for this stream */
|
||||||
|
{
|
||||||
|
data = calloc(1,sizeof(ogg_vorbis_codec_data));
|
||||||
|
if (!data) goto fail;
|
||||||
|
|
||||||
|
data->ov_streamfile.streamfile = streamFile->open(streamFile,filename, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||||
|
if (!data->ov_streamfile.streamfile) goto fail;
|
||||||
|
|
||||||
|
data->ov_streamfile.start = start;
|
||||||
|
data->ov_streamfile.offset = 0;
|
||||||
|
data->ov_streamfile.size = stream_size;
|
||||||
|
|
||||||
|
data->ov_streamfile.decryption_callback = vgm_inf->decryption_callback;
|
||||||
|
data->ov_streamfile.scd_xor = vgm_inf->scd_xor;
|
||||||
|
data->ov_streamfile.scd_xor_length = vgm_inf->scd_xor_length;
|
||||||
|
data->ov_streamfile.sngw_xor = vgm_inf->sngw_xor;
|
||||||
|
|
||||||
|
/* open the ogg vorbis file for real */
|
||||||
|
if (ov_open_callbacks(&data->ov_streamfile, &data->ogg_vorbis_file, NULL, 0, *callbacks_p))
|
||||||
|
goto fail;
|
||||||
|
ovf = &data->ogg_vorbis_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get info from bitstream 0 */
|
||||||
|
data->bitstream = OGG_DEFAULT_BITSTREAM;
|
||||||
|
vi = ov_info(ovf,OGG_DEFAULT_BITSTREAM);
|
||||||
|
|
||||||
|
/* search for loop comments */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
vorbis_comment *comment = ov_comment(ovf,OGG_DEFAULT_BITSTREAM);
|
||||||
|
|
||||||
|
for (i = 0; i < comment->comments; i++) {
|
||||||
|
const char * user_comment = comment->user_comments[i];
|
||||||
|
if (strstr(user_comment,"loop_start=")==user_comment || /* PSO4 */
|
||||||
|
strstr(user_comment,"LOOP_START=")==user_comment || /* PSO4 */
|
||||||
|
strstr(user_comment,"COMMENT=LOOPPOINT=")==user_comment ||
|
||||||
|
strstr(user_comment,"LOOPSTART=")==user_comment ||
|
||||||
|
strstr(user_comment,"um3.stream.looppoint.start=")==user_comment ||
|
||||||
|
strstr(user_comment,"LOOP_BEGIN=")==user_comment || /* Hatsune Miku: Project Diva F (PS3) */
|
||||||
|
strstr(user_comment,"LoopStart=")==user_comment) { /* Devil May Cry 4 (PC) */
|
||||||
|
loop_start = atol(strrchr(user_comment,'=')+1);
|
||||||
|
loop_flag = (loop_start >= 0);
|
||||||
|
}
|
||||||
|
else if (strstr(user_comment,"LOOPLENGTH=")==user_comment) {/* (LOOPSTART pair) */
|
||||||
|
loop_length = atol(strrchr(user_comment,'=')+1);
|
||||||
|
loop_length_found = 1;
|
||||||
|
}
|
||||||
|
else if (strstr(user_comment,"title=-lps")==user_comment) { /* Memories Off #5 (PC) */
|
||||||
|
loop_start = atol(user_comment+10);
|
||||||
|
loop_flag = (loop_start >= 0);
|
||||||
|
}
|
||||||
|
else if (strstr(user_comment,"album=-lpe")==user_comment) { /* (title=-lps pair) */
|
||||||
|
loop_end = atol(user_comment+10);
|
||||||
|
loop_flag = 1;
|
||||||
|
loop_end_found = 1;
|
||||||
|
}
|
||||||
|
else if (strstr(user_comment,"LoopEnd=")==user_comment) { /* (LoopStart pair) */
|
||||||
|
if(loop_flag) {
|
||||||
|
loop_length = atol(strrchr(user_comment,'=')+1)-loop_start;
|
||||||
|
loop_length_found = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strstr(user_comment,"LOOP_END=")==user_comment) { /* (LOOP_BEGIN pair) */
|
||||||
|
if(loop_flag) {
|
||||||
|
loop_length = atol(strrchr(user_comment,'=')+1)-loop_start;
|
||||||
|
loop_length_found = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strstr(user_comment,"lp=")==user_comment) {
|
||||||
|
sscanf(strrchr(user_comment,'=')+1,"%d,%d", &loop_start,&loop_end);
|
||||||
|
loop_flag = 1;
|
||||||
|
loop_end_found = 1;
|
||||||
|
}
|
||||||
|
else if (strstr(user_comment,"LOOPDEFS=")==user_comment) { /* Fairy Fencer F: Advent Dark Force */
|
||||||
|
sscanf(strrchr(user_comment,'=')+1,"%d,%d", &loop_start,&loop_end);
|
||||||
|
loop_flag = 1;
|
||||||
|
loop_end_found = 1;
|
||||||
|
}
|
||||||
|
else if (strstr(user_comment,"COMMENT=loop(")==user_comment) { /* Zero Time Dilemma (PC) */
|
||||||
|
sscanf(strrchr(user_comment,'(')+1,"%d,%d", &loop_start,&loop_end);
|
||||||
|
loop_flag = 1;
|
||||||
|
loop_end_found = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* build the VGMSTREAM */
|
||||||
|
vgmstream = allocate_vgmstream(vi->channels,loop_flag);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
vgmstream->codec_data = data; /* store our fun extra datas */
|
||||||
|
vgmstream->channels = vi->channels;
|
||||||
|
vgmstream->sample_rate = vi->rate;
|
||||||
|
vgmstream->num_streams = vgm_inf->total_subsongs;
|
||||||
|
vgmstream->stream_size = stream_size;
|
||||||
|
|
||||||
|
vgmstream->num_samples = ov_pcm_total(ovf,-1); /* let libvorbisfile find total samples */
|
||||||
|
if (loop_flag) {
|
||||||
|
vgmstream->loop_start_sample = loop_start;
|
||||||
|
if (loop_length_found)
|
||||||
|
vgmstream->loop_end_sample = loop_start+loop_length;
|
||||||
|
else if (loop_end_found)
|
||||||
|
vgmstream->loop_end_sample = loop_end;
|
||||||
|
else
|
||||||
|
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||||
|
vgmstream->loop_flag = loop_flag;
|
||||||
|
|
||||||
|
if (vgmstream->loop_end_sample > vgmstream->num_samples)
|
||||||
|
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
vgmstream->coding_type = coding_ogg_vorbis;
|
||||||
|
vgmstream->layout_type = vgm_inf->layout_type;
|
||||||
|
vgmstream->meta_type = vgm_inf->meta_type;
|
||||||
|
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
/* clean up anything we may have opened */
|
||||||
|
if (data) {
|
||||||
|
if (ovf)
|
||||||
|
ov_clear(&data->ogg_vorbis_file);//same as ovf
|
||||||
|
if (data->ov_streamfile.streamfile)
|
||||||
|
close_streamfile(data->ov_streamfile.streamfile);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
if (vgmstream) {
|
||||||
|
vgmstream->codec_data = NULL;
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,461 +0,0 @@
|
||||||
#include "../vgmstream.h"
|
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "meta.h"
|
|
||||||
#include "../util.h"
|
|
||||||
#include <vorbis/vorbisfile.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define DEFAULT_BITSTREAM 0
|
|
||||||
|
|
||||||
static size_t read_func(void *ptr, size_t size, size_t nmemb, void * datasource)
|
|
||||||
{
|
|
||||||
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
|
||||||
size_t items_read;
|
|
||||||
|
|
||||||
size_t bytes_read;
|
|
||||||
|
|
||||||
bytes_read = read_streamfile(ptr, ov_streamfile->offset + ov_streamfile->other_header_bytes, size * nmemb,
|
|
||||||
ov_streamfile->streamfile);
|
|
||||||
|
|
||||||
items_read = bytes_read / size;
|
|
||||||
|
|
||||||
ov_streamfile->offset += items_read * size;
|
|
||||||
|
|
||||||
return items_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t read_func_um3(void *ptr, size_t size, size_t nmemb, void * datasource)
|
|
||||||
{
|
|
||||||
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
|
||||||
size_t items_read;
|
|
||||||
|
|
||||||
size_t bytes_read;
|
|
||||||
|
|
||||||
bytes_read = read_streamfile(ptr, ov_streamfile->offset + ov_streamfile->other_header_bytes, size * nmemb,
|
|
||||||
ov_streamfile->streamfile);
|
|
||||||
|
|
||||||
items_read = bytes_read / size;
|
|
||||||
|
|
||||||
/* first 0x800 bytes of um3 are xor'd with 0xff */
|
|
||||||
if (ov_streamfile->offset < 0x800) {
|
|
||||||
int num_crypt = 0x800-ov_streamfile->offset;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (num_crypt > bytes_read) num_crypt=bytes_read;
|
|
||||||
for (i=0;i<num_crypt;i++)
|
|
||||||
((uint8_t*)ptr)[i] ^= 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
ov_streamfile->offset += items_read * size;
|
|
||||||
|
|
||||||
return items_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t read_func_kovs(void *ptr, size_t size, size_t nmemb, void * datasource)
|
|
||||||
{
|
|
||||||
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
|
||||||
size_t items_read;
|
|
||||||
|
|
||||||
size_t bytes_read;
|
|
||||||
|
|
||||||
bytes_read = read_streamfile(ptr, ov_streamfile->offset+ov_streamfile->other_header_bytes, size * nmemb,
|
|
||||||
ov_streamfile->streamfile);
|
|
||||||
|
|
||||||
items_read = bytes_read / size;
|
|
||||||
|
|
||||||
/* first 0x100 bytes of KOVS are xor'd with offset */
|
|
||||||
if (ov_streamfile->offset < 0x100) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i=ov_streamfile->offset;i<0x100;i++)
|
|
||||||
((uint8_t*)ptr)[i-ov_streamfile->offset] ^= i;
|
|
||||||
}
|
|
||||||
|
|
||||||
ov_streamfile->offset += items_read * size;
|
|
||||||
|
|
||||||
return items_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t read_func_scd(void *ptr, size_t size, size_t nmemb, void * datasource)
|
|
||||||
{
|
|
||||||
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
|
||||||
size_t items_read;
|
|
||||||
|
|
||||||
size_t bytes_read;
|
|
||||||
|
|
||||||
bytes_read = read_streamfile(ptr, ov_streamfile->offset + ov_streamfile->other_header_bytes, size * nmemb,
|
|
||||||
ov_streamfile->streamfile);
|
|
||||||
|
|
||||||
items_read = bytes_read / size;
|
|
||||||
|
|
||||||
/* may be encrypted */
|
|
||||||
if (ov_streamfile->decryption_enabled) {
|
|
||||||
ov_streamfile->decryption_callback(ptr, size, nmemb, ov_streamfile, bytes_read);
|
|
||||||
}
|
|
||||||
|
|
||||||
ov_streamfile->offset += items_read * size;
|
|
||||||
|
|
||||||
return items_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t read_func_psych(void *ptr, size_t size, size_t nmemb, void * datasource)
|
|
||||||
{
|
|
||||||
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
|
||||||
size_t items_read;
|
|
||||||
|
|
||||||
size_t bytes_read;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
bytes_read = read_streamfile(ptr, ov_streamfile->offset + ov_streamfile->other_header_bytes, size * nmemb,
|
|
||||||
ov_streamfile->streamfile);
|
|
||||||
|
|
||||||
/* add 0x23 ('#') */
|
|
||||||
for (i=0;i<bytes_read;i++)
|
|
||||||
((uint8_t*)ptr)[i] += 0x23;
|
|
||||||
|
|
||||||
items_read = bytes_read / size;
|
|
||||||
|
|
||||||
ov_streamfile->offset += items_read * size;
|
|
||||||
|
|
||||||
return items_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int seek_func(void *datasource, ogg_int64_t offset, int whence) {
|
|
||||||
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
|
||||||
ogg_int64_t base_offset;
|
|
||||||
ogg_int64_t new_offset;
|
|
||||||
|
|
||||||
switch (whence) {
|
|
||||||
case SEEK_SET:
|
|
||||||
base_offset = 0;
|
|
||||||
break;
|
|
||||||
case SEEK_CUR:
|
|
||||||
base_offset = ov_streamfile->offset;
|
|
||||||
break;
|
|
||||||
case SEEK_END:
|
|
||||||
base_offset = ov_streamfile->size - ov_streamfile->other_header_bytes;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_offset = base_offset + offset;
|
|
||||||
if (new_offset < 0 || new_offset > (ov_streamfile->size - ov_streamfile->other_header_bytes)) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
ov_streamfile->offset = new_offset;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static long tell_func(void * datasource) {
|
|
||||||
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
|
||||||
return ov_streamfile->offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* setting close_func in ov_callbacks to NULL doesn't seem to work */
|
|
||||||
static int close_func(void * datasource) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ogg Vorbis, by way of libvorbisfile */
|
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
|
|
||||||
char filename[PATH_LIMIT];
|
|
||||||
|
|
||||||
ov_callbacks callbacks;
|
|
||||||
|
|
||||||
off_t other_header_bytes = 0;
|
|
||||||
int um3_ogg = 0;
|
|
||||||
int kovs_ogg = 0;
|
|
||||||
int psych_ogg = 0;
|
|
||||||
|
|
||||||
vgm_vorbis_info_t inf;
|
|
||||||
memset(&inf, 0, sizeof(inf));
|
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
|
||||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
|
||||||
|
|
||||||
/* It is only interesting to use oggs with vgmstream if they are looped.
|
|
||||||
To prevent such files from being played by other plugins and such they
|
|
||||||
may be renamed to .logg. This meta reader should still support .ogg,
|
|
||||||
though. */
|
|
||||||
if (strcasecmp("logg",filename_extension(filename)) &&
|
|
||||||
strcasecmp("ogg",filename_extension(filename))) {
|
|
||||||
if (!strcasecmp("um3",filename_extension(filename))) {
|
|
||||||
um3_ogg = 1;
|
|
||||||
} else if (check_extensions(streamFile,"kvs,kovs")) { /* .kvs: Atelier Sophie, kovs: header id only? */
|
|
||||||
kovs_ogg = 1;
|
|
||||||
} else {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* not all um3-ogg are crypted */
|
|
||||||
if (um3_ogg && read_32bitBE(0x0,streamFile)==0x4f676753) {
|
|
||||||
um3_ogg = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* use KOVS header */
|
|
||||||
if (kovs_ogg) {
|
|
||||||
if (read_32bitBE(0x0,streamFile)!=0x4b4f5653) { /* "KOVS" */
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (read_32bitLE(0x8,streamFile)!=0) {
|
|
||||||
inf.loop_start = read_32bitLE(0x8,streamFile);
|
|
||||||
inf.loop_flag = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
other_header_bytes = 0x20;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* detect Psychic Software obfuscation (as seen in "Darkwind") */
|
|
||||||
if (read_32bitBE(0x0,streamFile)==0x2c444430) {
|
|
||||||
psych_ogg = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (um3_ogg) {
|
|
||||||
callbacks.read_func = read_func_um3;
|
|
||||||
} else if (kovs_ogg) {
|
|
||||||
callbacks.read_func = read_func_kovs;
|
|
||||||
} else if (psych_ogg) {
|
|
||||||
callbacks.read_func = read_func_psych;
|
|
||||||
} else {
|
|
||||||
callbacks.read_func = read_func;
|
|
||||||
}
|
|
||||||
callbacks.seek_func = seek_func;
|
|
||||||
callbacks.close_func = close_func;
|
|
||||||
callbacks.tell_func = tell_func;
|
|
||||||
|
|
||||||
if (um3_ogg) {
|
|
||||||
inf.meta_type = meta_OGG_UM3;
|
|
||||||
} else if (kovs_ogg) {
|
|
||||||
inf.meta_type = meta_OGG_KOVS;
|
|
||||||
} else if (psych_ogg) {
|
|
||||||
inf.meta_type = meta_OGG_PSYCH;
|
|
||||||
} else {
|
|
||||||
inf.meta_type = meta_OGG_VORBIS;
|
|
||||||
}
|
|
||||||
|
|
||||||
inf.layout_type = layout_ogg_vorbis;
|
|
||||||
|
|
||||||
return init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, &callbacks, other_header_bytes, &inf);
|
|
||||||
|
|
||||||
fail:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const char * filename, ov_callbacks *callbacks_p, off_t other_header_bytes, const vgm_vorbis_info_t *vgm_inf) {
|
|
||||||
VGMSTREAM * vgmstream = NULL;
|
|
||||||
|
|
||||||
OggVorbis_File temp_ovf;
|
|
||||||
ogg_vorbis_streamfile temp_streamfile;
|
|
||||||
|
|
||||||
ogg_vorbis_codec_data * data = NULL;
|
|
||||||
OggVorbis_File *ovf;
|
|
||||||
int inited_ovf = 0;
|
|
||||||
vorbis_info *info;
|
|
||||||
|
|
||||||
int loop_flag = vgm_inf->loop_flag;
|
|
||||||
int32_t loop_start = vgm_inf->loop_start;
|
|
||||||
int loop_length_found = vgm_inf->loop_length_found;
|
|
||||||
int32_t loop_length = vgm_inf->loop_length;
|
|
||||||
int loop_end_found = vgm_inf->loop_end_found;
|
|
||||||
int32_t loop_end = vgm_inf->loop_end;
|
|
||||||
|
|
||||||
ov_callbacks default_callbacks;
|
|
||||||
|
|
||||||
if (!callbacks_p) {
|
|
||||||
default_callbacks.read_func = read_func;
|
|
||||||
default_callbacks.seek_func = seek_func;
|
|
||||||
default_callbacks.close_func = close_func;
|
|
||||||
default_callbacks.tell_func = tell_func;
|
|
||||||
|
|
||||||
if (vgm_inf->decryption_enabled) {
|
|
||||||
default_callbacks.read_func = read_func_scd;
|
|
||||||
}
|
|
||||||
|
|
||||||
callbacks_p = &default_callbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
temp_streamfile.streamfile = streamFile;
|
|
||||||
temp_streamfile.offset = 0;
|
|
||||||
temp_streamfile.size = get_streamfile_size(temp_streamfile.streamfile);
|
|
||||||
temp_streamfile.other_header_bytes = other_header_bytes;
|
|
||||||
temp_streamfile.decryption_enabled = vgm_inf->decryption_enabled;
|
|
||||||
temp_streamfile.decryption_callback = vgm_inf->decryption_callback;
|
|
||||||
temp_streamfile.scd_xor = vgm_inf->scd_xor;
|
|
||||||
temp_streamfile.scd_xor_length = vgm_inf->scd_xor_length;
|
|
||||||
|
|
||||||
/* can we open this as a proper ogg vorbis file? */
|
|
||||||
memset(&temp_ovf, 0, sizeof(temp_ovf));
|
|
||||||
if (ov_test_callbacks(&temp_streamfile, &temp_ovf, NULL,
|
|
||||||
0, *callbacks_p)) goto fail;
|
|
||||||
|
|
||||||
/* we have to close this as it has the init_vgmstream meta-reading
|
|
||||||
STREAMFILE */
|
|
||||||
ov_clear(&temp_ovf);
|
|
||||||
|
|
||||||
/* proceed to open a STREAMFILE just for this stream */
|
|
||||||
data = calloc(1,sizeof(ogg_vorbis_codec_data));
|
|
||||||
if (!data) goto fail;
|
|
||||||
|
|
||||||
data->ov_streamfile.streamfile = streamFile->open(streamFile,filename,
|
|
||||||
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
|
||||||
if (!data->ov_streamfile.streamfile) goto fail;
|
|
||||||
data->ov_streamfile.offset = 0;
|
|
||||||
data->ov_streamfile.size = get_streamfile_size(data->ov_streamfile.streamfile);
|
|
||||||
data->ov_streamfile.other_header_bytes = other_header_bytes;
|
|
||||||
data->ov_streamfile.decryption_enabled = vgm_inf->decryption_enabled;
|
|
||||||
data->ov_streamfile.decryption_callback = vgm_inf->decryption_callback;
|
|
||||||
data->ov_streamfile.scd_xor = vgm_inf->scd_xor;
|
|
||||||
data->ov_streamfile.scd_xor_length = vgm_inf->scd_xor_length;
|
|
||||||
|
|
||||||
/* open the ogg vorbis file for real */
|
|
||||||
if (ov_open_callbacks(&data->ov_streamfile, &data->ogg_vorbis_file, NULL,
|
|
||||||
0, *callbacks_p)) goto fail;
|
|
||||||
ovf = &data->ogg_vorbis_file;
|
|
||||||
inited_ovf = 1;
|
|
||||||
|
|
||||||
data->bitstream = DEFAULT_BITSTREAM;
|
|
||||||
|
|
||||||
info = ov_info(ovf,DEFAULT_BITSTREAM);
|
|
||||||
|
|
||||||
/* grab the comments */
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
vorbis_comment *comment;
|
|
||||||
|
|
||||||
comment = ov_comment(ovf,DEFAULT_BITSTREAM);
|
|
||||||
|
|
||||||
/* search for a "loop_start" comment */
|
|
||||||
for (i=0;i<comment->comments;i++) {
|
|
||||||
if (strstr(comment->user_comments[i],"loop_start=")==
|
|
||||||
comment->user_comments[i] ||
|
|
||||||
strstr(comment->user_comments[i],"LOOP_START=")==
|
|
||||||
comment->user_comments[i] ||
|
|
||||||
strstr(comment->user_comments[i],"COMMENT=LOOPPOINT=")==
|
|
||||||
comment->user_comments[i] ||
|
|
||||||
strstr(comment->user_comments[i],"LOOPSTART=")==
|
|
||||||
comment->user_comments[i] ||
|
|
||||||
strstr(comment->user_comments[i],"um3.stream.looppoint.start=")==
|
|
||||||
comment->user_comments[i] ||
|
|
||||||
strstr(comment->user_comments[i],"LOOP_BEGIN=")==
|
|
||||||
comment->user_comments[i] ||
|
|
||||||
strstr(comment->user_comments[i],"LoopStart=")==
|
|
||||||
comment->user_comments[i]
|
|
||||||
) {
|
|
||||||
loop_start=atol(strrchr(comment->user_comments[i],'=')+1);
|
|
||||||
if (loop_start >= 0)
|
|
||||||
loop_flag=1;
|
|
||||||
}
|
|
||||||
else if (strstr(comment->user_comments[i],"LOOPLENGTH=")==
|
|
||||||
comment->user_comments[i]) {
|
|
||||||
loop_length=atol(strrchr(comment->user_comments[i],'=')+1);
|
|
||||||
loop_length_found=1;
|
|
||||||
}
|
|
||||||
else if (strstr(comment->user_comments[i],"title=-lps")==
|
|
||||||
comment->user_comments[i]) {
|
|
||||||
loop_start=atol(comment->user_comments[i]+10);
|
|
||||||
if (loop_start >= 0)
|
|
||||||
loop_flag=1;
|
|
||||||
}
|
|
||||||
else if (strstr(comment->user_comments[i],"album=-lpe")==
|
|
||||||
comment->user_comments[i]) {
|
|
||||||
loop_end=atol(comment->user_comments[i]+10);
|
|
||||||
loop_flag=1;
|
|
||||||
loop_end_found=1;
|
|
||||||
}
|
|
||||||
else if (strstr(comment->user_comments[i],"LoopEnd=")==
|
|
||||||
comment->user_comments[i]) {
|
|
||||||
if(loop_flag) {
|
|
||||||
loop_length=atol(strrchr(comment->user_comments[i],'=')+1)-loop_start;
|
|
||||||
loop_length_found=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strstr(comment->user_comments[i],"LOOP_END=")==
|
|
||||||
comment->user_comments[i]) {
|
|
||||||
if(loop_flag) {
|
|
||||||
loop_length=atol(strrchr(comment->user_comments[i],'=')+1)-loop_start;
|
|
||||||
loop_length_found=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strstr(comment->user_comments[i],"lp=")==
|
|
||||||
comment->user_comments[i]) {
|
|
||||||
sscanf(strrchr(comment->user_comments[i],'=')+1,"%d,%d",
|
|
||||||
&loop_start,&loop_end);
|
|
||||||
loop_flag=1;
|
|
||||||
loop_end_found=1;
|
|
||||||
}
|
|
||||||
else if (strstr(comment->user_comments[i],"LOOPDEFS=")==
|
|
||||||
comment->user_comments[i]) {
|
|
||||||
sscanf(strrchr(comment->user_comments[i],'=')+1,"%d,%d",
|
|
||||||
&loop_start,&loop_end);
|
|
||||||
loop_flag=1;
|
|
||||||
loop_end_found=1;
|
|
||||||
}
|
|
||||||
else if (strstr(comment->user_comments[i],"COMMENT=loop(")==
|
|
||||||
comment->user_comments[i]) {
|
|
||||||
sscanf(strrchr(comment->user_comments[i],'(')+1,"%d,%d",
|
|
||||||
&loop_start,&loop_end);
|
|
||||||
loop_flag=1;
|
|
||||||
loop_end_found=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
|
||||||
vgmstream = allocate_vgmstream(info->channels,loop_flag);
|
|
||||||
if (!vgmstream) goto fail;
|
|
||||||
|
|
||||||
/* store our fun extra datas */
|
|
||||||
vgmstream->codec_data = data;
|
|
||||||
|
|
||||||
/* fill in the vital statistics */
|
|
||||||
vgmstream->channels = info->channels;
|
|
||||||
vgmstream->sample_rate = info->rate;
|
|
||||||
|
|
||||||
/* let's play the whole file */
|
|
||||||
vgmstream->num_samples = ov_pcm_total(ovf,-1);
|
|
||||||
|
|
||||||
if (loop_flag) {
|
|
||||||
vgmstream->loop_start_sample = loop_start;
|
|
||||||
if (loop_length_found)
|
|
||||||
vgmstream->loop_end_sample = loop_start+loop_length;
|
|
||||||
else if (loop_end_found)
|
|
||||||
vgmstream->loop_end_sample = loop_end;
|
|
||||||
else
|
|
||||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
|
||||||
vgmstream->loop_flag = loop_flag;
|
|
||||||
|
|
||||||
if (vgmstream->loop_end_sample > vgmstream->num_samples)
|
|
||||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
|
||||||
}
|
|
||||||
vgmstream->coding_type = coding_ogg_vorbis;
|
|
||||||
vgmstream->layout_type = vgm_inf->layout_type;
|
|
||||||
vgmstream->meta_type = vgm_inf->meta_type;
|
|
||||||
|
|
||||||
return vgmstream;
|
|
||||||
|
|
||||||
/* clean up anything we may have opened */
|
|
||||||
fail:
|
|
||||||
if (data) {
|
|
||||||
if (inited_ovf)
|
|
||||||
ov_clear(&data->ogg_vorbis_file);
|
|
||||||
if (data->ov_streamfile.streamfile)
|
|
||||||
close_streamfile(data->ov_streamfile.streamfile);
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
if (vgmstream) {
|
|
||||||
vgmstream->codec_data = NULL;
|
|
||||||
close_vgmstream(vgmstream);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -7,10 +7,10 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
STREAMFILE * streamHeader = NULL;
|
STREAMFILE * streamHeader = NULL;
|
||||||
off_t start_offset, chunk_offset, name_offset = 0;
|
off_t start_offset, chunk_offset, name_offset = 0;
|
||||||
size_t data_size, chunk_size;
|
size_t stream_size, chunk_size;
|
||||||
int loop_flag = 0, channel_count, is_separate = 0, type, sample_rate;
|
int loop_flag = 0, channel_count, is_separate = 0, type, sample_rate;
|
||||||
int32_t loop_start, loop_end;
|
int32_t loop_start, loop_end;
|
||||||
int total_streams, target_stream = streamFile->stream_index;
|
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||||
|
|
||||||
/* check extensions */
|
/* check extensions */
|
||||||
/* .xws: header and data, .xwh+xwb: header + data (.bin+dat are also found in Wild Arms 4/5) */
|
/* .xws: header and data, .xwh+xwb: header + data (.bin+dat are also found in Wild Arms 4/5) */
|
||||||
|
@ -46,14 +46,14 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
|
|
||||||
/* check multi-streams */
|
/* check multi-streams */
|
||||||
total_streams = read_32bitLE(chunk_offset+0x00,streamHeader);
|
total_subsongs = read_32bitLE(chunk_offset+0x00,streamHeader);
|
||||||
if (target_stream == 0) target_stream = 1;
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
if (target_stream < 0 || target_stream > total_streams || total_streams < 1) goto fail;
|
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||||
|
|
||||||
|
|
||||||
/* read stream header */
|
/* read stream header */
|
||||||
{
|
{
|
||||||
off_t header_offset = chunk_offset + 0x4 + 0x1c * (target_stream-1); /* position in FORM */
|
off_t header_offset = chunk_offset + 0x4 + 0x1c * (target_subsong-1); /* position in FORM */
|
||||||
off_t stream_offset, next_stream_offset, data_offset = 0;
|
off_t stream_offset, next_stream_offset, data_offset = 0;
|
||||||
|
|
||||||
type = read_8bit(header_offset+0x00, streamHeader);
|
type = read_8bit(header_offset+0x00, streamHeader);
|
||||||
|
@ -83,22 +83,22 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
||||||
if (!data_offset) goto fail;
|
if (!data_offset) goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target_stream == total_streams) {
|
if (target_subsong == total_subsongs) {
|
||||||
next_stream_offset = data_offset + get_streamfile_size(is_separate ? streamFile : streamHeader);
|
next_stream_offset = data_offset + get_streamfile_size(is_separate ? streamFile : streamHeader);
|
||||||
} else {
|
} else {
|
||||||
off_t next_header_offset = chunk_offset + 0x4 + 0x1c * (target_stream);
|
off_t next_header_offset = chunk_offset + 0x4 + 0x1c * (target_subsong);
|
||||||
next_stream_offset = read_32bitLE(next_header_offset+0x10,streamHeader);
|
next_stream_offset = read_32bitLE(next_header_offset+0x10,streamHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
data_size = next_stream_offset - stream_offset;
|
stream_size = next_stream_offset - stream_offset;
|
||||||
start_offset = data_offset + stream_offset;
|
start_offset = data_offset + stream_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get stream name (always follows FORM) */
|
/* get stream name (always follows FORM) */
|
||||||
if (read_32bitBE(0x10+0x10 + chunk_size,streamHeader) == 0x46545854) { /* "FTXT" */
|
if (read_32bitBE(0x10+0x10 + chunk_size,streamHeader) == 0x46545854) { /* "FTXT" */
|
||||||
chunk_offset = 0x10+0x10 + chunk_size + 0x10;
|
chunk_offset = 0x10+0x10 + chunk_size + 0x10;
|
||||||
if (read_32bitLE(chunk_offset+0x00,streamHeader) == total_streams) {
|
if (read_32bitLE(chunk_offset+0x00,streamHeader) == total_subsongs) {
|
||||||
name_offset = chunk_offset + read_32bitLE(chunk_offset+0x04 + (target_stream-1)*0x04,streamHeader);
|
name_offset = chunk_offset + read_32bitLE(chunk_offset+0x04 + (target_subsong-1)*0x04,streamHeader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +108,8 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
vgmstream->sample_rate = sample_rate;
|
vgmstream->sample_rate = sample_rate;
|
||||||
vgmstream->num_streams = total_streams;
|
vgmstream->num_streams = total_subsongs;
|
||||||
|
vgmstream->stream_size = stream_size;
|
||||||
vgmstream->meta_type = meta_PS2_RXWS;
|
vgmstream->meta_type = meta_PS2_RXWS;
|
||||||
if (name_offset)
|
if (name_offset)
|
||||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamHeader);
|
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamHeader);
|
||||||
|
@ -143,10 +144,10 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
||||||
joint_stereo = 0;
|
joint_stereo = 0;
|
||||||
encoder_delay = 0x0;
|
encoder_delay = 0x0;
|
||||||
|
|
||||||
bytes = ffmpeg_make_riff_atrac3(buf, 0x100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay);
|
bytes = ffmpeg_make_riff_atrac3(buf, 0x100, vgmstream->num_samples, stream_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay);
|
||||||
if (bytes <= 0) goto fail;
|
if (bytes <= 0) goto fail;
|
||||||
|
|
||||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
|
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,stream_size);
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
vgmstream->coding_type = coding_FFmpeg;
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
|
@ -39,20 +39,27 @@ VGMSTREAM * init_vgmstream_cdxa(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* test first block (except when RIFF) */
|
/* test some blocks (except when RIFF) since other .XA/STR may start blank */
|
||||||
if (start_offset == 0) {
|
if (start_offset == 0) {
|
||||||
int i, j;
|
int i, j, block;
|
||||||
|
off_t test_offset = start_offset;
|
||||||
|
size_t sector_size = (is_blocked ? 0x900 : 0x800);
|
||||||
|
size_t block_size = 0x80;
|
||||||
|
|
||||||
/* 0x80 frames for 1 sector (max ~0x800 for ISO mode) */
|
for (block = 0; block < 3; block++) {
|
||||||
for (i = 0; i < (0x800/0x80); i++) {
|
test_offset += (is_blocked ? 0x18 : 0x00); /* header */
|
||||||
off_t test_offset = start_offset + (is_blocked ? 0x18 : 0x00) + 0x80*i;
|
|
||||||
|
|
||||||
/* ADPCM predictors should be 0..3 index */
|
for (i = 0; i < (sector_size/block_size); i++) {
|
||||||
for (j = 0; j < 16; j++) {
|
/* first 0x10 ADPCM predictors should be 0..3 index */
|
||||||
uint8_t header = read_8bit(test_offset + i, streamFile);
|
for (j = 0; j < 16; j++) {
|
||||||
if (((header >> 4) & 0xF) > 3)
|
uint8_t header = read_8bit(test_offset + i, streamFile);
|
||||||
goto fail;
|
if (((header >> 4) & 0xF) > 3)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
test_offset += 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_offset += (is_blocked ? 0x18 : 0x00); /* footer */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
|
|
||||||
/* RIFF - Resource Interchange File Format, standard container used in many games */
|
/* RIFF - Resource Interchange File Format, standard container used in many games */
|
||||||
|
|
||||||
|
#ifdef VGM_USE_VORBIS
|
||||||
|
static VGMSTREAM *parse_riff_ogg(STREAMFILE * streamFile, off_t start_offset, size_t data_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* return milliseconds */
|
/* return milliseconds */
|
||||||
static long parse_adtl_marker(unsigned char * marker) {
|
static long parse_adtl_marker(unsigned char * marker) {
|
||||||
long hh,mm,ss,ms;
|
long hh,mm,ss,ms;
|
||||||
|
@ -76,16 +80,17 @@ static void parse_adtl(off_t adtl_offset, off_t adtl_length, STREAMFILE *stream
|
||||||
typedef struct {
|
typedef struct {
|
||||||
off_t offset;
|
off_t offset;
|
||||||
off_t size;
|
off_t size;
|
||||||
|
uint32_t codec;
|
||||||
int sample_rate;
|
int sample_rate;
|
||||||
int channel_count;
|
int channel_count;
|
||||||
uint32_t block_size;
|
uint32_t block_size;
|
||||||
|
int bps;
|
||||||
|
|
||||||
int coding_type;
|
int coding_type;
|
||||||
int interleave;
|
int interleave;
|
||||||
} riff_fmt_chunk;
|
} riff_fmt_chunk;
|
||||||
|
|
||||||
static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk, riff_fmt_chunk * fmt, int sns, int mwv) {
|
static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk, riff_fmt_chunk * fmt, int sns, int mwv) {
|
||||||
int codec, bps;
|
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
|
||||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE;
|
int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE;
|
||||||
|
|
||||||
|
@ -97,12 +102,12 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||||
fmt->block_size = read_16bit(current_chunk+0x14,streamFile);
|
fmt->block_size = read_16bit(current_chunk+0x14,streamFile);
|
||||||
fmt->interleave = 0;
|
fmt->interleave = 0;
|
||||||
|
|
||||||
bps = read_16bit(current_chunk+0x16,streamFile);
|
fmt->bps = read_16bit(current_chunk+0x16,streamFile);
|
||||||
codec = (uint16_t)read_16bit(current_chunk+0x8,streamFile);
|
fmt->codec = (uint16_t)read_16bit(current_chunk+0x8,streamFile);
|
||||||
|
|
||||||
switch (codec) {
|
switch (fmt->codec) {
|
||||||
case 0x01: /* PCM */
|
case 0x01: /* PCM */
|
||||||
switch (bps) {
|
switch (fmt->bps) {
|
||||||
case 16:
|
case 16:
|
||||||
fmt->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
|
fmt->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
|
||||||
fmt->interleave = 2;
|
fmt->interleave = 2;
|
||||||
|
@ -117,17 +122,17 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x02: /* MS ADPCM */
|
case 0x02: /* MS ADPCM */
|
||||||
if (bps != 4) goto fail;
|
if (fmt->bps != 4) goto fail;
|
||||||
fmt->coding_type = coding_MSADPCM;
|
fmt->coding_type = coding_MSADPCM;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x11: /* MS IMA ADPCM */
|
case 0x11: /* MS IMA ADPCM */
|
||||||
if (bps != 4) goto fail;
|
if (fmt->bps != 4) goto fail;
|
||||||
fmt->coding_type = coding_MS_IMA;
|
fmt->coding_type = coding_MS_IMA;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x69: /* MS IMA ADPCM (XBOX) - Rayman Raving Rabbids 2 (PC) */
|
case 0x69: /* MS IMA ADPCM (XBOX) - Rayman Raving Rabbids 2 (PC) */
|
||||||
if (bps != 4) goto fail;
|
if (fmt->bps != 4) goto fail;
|
||||||
fmt->coding_type = coding_MS_IMA;
|
fmt->coding_type = coding_MS_IMA;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -136,9 +141,9 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||||
if (!check_extensions(streamFile,"med"))
|
if (!check_extensions(streamFile,"med"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (bps == 4) /* normal MS IMA */
|
if (fmt->bps == 4) /* normal MS IMA */
|
||||||
fmt->coding_type = coding_MS_IMA;
|
fmt->coding_type = coding_MS_IMA;
|
||||||
else if (bps == 3) /* 3-bit MS IMA, used in a very few files */
|
else if (fmt->bps == 3) /* 3-bit MS IMA, used in a very few files */
|
||||||
goto fail; //fmt->coding_type = coding_MS_IMA_3BIT;
|
goto fail; //fmt->coding_type = coding_MS_IMA_3BIT;
|
||||||
else
|
else
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -150,12 +155,20 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||||
fmt->interleave = 0x12;
|
fmt->interleave = 0x12;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x5050: /* Ubisoft .sns uses this for DSP */
|
case 0x5050: /* Ubisoft LyN engine's DSP */
|
||||||
if (!sns) goto fail;
|
if (!sns) goto fail;
|
||||||
fmt->coding_type = coding_NGC_DSP;
|
fmt->coding_type = coding_NGC_DSP;
|
||||||
fmt->interleave = 0x08;
|
fmt->interleave = 0x08;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#ifdef VGM_USE_VORBIS
|
||||||
|
case 0x6771: /* Ogg Vorbis (mode 3+) */
|
||||||
|
fmt->coding_type = coding_ogg_vorbis;
|
||||||
|
break;
|
||||||
|
#else
|
||||||
|
goto fail;
|
||||||
|
#endif
|
||||||
|
|
||||||
case 0x270: /* ATRAC3 */
|
case 0x270: /* ATRAC3 */
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
fmt->coding_type = coding_FFmpeg;
|
fmt->coding_type = coding_FFmpeg;
|
||||||
|
@ -264,8 +277,12 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||||
riff_size = read_32bitLE(0x04,streamFile);
|
riff_size = read_32bitLE(0x04,streamFile);
|
||||||
file_size = get_streamfile_size(streamFile);
|
file_size = get_streamfile_size(streamFile);
|
||||||
|
|
||||||
|
/* for some of Liar-soft's buggy RIFF+Ogg made with Soundforge [Shikkoku no Sharnoth (PC)] */
|
||||||
|
if (riff_size+0x08+0x01 == file_size)
|
||||||
|
riff_size += 0x01;
|
||||||
|
|
||||||
/* check for truncated RIFF */
|
/* check for truncated RIFF */
|
||||||
if (file_size < riff_size+8) goto fail;
|
if (file_size < riff_size+0x08) goto fail;
|
||||||
|
|
||||||
/* read through chunks to verify format and find metadata */
|
/* read through chunks to verify format and find metadata */
|
||||||
{
|
{
|
||||||
|
@ -273,7 +290,10 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
while (current_chunk < file_size && current_chunk < riff_size+8) {
|
while (current_chunk < file_size && current_chunk < riff_size+8) {
|
||||||
uint32_t chunk_type = read_32bitBE(current_chunk,streamFile);
|
uint32_t chunk_type = read_32bitBE(current_chunk,streamFile);
|
||||||
off_t chunk_size = read_32bitLE(current_chunk+4,streamFile);
|
size_t chunk_size = read_32bitLE(current_chunk+4,streamFile);
|
||||||
|
|
||||||
|
if (fmt.codec == 0x6771 && chunk_type == 0x64617461) /* Liar-soft again */
|
||||||
|
chunk_size += (chunk_size%2) ? 0x01 : 0x00;
|
||||||
|
|
||||||
if (current_chunk+8+chunk_size > file_size) goto fail;
|
if (current_chunk+8+chunk_size > file_size) goto fail;
|
||||||
|
|
||||||
|
@ -370,6 +390,14 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef VGM_USE_VORBIS
|
||||||
|
/* special case using init_vgmstream_ogg_vorbis */
|
||||||
|
if (fmt.coding_type == coding_ogg_vorbis) {
|
||||||
|
return parse_riff_ogg(streamFile, start_offset, data_size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
vgmstream = allocate_vgmstream(fmt.channel_count,loop_flag);
|
vgmstream = allocate_vgmstream(fmt.channel_count,loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
@ -385,10 +413,11 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||||
vgmstream->num_samples = pcm_bytes_to_samples(data_size, vgmstream->channels, 8);
|
vgmstream->num_samples = pcm_bytes_to_samples(data_size, vgmstream->channels, 8);
|
||||||
break;
|
break;
|
||||||
case coding_L5_555:
|
case coding_L5_555:
|
||||||
|
if (!mwv) goto fail;
|
||||||
vgmstream->num_samples = data_size / 0x12 / fmt.channel_count * 32;
|
vgmstream->num_samples = data_size / 0x12 / fmt.channel_count * 32;
|
||||||
|
|
||||||
/* coefs */
|
/* coefs */
|
||||||
if (mwv) {
|
{
|
||||||
int i, ch;
|
int i, ch;
|
||||||
const int filter_order = 3;
|
const int filter_order = 3;
|
||||||
int filter_count = read_32bitLE(mwv_pflt_offset+0x0c, streamFile);
|
int filter_count = read_32bitLE(mwv_pflt_offset+0x0c, streamFile);
|
||||||
|
@ -415,10 +444,13 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||||
vgmstream->num_samples = ms_ima_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count);
|
vgmstream->num_samples = ms_ima_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count);
|
||||||
break;
|
break;
|
||||||
case coding_NGC_DSP:
|
case coding_NGC_DSP:
|
||||||
//sample_count = dsp_bytes_to_samples(data_size, fmt.channel_count); /* expected from the "fact" chunk */
|
if (!sns) goto fail;
|
||||||
|
if (fact_sample_count <= 0) goto fail;
|
||||||
|
vgmstream->num_samples = fact_sample_count;
|
||||||
|
//vgmstream->num_samples = dsp_bytes_to_samples(data_size, fmt.channel_count);
|
||||||
|
|
||||||
/* coefs */
|
/* coefs */
|
||||||
if (sns) {
|
{
|
||||||
int i, ch;
|
int i, ch;
|
||||||
static const int16_t coef[16] = { /* common codebook? */
|
static const int16_t coef[16] = { /* common codebook? */
|
||||||
0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1,
|
0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1,
|
||||||
|
@ -433,6 +465,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
case coding_FFmpeg: {
|
case coding_FFmpeg: {
|
||||||
ffmpeg_codec_data *ffmpeg_data = init_ffmpeg_offset(streamFile, 0x00, streamFile->get_size(streamFile));
|
ffmpeg_codec_data *ffmpeg_data = init_ffmpeg_offset(streamFile, 0x00, streamFile->get_size(streamFile));
|
||||||
|
@ -492,11 +525,6 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||||
default:
|
default:
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
/* .sns uses fact chunk */
|
|
||||||
if (sns) {
|
|
||||||
if (-1 == fact_sample_count) goto fail;
|
|
||||||
vgmstream->num_samples = fact_sample_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* coding, layout, interleave */
|
/* coding, layout, interleave */
|
||||||
vgmstream->coding_type = fmt.coding_type;
|
vgmstream->coding_type = fmt.coding_type;
|
||||||
|
@ -688,3 +716,98 @@ fail:
|
||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef VGM_USE_VORBIS
|
||||||
|
typedef struct {
|
||||||
|
off_t patch_offset;
|
||||||
|
} riff_ogg_io_data;
|
||||||
|
|
||||||
|
static size_t riff_ogg_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, riff_ogg_io_data* data) {
|
||||||
|
size_t bytes_read = streamfile->read(streamfile, dest, offset, length);
|
||||||
|
|
||||||
|
/* has garbage init Oggs pages, patch bad flag */
|
||||||
|
if (data->patch_offset && data->patch_offset >= offset && data->patch_offset < offset + bytes_read) {
|
||||||
|
VGM_ASSERT(dest[data->patch_offset - offset] != 0x02, "RIFF Ogg: bad patch offset\n");
|
||||||
|
dest[data->patch_offset - offset] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* special handling of Liar-soft's buggy RIFF+Ogg made with Soundforge [Shikkoku no Sharnoth (PC)] */
|
||||||
|
static VGMSTREAM *parse_riff_ogg(STREAMFILE * streamFile, off_t start_offset, size_t data_size) {
|
||||||
|
off_t patch_offset = 0;
|
||||||
|
size_t real_size = data_size;
|
||||||
|
|
||||||
|
/* initial page flag is repeated and causes glitches in decoders, find bad offset */
|
||||||
|
{
|
||||||
|
off_t offset = start_offset + 0x04+0x02;
|
||||||
|
off_t offset_limit = start_offset + data_size; /* usually in the first 0x3000 but can be +0x100000 */
|
||||||
|
|
||||||
|
while (offset < offset_limit) {
|
||||||
|
if (read_32bitBE(offset+0x00, streamFile) == 0x4f676753 && /* "OggS" */
|
||||||
|
read_16bitBE(offset+0x04, streamFile) == 0x0002) { /* start page flag */
|
||||||
|
|
||||||
|
//todo callback should patch on-the-fly by analyzing all "OggS", but is problematic due to arbitrary offsets
|
||||||
|
if (patch_offset) {
|
||||||
|
VGM_LOG("RIFF Ogg: found multiple repeated start pages\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
patch_offset = offset /*- start_offset*/ + 0x04+0x01;
|
||||||
|
}
|
||||||
|
offset++; //todo could be optimized to do OggS page sizes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* last pages don't have the proper flag and confuse decoders, find actual end */
|
||||||
|
{
|
||||||
|
size_t max_size = data_size;
|
||||||
|
off_t offset_limit = start_offset + data_size - 0x1000; /* not worth checking more, let decoder try */
|
||||||
|
off_t offset = start_offset + data_size - 0x1a;
|
||||||
|
|
||||||
|
while (offset > offset_limit) {
|
||||||
|
if (read_32bitBE(offset+0x00, streamFile) == 0x4f676753) { /* "OggS" */
|
||||||
|
if (read_16bitBE(offset+0x04, streamFile) == 0x0004) { /* last page flag */
|
||||||
|
real_size = max_size;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
max_size = offset - start_offset; /* ignore bad pages */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Soundforge includes fact_samples but should be equal to Ogg samples */
|
||||||
|
|
||||||
|
/* actual Ogg init with custom callback to patch weirdness */
|
||||||
|
{
|
||||||
|
VGMSTREAM *vgmstream = NULL;
|
||||||
|
STREAMFILE *custom_streamFile = NULL;
|
||||||
|
char filename[PATH_LIMIT];
|
||||||
|
vgm_vorbis_info_t inf = {0};
|
||||||
|
riff_ogg_io_data io_data = {0};
|
||||||
|
size_t io_data_size = sizeof(riff_ogg_io_data);
|
||||||
|
|
||||||
|
|
||||||
|
inf.layout_type = layout_ogg_vorbis;
|
||||||
|
inf.meta_type = meta_RIFF_WAVE;
|
||||||
|
inf.stream_size = real_size;
|
||||||
|
//inf.loop_flag = 0; /* not observed */
|
||||||
|
|
||||||
|
io_data.patch_offset = patch_offset;
|
||||||
|
|
||||||
|
custom_streamFile = open_io_streamfile(open_wrap_streamfile(streamFile), &io_data,io_data_size, riff_ogg_io_read);
|
||||||
|
if (!custom_streamFile) return NULL;
|
||||||
|
|
||||||
|
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||||
|
vgmstream = init_vgmstream_ogg_vorbis_callbacks(custom_streamFile, filename, NULL, start_offset, &inf);
|
||||||
|
|
||||||
|
close_streamfile(custom_streamFile);
|
||||||
|
|
||||||
|
return vgmstream;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -15,7 +15,7 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
||||||
size_t block_size = 0, block_size_total = 0;
|
size_t block_size = 0, block_size_total = 0;
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||||
int i, total_segments;
|
int i, total_segments;
|
||||||
int total_streams, target_stream = streamFile->stream_index;
|
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||||
|
|
||||||
|
|
||||||
if (!check_extensions(streamFile,"rws"))
|
if (!check_extensions(streamFile,"rws"))
|
||||||
|
@ -49,7 +49,7 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
||||||
* 0x1c: null? 0x30: 0x800?, 0x34: block_size_total?, 0x38: data offset, 0x3c: 0?, 0x40-50: file uuid */
|
* 0x1c: null? 0x30: 0x800?, 0x34: block_size_total?, 0x38: data offset, 0x3c: 0?, 0x40-50: file uuid */
|
||||||
read_32bit = (read_32bitLE(off+0x00,streamFile) > header_size) ? read_32bitBE : read_32bitLE; /* GC/Wii/X360 = BE */
|
read_32bit = (read_32bitLE(off+0x00,streamFile) > header_size) ? read_32bitBE : read_32bitLE; /* GC/Wii/X360 = BE */
|
||||||
total_segments = read_32bit(off+0x20,streamFile);
|
total_segments = read_32bit(off+0x20,streamFile);
|
||||||
total_streams = read_32bit(off+0x28,streamFile);
|
total_subsongs = read_32bit(off+0x28,streamFile);
|
||||||
|
|
||||||
/* skip audio file name */
|
/* skip audio file name */
|
||||||
off += 0x50 + get_rws_string_size(off+0x50, streamFile);
|
off += 0x50 + get_rws_string_size(off+0x50, streamFile);
|
||||||
|
@ -58,8 +58,8 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
||||||
/* Data is divided into "segments" (cues/divisions within data, ex. intro+main, voice1+2+..N) and "streams"
|
/* Data is divided into "segments" (cues/divisions within data, ex. intro+main, voice1+2+..N) and "streams"
|
||||||
* of interleaved blocks (for multichannel?). last stream (only?) has padding. Segments divide all streams.
|
* of interleaved blocks (for multichannel?). last stream (only?) has padding. Segments divide all streams.
|
||||||
* ex.- 0x1800 data + 0 pad of stream_0 2ch, 0x1800 data + 0x200 pad of stream1 2ch (xN). */
|
* ex.- 0x1800 data + 0 pad of stream_0 2ch, 0x1800 data + 0x200 pad of stream1 2ch (xN). */
|
||||||
if (target_stream == 0) target_stream = 1;
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
if (target_stream < 0 || target_stream > total_streams || total_streams < 1) goto fail;
|
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||||
|
|
||||||
/* get segment info, for all streams */
|
/* get segment info, for all streams */
|
||||||
/* 0x00/04/0c: command?, 0x18: full segment size (including all streams), 0x1c: offset, others: ?) */
|
/* 0x00/04/0c: command?, 0x18: full segment size (including all streams), 0x1c: offset, others: ?) */
|
||||||
|
@ -70,9 +70,9 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
/* get usable segment sizes (usually ok but sometimes > stream_size), per stream */
|
/* get usable segment sizes (usually ok but sometimes > stream_size), per stream */
|
||||||
for (i = 0; i < total_segments; i++) { /* sum usable segment sizes (no padding) */
|
for (i = 0; i < total_segments; i++) { /* sum usable segment sizes (no padding) */
|
||||||
stream_size += read_32bit(off + 0x04*i + 0x04*total_segments*(target_stream-1),streamFile);
|
stream_size += read_32bit(off + 0x04*i + 0x04*total_segments*(target_subsong-1),streamFile);
|
||||||
}
|
}
|
||||||
off += 0x04 * (total_segments * total_streams);
|
off += 0x04 * (total_segments * total_subsongs);
|
||||||
|
|
||||||
/* skip segment uuids */
|
/* skip segment uuids */
|
||||||
off += 0x10 * total_segments;
|
off += 0x10 * total_segments;
|
||||||
|
@ -85,21 +85,21 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
||||||
/* get stream layout */
|
/* get stream layout */
|
||||||
/* 0x00/04/14: command?, 0x08: null? 0x0c: spf related? (XADPCM=07, VAG=1C, DSP=0E, PCM=01)
|
/* 0x00/04/14: command?, 0x08: null? 0x0c: spf related? (XADPCM=07, VAG=1C, DSP=0E, PCM=01)
|
||||||
* 0x24: offset within data chunk, 0x1c: codec related?, others: ?) */
|
* 0x24: offset within data chunk, 0x1c: codec related?, others: ?) */
|
||||||
for (i = 0; i < total_streams; i++) { /* get block_sizes */
|
for (i = 0; i < total_subsongs; i++) { /* get block_sizes */
|
||||||
block_size_total += read_32bit(off + 0x10 + 0x28*i, streamFile); /* for all streeams, to skip during decode */
|
block_size_total += read_32bit(off + 0x10 + 0x28*i, streamFile); /* for all streeams, to skip during decode */
|
||||||
if (i+1 == target_stream) {
|
if (i+1 == target_subsong) {
|
||||||
//block_size_full = read_32bit(off + 0x10 + 0x28*i, streamFile); /* with padding, can be different per stream */
|
//block_size_full = read_32bit(off + 0x10 + 0x28*i, streamFile); /* with padding, can be different per stream */
|
||||||
block_size = read_32bit(off + 0x20 + 0x28*i, streamFile); /* without padding */
|
block_size = read_32bit(off + 0x20 + 0x28*i, streamFile); /* without padding */
|
||||||
stream_offset = read_32bit(off + 0x24 + 0x28*i, streamFile); /* within data */
|
stream_offset = read_32bit(off + 0x24 + 0x28*i, streamFile); /* within data */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
off += 0x28 * total_streams;
|
off += 0x28 * total_subsongs;
|
||||||
|
|
||||||
/* get stream config */
|
/* get stream config */
|
||||||
/* 0x04: command?, 0x0c(1): bits per sample, others: null? */
|
/* 0x04: command?, 0x0c(1): bits per sample, others: null? */
|
||||||
for (i = 0; i < total_streams; i++) { /* size depends on codec so we must parse it */
|
for (i = 0; i < total_subsongs; i++) { /* size depends on codec so we must parse it */
|
||||||
int prev_codec = 0;
|
int prev_codec = 0;
|
||||||
if (i+1 == target_stream) {
|
if (i+1 == target_subsong) {
|
||||||
sample_rate = read_32bit(off+0x00, streamFile);
|
sample_rate = read_32bit(off+0x00, streamFile);
|
||||||
//unk_size = read_32bit(off+0x08, streamFile); /* segment size again? loop-related? */
|
//unk_size = read_32bit(off+0x08, streamFile); /* segment size again? loop-related? */
|
||||||
channel_count = read_8bit(off+0x0d, streamFile);
|
channel_count = read_8bit(off+0x0d, streamFile);
|
||||||
|
@ -110,7 +110,7 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
if (prev_codec == 0xF86215B0) { /* if codec is DSP there is an extra field per stream */
|
if (prev_codec == 0xF86215B0) { /* if codec is DSP there is an extra field per stream */
|
||||||
/* 0x00: approx num samples? 0x04: approx size/loop related? (can be 0) */
|
/* 0x00: approx num samples? 0x04: approx size/loop related? (can be 0) */
|
||||||
if (i+1 == target_stream) {
|
if (i+1 == target_subsong) {
|
||||||
coefs_offset = off + 0x1c;
|
coefs_offset = off + 0x1c;
|
||||||
}
|
}
|
||||||
off += 0x60;
|
off += 0x60;
|
||||||
|
@ -120,11 +120,11 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* skip stream uuids */
|
/* skip stream uuids */
|
||||||
off += 0x10 * total_streams;
|
off += 0x10 * total_subsongs;
|
||||||
|
|
||||||
/* get stream name */
|
/* get stream name */
|
||||||
for (i = 0; i < total_streams; i++) {
|
for (i = 0; i < total_subsongs; i++) {
|
||||||
if (i+1 == target_stream) {
|
if (i+1 == target_subsong) {
|
||||||
name_offset = off;
|
name_offset = off;
|
||||||
}
|
}
|
||||||
off += get_rws_string_size(off, streamFile);
|
off += get_rws_string_size(off, streamFile);
|
||||||
|
@ -137,7 +137,7 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
||||||
start_offset = 0x0c + 0x0c + header_size + 0x0c + stream_offset;
|
start_offset = 0x0c + 0x0c + header_size + 0x0c + stream_offset;
|
||||||
|
|
||||||
/* sometimes it's wrong for no apparent reason (probably a bug in RWS) */
|
/* sometimes it's wrong for no apparent reason (probably a bug in RWS) */
|
||||||
stream_size_expected = (stream_size_full / block_size_total) * (block_size * total_streams) / total_streams;
|
stream_size_expected = (stream_size_full / block_size_total) * (block_size * total_subsongs) / total_subsongs;
|
||||||
if (stream_size > stream_size_expected) {
|
if (stream_size > stream_size_expected) {
|
||||||
VGM_LOG("RWS: readjusting wrong stream size %x vs expected %x\n", stream_size, stream_size_expected);
|
VGM_LOG("RWS: readjusting wrong stream size %x vs expected %x\n", stream_size, stream_size_expected);
|
||||||
stream_size = stream_size_expected;
|
stream_size = stream_size_expected;
|
||||||
|
@ -149,7 +149,8 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
vgmstream->sample_rate = sample_rate;
|
vgmstream->sample_rate = sample_rate;
|
||||||
vgmstream->num_streams = total_streams;
|
vgmstream->num_streams = total_subsongs;
|
||||||
|
vgmstream->stream_size = stream_size;
|
||||||
vgmstream->meta_type = meta_RWS;
|
vgmstream->meta_type = meta_RWS;
|
||||||
if (name_offset)
|
if (name_offset)
|
||||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamFile);
|
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamFile);
|
||||||
|
@ -159,10 +160,11 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
||||||
vgmstream->full_block_size = block_size_total;
|
vgmstream->full_block_size = block_size_total;
|
||||||
|
|
||||||
switch(codec) {
|
switch(codec) {
|
||||||
|
case 0x17D21BD0: /* PCM PC (17D21BD0 8735ED4E B9D9B8E8 6EA9B995) */
|
||||||
case 0xD01BD217: /* PCM X360 (D01BD217 35874EED B9D9B8E8 6EA9B995) */
|
case 0xD01BD217: /* PCM X360 (D01BD217 35874EED B9D9B8E8 6EA9B995) */
|
||||||
/* ex. The Legend of Spyro (X360) */
|
/* ex. D.i.R.T. - Origin of the Species (PC), The Legend of Spyro (X360) */
|
||||||
vgmstream->coding_type = coding_PCM16_int;
|
vgmstream->coding_type = coding_PCM16_int;
|
||||||
vgmstream->codec_endian = 1; /* big */
|
vgmstream->codec_endian = (codec == 0xD01BD217);
|
||||||
vgmstream->interleave_block_size = 0x02; /* only used to setup channels */
|
vgmstream->interleave_block_size = 0x02; /* only used to setup channels */
|
||||||
|
|
||||||
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16);
|
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16);
|
||||||
|
|
|
@ -8,8 +8,8 @@ static void get_stream_name(char * stream_name, STREAMFILE *streamFile, int targ
|
||||||
VGMSTREAM * init_vgmstream_sab(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_sab(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
int loop_flag, channel_count = 0, is_stream, align, codec, sample_rate, data_size, loop_start, loop_end;
|
int loop_flag, channel_count = 0, is_stream, align, codec, sample_rate, stream_size, loop_start, loop_end;
|
||||||
int total_streams, target_stream = streamFile->stream_index;
|
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||||
|
|
||||||
/* .sab: main, .sob: config/names */
|
/* .sab: main, .sob: config/names */
|
||||||
if (!check_extensions(streamFile,"sab"))
|
if (!check_extensions(streamFile,"sab"))
|
||||||
|
@ -20,29 +20,29 @@ VGMSTREAM * init_vgmstream_sab(STREAMFILE *streamFile) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
is_stream = read_32bitLE(0x04,streamFile) & 0x04; /* other flags don't seem to matter */
|
is_stream = read_32bitLE(0x04,streamFile) & 0x04; /* other flags don't seem to matter */
|
||||||
total_streams = is_stream ? 1 : read_32bitLE(0x08,streamFile);
|
total_subsongs = is_stream ? 1 : read_32bitLE(0x08,streamFile);
|
||||||
if (target_stream == 0) target_stream = 1;
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
if (target_stream < 0 || target_stream > total_streams || total_streams < 1) goto fail;
|
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||||
|
|
||||||
align = read_32bitLE(0x0c,streamFile); /* doubles as interleave */
|
align = read_32bitLE(0x0c,streamFile); /* doubles as interleave */
|
||||||
|
|
||||||
/* stream config */
|
/* stream config */
|
||||||
codec = read_32bitLE(0x18 + 0x1c*(target_stream-1) + 0x00,streamFile);
|
codec = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x00,streamFile);
|
||||||
channel_count = read_32bitLE(0x18 + 0x1c*(target_stream-1) + 0x04,streamFile);
|
channel_count = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x04,streamFile);
|
||||||
sample_rate = read_32bitLE(0x18 + 0x1c*(target_stream-1) + 0x08,streamFile);
|
sample_rate = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x08,streamFile);
|
||||||
data_size = read_32bitLE(0x18 + 0x1c*(target_stream-1) + 0x0c,streamFile);
|
stream_size = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x0c,streamFile);
|
||||||
loop_start = read_32bitLE(0x18 + 0x1c*(target_stream-1) + 0x10,streamFile);
|
loop_start = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x10,streamFile);
|
||||||
loop_end = read_32bitLE(0x18 + 0x1c*(target_stream-1) + 0x14,streamFile);
|
loop_end = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x14,streamFile);
|
||||||
loop_flag = (loop_end > 0);
|
loop_flag = (loop_end > 0);
|
||||||
|
|
||||||
start_offset = 0x18 + 0x1c*total_streams;
|
start_offset = 0x18 + 0x1c*total_subsongs;
|
||||||
if (start_offset % align)
|
if (start_offset % align)
|
||||||
start_offset += align - (start_offset % align);
|
start_offset += align - (start_offset % align);
|
||||||
start_offset += read_32bitLE(0x18 + 0x1c*(target_stream-1) + 0x18,streamFile);
|
start_offset += read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x18,streamFile);
|
||||||
|
|
||||||
if (is_stream) {
|
if (is_stream) {
|
||||||
channel_count = read_32bitLE(0x08,streamFile); /* uncommon, but non-stream stereo exists */
|
channel_count = read_32bitLE(0x08,streamFile); /* uncommon, but non-stream stereo exists */
|
||||||
data_size *= channel_count;
|
stream_size *= channel_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
|
@ -50,8 +50,8 @@ VGMSTREAM * init_vgmstream_sab(STREAMFILE *streamFile) {
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
vgmstream->sample_rate = sample_rate;
|
vgmstream->sample_rate = sample_rate;
|
||||||
|
vgmstream->num_streams = total_subsongs;
|
||||||
vgmstream->num_streams = total_streams;
|
vgmstream->stream_size = stream_size;
|
||||||
vgmstream->meta_type = meta_SAB;
|
vgmstream->meta_type = meta_SAB;
|
||||||
|
|
||||||
switch(codec) {
|
switch(codec) {
|
||||||
|
@ -60,7 +60,7 @@ VGMSTREAM * init_vgmstream_sab(STREAMFILE *streamFile) {
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = is_stream ? align : 0x02;
|
vgmstream->interleave_block_size = is_stream ? align : 0x02;
|
||||||
|
|
||||||
vgmstream->num_samples = pcm_bytes_to_samples(data_size, vgmstream->channels, 16);
|
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, vgmstream->channels, 16);
|
||||||
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, vgmstream->channels, 16);
|
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, vgmstream->channels, 16);
|
||||||
vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_end, vgmstream->channels, 16);
|
vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_end, vgmstream->channels, 16);
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ VGMSTREAM * init_vgmstream_sab(STREAMFILE *streamFile) {
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = is_stream ? align : 0x10;
|
vgmstream->interleave_block_size = is_stream ? align : 0x10;
|
||||||
|
|
||||||
vgmstream->num_samples = ps_bytes_to_samples(data_size, vgmstream->channels);
|
vgmstream->num_samples = ps_bytes_to_samples(stream_size, vgmstream->channels);
|
||||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, vgmstream->channels);
|
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, vgmstream->channels);
|
||||||
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, vgmstream->channels);
|
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, vgmstream->channels);
|
||||||
break;
|
break;
|
||||||
|
@ -81,7 +81,7 @@ VGMSTREAM * init_vgmstream_sab(STREAMFILE *streamFile) {
|
||||||
vgmstream->layout_type = is_stream ? layout_interleave : layout_none;
|
vgmstream->layout_type = is_stream ? layout_interleave : layout_none;
|
||||||
vgmstream->interleave_block_size = is_stream ? align : 0x00;
|
vgmstream->interleave_block_size = is_stream ? align : 0x00;
|
||||||
|
|
||||||
vgmstream->num_samples = ms_ima_bytes_to_samples(data_size, 0x24*vgmstream->channels, vgmstream->channels);
|
vgmstream->num_samples = ms_ima_bytes_to_samples(stream_size, 0x24*vgmstream->channels, vgmstream->channels);
|
||||||
vgmstream->loop_start_sample = ms_ima_bytes_to_samples(loop_start, 0x24*vgmstream->channels, vgmstream->channels);
|
vgmstream->loop_start_sample = ms_ima_bytes_to_samples(loop_start, 0x24*vgmstream->channels, vgmstream->channels);
|
||||||
vgmstream->loop_end_sample = ms_ima_bytes_to_samples(loop_end, 0x24*vgmstream->channels, vgmstream->channels);
|
vgmstream->loop_end_sample = ms_ima_bytes_to_samples(loop_end, 0x24*vgmstream->channels, vgmstream->channels);
|
||||||
break;
|
break;
|
||||||
|
@ -91,7 +91,7 @@ VGMSTREAM * init_vgmstream_sab(STREAMFILE *streamFile) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
get_stream_name(vgmstream->stream_name, streamFile, target_stream);
|
get_stream_name(vgmstream->stream_name, streamFile, target_subsong);
|
||||||
|
|
||||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
@ -2,19 +2,17 @@
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
|
|
||||||
/* SGXD - Sony/SCEI's format (SGB+SGH / SGD / SGX), found in:
|
/* SGXD - Sony/SCEI's format (SGB+SGH / SGD / SGX) */
|
||||||
* PS3: Genji, Folklore, Afrika (Short VAG), Tokyo Jungle
|
|
||||||
* PSP: Brave Story, Sarugetchu Sarusaru Daisakusen, Kurohyo 1/2, Pathwork Heroes */
|
|
||||||
VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
STREAMFILE * streamHeader = NULL;
|
STREAMFILE * streamHeader = NULL;
|
||||||
off_t start_offset, data_offset, chunk_offset, name_offset = 0;
|
off_t start_offset, data_offset, chunk_offset, name_offset = 0;
|
||||||
size_t data_size;
|
size_t stream_size;
|
||||||
|
|
||||||
int is_sgx, is_sgb = 0;
|
int is_sgx, is_sgb = 0;
|
||||||
int loop_flag, channels, type;
|
int loop_flag, channels, type;
|
||||||
int sample_rate, num_samples, loop_start_sample, loop_end_sample;
|
int sample_rate, num_samples, loop_start_sample, loop_end_sample;
|
||||||
int total_streams, target_stream = streamFile->stream_index;
|
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||||
|
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* check extension, case insensitive */
|
||||||
|
@ -59,14 +57,14 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
|
||||||
/* 0x04 SGX: unknown; SGD/SGH: chunk length, 0x08 null */
|
/* 0x04 SGX: unknown; SGD/SGH: chunk length, 0x08 null */
|
||||||
|
|
||||||
/* check multi-streams (usually only SE containers; Puppeteer) */
|
/* check multi-streams (usually only SE containers; Puppeteer) */
|
||||||
total_streams = read_32bitLE(chunk_offset+0x04,streamHeader);
|
total_subsongs = read_32bitLE(chunk_offset+0x04,streamHeader);
|
||||||
if (target_stream == 0) target_stream = 1;
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
if (target_stream < 0 || target_stream > total_streams || total_streams < 1) goto fail;
|
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||||
|
|
||||||
/* read stream header */
|
/* read stream header */
|
||||||
{
|
{
|
||||||
off_t stream_offset;
|
off_t stream_offset;
|
||||||
chunk_offset += 0x08 + 0x38 * (target_stream-1); /* position in target header*/
|
chunk_offset += 0x08 + 0x38 * (target_subsong-1); /* position in target header*/
|
||||||
|
|
||||||
/* 0x00 ? (00/01/02) */
|
/* 0x00 ? (00/01/02) */
|
||||||
if (!is_sgx) /* meaning unknown in .sgx; offset 0 = not a stream (a RGND sample) */
|
if (!is_sgx) /* meaning unknown in .sgx; offset 0 = not a stream (a RGND sample) */
|
||||||
|
@ -85,7 +83,7 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
|
||||||
num_samples = read_32bitLE(chunk_offset+0x20,streamHeader);
|
num_samples = read_32bitLE(chunk_offset+0x20,streamHeader);
|
||||||
loop_start_sample = read_32bitLE(chunk_offset+0x24,streamHeader);
|
loop_start_sample = read_32bitLE(chunk_offset+0x24,streamHeader);
|
||||||
loop_end_sample = read_32bitLE(chunk_offset+0x28,streamHeader);
|
loop_end_sample = read_32bitLE(chunk_offset+0x28,streamHeader);
|
||||||
data_size = read_32bitLE(chunk_offset+0x2c,streamHeader); /* stream size (without padding) / interleave (for type3) */
|
stream_size = read_32bitLE(chunk_offset+0x2c,streamHeader); /* stream size (without padding) / interleave (for type3) */
|
||||||
|
|
||||||
if (is_sgx) {
|
if (is_sgx) {
|
||||||
stream_offset = 0x0;
|
stream_offset = 0x0;
|
||||||
|
@ -107,7 +105,8 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
|
||||||
vgmstream->num_samples = num_samples;
|
vgmstream->num_samples = num_samples;
|
||||||
vgmstream->loop_start_sample = loop_start_sample;
|
vgmstream->loop_start_sample = loop_start_sample;
|
||||||
vgmstream->loop_end_sample = loop_end_sample;
|
vgmstream->loop_end_sample = loop_end_sample;
|
||||||
vgmstream->num_streams = total_streams;
|
vgmstream->num_streams = total_subsongs;
|
||||||
|
vgmstream->stream_size = stream_size;
|
||||||
vgmstream->meta_type = meta_SGXD;
|
vgmstream->meta_type = meta_SGXD;
|
||||||
if (name_offset)
|
if (name_offset)
|
||||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamHeader);
|
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamHeader);
|
||||||
|
@ -118,23 +117,23 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
|
||||||
vgmstream->loop_end_sample -= 1;
|
vgmstream->loop_end_sample -= 1;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 0x03: /* PS-ADPCM */
|
case 0x03: /* PS-ADPCM [Genji (PS3), Ape Escape Move (PS3)]*/
|
||||||
vgmstream->coding_type = coding_PSX;
|
vgmstream->coding_type = coding_PSX;
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
if (is_sgx || is_sgb) {
|
if (is_sgx || is_sgb) {
|
||||||
vgmstream->interleave_block_size = 0x10;
|
vgmstream->interleave_block_size = 0x10;
|
||||||
} else { /* this only seems to happen with SFX */
|
} else { /* this only seems to happen with SFX */
|
||||||
vgmstream->interleave_block_size = data_size;
|
vgmstream->interleave_block_size = stream_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
case 0x04: { /* ATRAC3plus */
|
case 0x04: { /* ATRAC3plus [Kurohyo 1/2 (PSP), BraveStory (PSP)] */
|
||||||
ffmpeg_codec_data *ffmpeg_data;
|
ffmpeg_codec_data *ffmpeg_data;
|
||||||
|
|
||||||
/* internally has a RIFF header; but the SGXD header / sample rate has priority over it (may not match) */
|
/* internally has a RIFF header; but the SGXD header / sample rate has priority over it (may not match) */
|
||||||
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, data_size);
|
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, stream_size);
|
||||||
if ( !ffmpeg_data ) goto fail;
|
if ( !ffmpeg_data ) goto fail;
|
||||||
vgmstream->codec_data = ffmpeg_data;
|
vgmstream->codec_data = ffmpeg_data;
|
||||||
vgmstream->coding_type = coding_FFmpeg;
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
|
@ -158,7 +157,7 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
case 0x05: /* Short PS-ADPCM */
|
case 0x05: /* Short PS-ADPCM [Afrika (PS3)] */
|
||||||
vgmstream->coding_type = coding_PSX_cfg;
|
vgmstream->coding_type = coding_PSX_cfg;
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = 0x4;
|
vgmstream->interleave_block_size = 0x4;
|
||||||
|
@ -166,10 +165,10 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
case 0x06: { /* AC3 */
|
case 0x06: { /* AC3 [Tokyo Jungle (PS3), Afrika (PS3)] */
|
||||||
ffmpeg_codec_data *ffmpeg_data;
|
ffmpeg_codec_data *ffmpeg_data;
|
||||||
|
|
||||||
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, data_size);
|
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, stream_size);
|
||||||
if ( !ffmpeg_data ) goto fail;
|
if ( !ffmpeg_data ) goto fail;
|
||||||
vgmstream->codec_data = ffmpeg_data;
|
vgmstream->codec_data = ffmpeg_data;
|
||||||
vgmstream->coding_type = coding_FFmpeg;
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
#include "meta.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
|
static STREAMFILE* setup_sps_streamfile(STREAMFILE *streamfile, off_t subfile_offset, size_t subfile_size, char* extension);
|
||||||
|
|
||||||
|
/* .SPS - Nippon Ichi's RIFF AT3 wrapper [ClaDun (PSP)] */
|
||||||
|
VGMSTREAM * init_vgmstream_sps_n1(STREAMFILE *streamFile) {
|
||||||
|
VGMSTREAM *vgmstream = NULL;
|
||||||
|
STREAMFILE *temp_streamFile = NULL;
|
||||||
|
int type, sample_rate;
|
||||||
|
off_t subfile_offset;
|
||||||
|
size_t subfile_size;
|
||||||
|
|
||||||
|
/* check extensions */
|
||||||
|
if ( !check_extensions(streamFile,"sps"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* mini header */
|
||||||
|
type = read_32bitLE(0x00,streamFile); //todo channels? all known VAG are mono and AT3 stereo
|
||||||
|
subfile_size = read_32bitLE(0x04,streamFile);
|
||||||
|
sample_rate = (uint16_t)read_16bitLE(0x08,streamFile);
|
||||||
|
/* 0x0a/0b: stereo+loop flags? */
|
||||||
|
//num_samples = read_32bitLE(0x0c,streamFile);
|
||||||
|
subfile_offset = 0x10;
|
||||||
|
|
||||||
|
/* init the VGMSTREAM */
|
||||||
|
switch(type) {
|
||||||
|
case 1: /* .vag */
|
||||||
|
temp_streamFile = setup_sps_streamfile(streamFile, subfile_offset, subfile_size, "vag");
|
||||||
|
if (!temp_streamFile) goto fail;
|
||||||
|
|
||||||
|
vgmstream = init_vgmstream_ps2_vag(temp_streamFile);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: /* .at3 */
|
||||||
|
temp_streamFile = setup_sps_streamfile(streamFile, subfile_offset, subfile_size, "at3");
|
||||||
|
if (!temp_streamFile) goto fail;
|
||||||
|
|
||||||
|
vgmstream = init_vgmstream_riff(temp_streamFile);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
//VGM_LOG(vgmstream->num_samples != num_samples,
|
||||||
|
// "SPS: sps num_samples and subfile num_samples don't match\n");
|
||||||
|
//vgmstream->num_samples = num_samples; //todo adjusted for MAIATRAC3
|
||||||
|
vgmstream->sample_rate = sample_rate; /* .vag header doesn't match */
|
||||||
|
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static STREAMFILE* setup_sps_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, char* extension) {
|
||||||
|
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||||
|
|
||||||
|
/* setup subfile */
|
||||||
|
new_streamFile = open_wrap_streamfile(streamFile);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,extension);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
return temp_streamFile;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -4,20 +4,19 @@
|
||||||
|
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
#ifdef VGM_USE_VORBIS
|
||||||
static void scd_ogg_decrypt_v2_callback(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read);
|
static void scd_ogg_v2_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource);
|
||||||
static void scd_ogg_decrypt_v3_callback(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read);
|
static void scd_ogg_v3_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* SCD - Square-Enix console games (FF XIII, XIV) */
|
/* SCD - Square-Enix games (FF XIII, XIV) */
|
||||||
VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
char filename[PATH_LIMIT];
|
char filename[PATH_LIMIT];
|
||||||
off_t start_offset, tables_offset, headers_offset, meta_offset, post_meta_offset;
|
off_t start_offset, tables_offset, meta_offset, post_meta_offset;
|
||||||
int headers_entries;
|
int32_t stream_size, subheader_size, loop_start, loop_end;
|
||||||
int32_t stream_size, loop_start, loop_end;
|
|
||||||
|
|
||||||
int target_stream = streamFile->stream_index;
|
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||||
int loop_flag = 0, channel_count, codec_id, sample_rate;
|
int loop_flag = 0, channel_count, codec, sample_rate;
|
||||||
int aux_chunk_count;
|
int aux_chunk_count;
|
||||||
|
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||||
|
@ -25,32 +24,34 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* check extension, case insensitive */
|
||||||
if ( !check_extensions(streamFile, "scd") ) goto fail;
|
if ( !check_extensions(streamFile, "scd") )
|
||||||
|
goto fail;
|
||||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||||
|
|
||||||
/* SEDB */
|
/** main header **/
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x53454442) goto fail;
|
if (read_32bitBE(0x00,streamFile) != 0x53454442 && /* "SEDB" */
|
||||||
/* SSCF */
|
read_32bitBE(0x04,streamFile) != 0x53534346) /* "SSCF" */
|
||||||
if (read_32bitBE(0x04,streamFile) != 0x53534346) goto fail;
|
goto fail;
|
||||||
|
|
||||||
/** main header section **/
|
|
||||||
if (read_32bitBE(0x08,streamFile) == 2 || /* version 2 BE, as seen in FFXIII demo for PS3 */
|
if (read_32bitBE(0x08,streamFile) == 2 || /* version 2 BE, as seen in FFXIII demo for PS3 */
|
||||||
read_32bitBE(0x08,streamFile) == 3) { /* version 3 BE, as seen in FFXIII for PS3 */
|
read_32bitBE(0x08,streamFile) == 3) { /* version 3 BE, as seen in FFXIII for PS3 */
|
||||||
|
//size_offset = 0x14;
|
||||||
read_32bit = read_32bitBE;
|
read_32bit = read_32bitBE;
|
||||||
read_16bit = read_16bitBE;
|
read_16bit = read_16bitBE;
|
||||||
//size_offset = 0x14;
|
}
|
||||||
} else if (read_32bitLE(0x08,streamFile) == 3 || /* version 2/3 LE, as seen in FFXIV for PC (and others?) */
|
else if (read_32bitLE(0x08,streamFile) == 2 || /* version 2/3 LE, as seen in FFXIV for PC (and others) */
|
||||||
read_32bitLE(0x08,streamFile) == 2) {
|
read_32bitLE(0x08,streamFile) == 3) {
|
||||||
|
//size_offset = 0x10;
|
||||||
read_32bit = read_32bitLE;
|
read_32bit = read_32bitLE;
|
||||||
read_16bit = read_16bitLE;
|
read_16bit = read_16bitLE;
|
||||||
//size_offset = 0x10;
|
}
|
||||||
} else goto fail;
|
else {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* 0x0c: probably 0=LE, 1=BE */
|
/* 0x0c: probably 0=LE, 1=BE */
|
||||||
/* 0x0d: unk (always 0x04) */
|
/* 0x0d: unknown (always 0x04) */
|
||||||
tables_offset = read_16bit(0xe,streamFile);
|
tables_offset = read_16bit(0x0e,streamFile); /* usually 0x30 or 0x20 */
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* never mind, FFXIII music_68tak.ps3.scd is 0x80 shorter */
|
/* never mind, FFXIII music_68tak.ps3.scd is 0x80 shorter */
|
||||||
|
@ -59,43 +60,66 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||||
goto fail;
|
goto fail;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** offset tables **/
|
|
||||||
/* 0x00: table1_unknown entries */
|
|
||||||
/* 0x02: table2_unknown entries */
|
|
||||||
/* 0x04: table_headers entries */
|
|
||||||
/* 0x06: unknown (varies) */
|
|
||||||
/* 0x08: table1_unknown start offset */
|
|
||||||
/* 0x0c: table_headers start offset */
|
|
||||||
/* 0x10: table2_unknown start offset */
|
|
||||||
/* 0x14: unknown (0x0) */
|
|
||||||
/* 0x18: unknown offset */
|
|
||||||
/* 0x1c: unknown (0x0) */
|
|
||||||
headers_entries = read_16bit(tables_offset+0x04,streamFile);
|
|
||||||
if (target_stream == 0) target_stream = 1; /* auto: default to 1 */
|
|
||||||
if (target_stream < 0 || target_stream > headers_entries || headers_entries < 1) goto fail;
|
|
||||||
|
|
||||||
headers_offset = read_32bit(tables_offset+0x0c,streamFile);
|
/** offset tables **/
|
||||||
|
/* 0x00(2): table1/4 (unknown) entries */
|
||||||
|
/* 0x02(2): table2 (unknown) entries */
|
||||||
|
/* 0x04(2): table3 (headers) entries */
|
||||||
|
/* 0x06(2): unknown, varies even for clone files */
|
||||||
|
|
||||||
/** header table entries (each is an uint32_t offset to stream header) **/
|
/* (implicit: table1 starts at 0x20) */
|
||||||
meta_offset = read_32bit(headers_offset + (target_stream-1)*4,streamFile);
|
/* 0x08: table2 (unknown) start offset */
|
||||||
|
/* 0x0c: table3 (headers) start offset */
|
||||||
|
/* 0x10: table4 (unknown) start offset */
|
||||||
|
/* 0x14: always null? */
|
||||||
|
/* 0x18: table5? (unknown) start offset? */
|
||||||
|
/* 0x1c: unknown, often null */
|
||||||
|
/* each table entry is an uint32_t offset */
|
||||||
|
/* if a table isn't present entries is 0 and offset points to next table */
|
||||||
|
|
||||||
|
/* find meta_offset in table3 (headers) and total subsongs */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int headers_entries = read_16bit(tables_offset+0x04,streamFile);
|
||||||
|
off_t headers_offset = read_32bit(tables_offset+0x0c,streamFile);
|
||||||
|
|
||||||
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
|
total_subsongs = 0;
|
||||||
|
meta_offset = 0;
|
||||||
|
|
||||||
|
/* manually find subsongs as entries can be dummy (ex. sfx banks in FF XIV or FF Type-0) */
|
||||||
|
for (i = 0; i < headers_entries; i++) {
|
||||||
|
off_t header_offset = read_32bit(headers_offset + i*0x04,streamFile);
|
||||||
|
|
||||||
|
if (read_32bit(header_offset+0x0c,streamFile) == -1)
|
||||||
|
continue; /* codec -1 when dummy */
|
||||||
|
|
||||||
|
total_subsongs++;
|
||||||
|
if (!meta_offset && total_subsongs == target_subsong)
|
||||||
|
meta_offset = header_offset;
|
||||||
|
}
|
||||||
|
if (meta_offset == 0) goto fail;
|
||||||
|
/* SCD can contain 0 entries too */
|
||||||
|
}
|
||||||
|
|
||||||
/** stream header **/
|
/** stream header **/
|
||||||
stream_size = read_32bit(meta_offset+0x00,streamFile);
|
stream_size = read_32bit(meta_offset+0x00,streamFile);
|
||||||
channel_count = read_32bit(meta_offset+0x04,streamFile);
|
channel_count = read_32bit(meta_offset+0x04,streamFile);
|
||||||
sample_rate = read_32bit(meta_offset+0x08,streamFile);
|
sample_rate = read_32bit(meta_offset+0x08,streamFile);
|
||||||
codec_id = read_32bit(meta_offset+0x0c,streamFile);
|
codec = read_32bit(meta_offset+0x0c,streamFile);
|
||||||
|
|
||||||
loop_start = read_32bit(meta_offset+0x10,streamFile);
|
loop_start = read_32bit(meta_offset+0x10,streamFile);
|
||||||
loop_end = read_32bit(meta_offset+0x14,streamFile);
|
loop_end = read_32bit(meta_offset+0x14,streamFile);
|
||||||
loop_flag = (loop_end > 0);
|
subheader_size = read_32bit(meta_offset+0x18,streamFile);
|
||||||
|
|
||||||
post_meta_offset = meta_offset + 0x20;
|
|
||||||
start_offset = post_meta_offset + read_32bit(meta_offset+0x18,streamFile);
|
|
||||||
aux_chunk_count = read_32bit(meta_offset+0x1c,streamFile);
|
aux_chunk_count = read_32bit(meta_offset+0x1c,streamFile);
|
||||||
/* 0x01e(e): unknown, seen in some FF XIV sfx (IMA) */
|
/* 0x01e(2): unknown, seen in some FF XIV sfx (MSADPCM) */
|
||||||
|
|
||||||
|
loop_flag = (loop_end > 0);
|
||||||
|
post_meta_offset = meta_offset + 0x20;
|
||||||
|
start_offset = post_meta_offset + subheader_size;
|
||||||
|
|
||||||
/* only "MARK" chunk is known (some FF XIV PS3 have "STBL" but it's not counted) */
|
/* only "MARK" chunk is known (some FF XIV PS3 have "STBL" but it's not counted) */
|
||||||
if (aux_chunk_count > 1 && aux_chunk_count < 0xFFFF) { /* some FF XIV Heavensward IMA sfx has 0x01000000 */
|
if (aux_chunk_count > 1 && aux_chunk_count < 0xFFFF) { /* some FF XIV Heavensward IMA sfx have 0x01000000 */
|
||||||
VGM_LOG("SCD: unknown aux chunk count %i\n", aux_chunk_count);
|
VGM_LOG("SCD: unknown aux chunk count %i\n", aux_chunk_count);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -107,73 +131,52 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
#ifdef VGM_USE_VORBIS
|
||||||
/* special case using init_vgmstream_ogg_vorbis with callbacks */
|
/* special case using init_vgmstream_ogg_vorbis */
|
||||||
if (codec_id == 0x06) {
|
if (codec == 0x06) {
|
||||||
VGMSTREAM * result = NULL;
|
uint8_t ogg_version, ogg_byte;
|
||||||
uint32_t seek_table_size, vorb_header_size;
|
|
||||||
uint8_t xor_version, xor_byte;
|
|
||||||
vgm_vorbis_info_t inf = {0};
|
vgm_vorbis_info_t inf = {0};
|
||||||
|
|
||||||
inf.loop_start = loop_start;
|
|
||||||
inf.loop_end = loop_end;
|
|
||||||
inf.loop_flag = loop_flag;
|
|
||||||
inf.loop_end_found = loop_flag;
|
|
||||||
inf.loop_length_found = 0;
|
|
||||||
inf.layout_type = layout_ogg_vorbis;
|
inf.layout_type = layout_ogg_vorbis;
|
||||||
inf.meta_type = meta_SQEX_SCD;
|
inf.meta_type = meta_SQEX_SCD;
|
||||||
|
inf.total_subsongs = total_subsongs;
|
||||||
|
/* loop values are in bytes, let init_vgmstream_ogg_vorbis find loop comments instead */
|
||||||
|
|
||||||
/* the following could be simplified but it's not clear what field signals that seek table exists
|
ogg_version = read_8bit(post_meta_offset + 0x00, streamFile);
|
||||||
* (seems that encrypted = always seek table, but maybe post_meta_offset+0x01 = 0x20) */
|
/* 0x01(1): 0x20 in v2/3, this ogg miniheader size? */
|
||||||
|
ogg_byte = read_8bit(post_meta_offset + 0x02, streamFile);
|
||||||
|
/* 0x03(1): ? in v3 */
|
||||||
|
|
||||||
/* try regular Ogg with default values */
|
if (ogg_version == 0) { /* 0x10? header, then custom Vorbis header before regular Ogg (FF XIV PC v1) */
|
||||||
{
|
inf.stream_size = stream_size;
|
||||||
result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf);
|
|
||||||
if (result != NULL)
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
else { /* 0x20 header, then seek table */
|
||||||
|
size_t seek_table_size = read_32bit(post_meta_offset+0x10, streamFile);
|
||||||
|
size_t vorb_header_size = read_32bit(post_meta_offset+0x14, streamFile);
|
||||||
|
/* 0x18(4): ? (can be 0) */
|
||||||
|
|
||||||
/* skip seek table and try regular Ogg again */
|
if ((post_meta_offset-meta_offset) + seek_table_size + vorb_header_size != subheader_size)
|
||||||
{
|
goto fail;
|
||||||
seek_table_size = read_32bit(post_meta_offset+0x10, streamFile);
|
|
||||||
vorb_header_size = read_32bit(post_meta_offset+0x14, streamFile);
|
|
||||||
if ((post_meta_offset-meta_offset) + seek_table_size + vorb_header_size != read_32bit(meta_offset+0x18, streamFile)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
start_offset = post_meta_offset + 0x20 + seek_table_size;
|
inf.stream_size = vorb_header_size + stream_size;
|
||||||
|
start_offset = post_meta_offset + 0x20 + seek_table_size; /* subheader_size skips vorb_header */
|
||||||
|
|
||||||
result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf);
|
if (ogg_version == 2) { /* header is XOR'ed using byte (FF XIV PC) */
|
||||||
if (result != NULL)
|
inf.decryption_callback = scd_ogg_v2_decryption_callback;
|
||||||
return result;
|
inf.scd_xor = ogg_byte;
|
||||||
}
|
|
||||||
|
|
||||||
/* try encrypted Ogg (with seek table already skipped) */
|
|
||||||
{
|
|
||||||
xor_version = read_8bit(post_meta_offset + 0x00, streamFile);
|
|
||||||
xor_byte = read_8bit(post_meta_offset + 0x02, streamFile);
|
|
||||||
if (xor_byte == 0)
|
|
||||||
return NULL; /* not actually encrypted, happens but should be handled above */
|
|
||||||
|
|
||||||
if (xor_version == 2) { /* header is XOR'ed using byte */
|
|
||||||
inf.decryption_enabled = 1;
|
|
||||||
inf.decryption_callback = scd_ogg_decrypt_v2_callback;
|
|
||||||
inf.scd_xor = xor_byte;
|
|
||||||
inf.scd_xor_length = vorb_header_size;
|
inf.scd_xor_length = vorb_header_size;
|
||||||
}
|
}
|
||||||
else if (xor_version == 3) { /* full file is XOR'ed using table */
|
else if (ogg_version == 3) { /* file is XOR'ed using table (FF XIV Heavensward PC) */
|
||||||
inf.decryption_enabled = 1;
|
inf.decryption_callback = scd_ogg_v3_decryption_callback;
|
||||||
inf.decryption_callback = scd_ogg_decrypt_v3_callback;
|
inf.scd_xor = stream_size & 0xFF; /* ogg_byte not used? */
|
||||||
inf.scd_xor = stream_size & 0xFF; /* xor_byte is not used? (also there is data at +0x03) */
|
inf.scd_xor_length = vorb_header_size + stream_size;
|
||||||
inf.scd_xor_length = stream_size;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
VGM_LOG("SCD: unknown encryption 0x%x\n", xor_version);
|
VGM_LOG("SCD: unknown ogg_version 0x%x\n", ogg_version);
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hope this works */
|
|
||||||
return init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* actual Ogg init */
|
||||||
|
return init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -182,21 +185,33 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
/* fill in the vital statistics */
|
|
||||||
vgmstream->channels = channel_count;
|
|
||||||
vgmstream->sample_rate = sample_rate;
|
vgmstream->sample_rate = sample_rate;
|
||||||
vgmstream->num_streams = headers_entries;
|
vgmstream->num_streams = total_subsongs;
|
||||||
|
vgmstream->stream_size = stream_size;
|
||||||
vgmstream->meta_type = meta_SQEX_SCD;
|
vgmstream->meta_type = meta_SQEX_SCD;
|
||||||
|
|
||||||
switch (codec_id) {
|
switch (codec) {
|
||||||
case 0x01: /* PCM */
|
case 0x01: /* PCM */
|
||||||
vgmstream->coding_type = coding_PCM16_int;
|
vgmstream->coding_type = coding_PCM16LE;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->num_samples = stream_size / 2 / channel_count;
|
vgmstream->interleave_block_size = 0x02;
|
||||||
|
|
||||||
|
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16);
|
||||||
if (loop_flag) {
|
if (loop_flag) {
|
||||||
vgmstream->loop_start_sample = loop_start / 2 / channel_count;
|
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, channel_count, 16);
|
||||||
vgmstream->loop_end_sample = loop_end / 2 / channel_count;
|
vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_end, channel_count, 16);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x03: /* PS-ADPCM [Final Fantasy Type-0] */
|
||||||
|
vgmstream->coding_type = coding_PSX;
|
||||||
|
vgmstream->layout_type = layout_interleave;
|
||||||
|
vgmstream->interleave_block_size = 0x10;
|
||||||
|
|
||||||
|
vgmstream->num_samples = ps_bytes_to_samples(stream_size, channel_count);
|
||||||
|
if (loop_flag) {
|
||||||
|
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channel_count);
|
||||||
|
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, channel_count);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -234,6 +249,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||||
vgmstream->coding_type = coding_MSADPCM;
|
vgmstream->coding_type = coding_MSADPCM;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
vgmstream->interleave_block_size = read_16bit(post_meta_offset+0x0c,streamFile);
|
vgmstream->interleave_block_size = read_16bit(post_meta_offset+0x0c,streamFile);
|
||||||
|
/* in post_meta_offset is a WAVEFORMATEX (including coefs and all) */
|
||||||
|
|
||||||
vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, vgmstream->interleave_block_size, vgmstream->channels);
|
vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, vgmstream->interleave_block_size, vgmstream->channels);
|
||||||
if (loop_flag) {
|
if (loop_flag) {
|
||||||
|
@ -324,7 +340,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x0E: { /* ATRAC3plus [Lord of Arcana (PSP)] */
|
case 0x0E: { /* ATRAC3/ATRAC3plus [Lord of Arcana (PSP), Final Fantasy Type-0] */
|
||||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||||
|
|
||||||
/* full RIFF header at start_offset/post_meta_offset (same) */
|
/* full RIFF header at start_offset/post_meta_offset (same) */
|
||||||
|
@ -357,8 +373,9 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
case -1: /* used for dummy entries */
|
||||||
default:
|
default:
|
||||||
VGM_LOG("SCD: unknown codec_id 0x%x\n", codec_id);
|
VGM_LOG("SCD: unknown codec 0x%x\n", codec);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,9 +392,14 @@ fail:
|
||||||
|
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
#ifdef VGM_USE_VORBIS
|
||||||
static void scd_ogg_decrypt_v2_callback(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read) {
|
static void scd_ogg_v2_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
|
||||||
|
size_t bytes_read = size*nmemb;
|
||||||
ogg_vorbis_streamfile * ov_streamfile = (ogg_vorbis_streamfile*)datasource;
|
ogg_vorbis_streamfile * ov_streamfile = (ogg_vorbis_streamfile*)datasource;
|
||||||
|
|
||||||
|
/* no encryption, sometimes happens */
|
||||||
|
if (ov_streamfile->scd_xor == 0x00)
|
||||||
|
return;
|
||||||
|
|
||||||
/* header is XOR'd with a constant byte */
|
/* header is XOR'd with a constant byte */
|
||||||
if (ov_streamfile->offset < ov_streamfile->scd_xor_length) {
|
if (ov_streamfile->offset < ov_streamfile->scd_xor_length) {
|
||||||
int i, num_crypt;
|
int i, num_crypt;
|
||||||
|
@ -392,9 +414,9 @@ static void scd_ogg_decrypt_v2_callback(void *ptr, size_t size, size_t nmemb, vo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scd_ogg_decrypt_v3_callback(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read) {
|
static void scd_ogg_v3_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
|
||||||
/* V3 decryption table found in the .exe */
|
/* V3 decryption table found in the .exe of FF XIV Heavensward */
|
||||||
static const uint8_t scd_ogg_v3_lookuptable[256] = { /* FF XIV Heavensward */
|
static const uint8_t scd_ogg_v3_lookuptable[256] = {
|
||||||
0x3A, 0x32, 0x32, 0x32, 0x03, 0x7E, 0x12, 0xF7, 0xB2, 0xE2, 0xA2, 0x67, 0x32, 0x32, 0x22, 0x32, // 00-0F
|
0x3A, 0x32, 0x32, 0x32, 0x03, 0x7E, 0x12, 0xF7, 0xB2, 0xE2, 0xA2, 0x67, 0x32, 0x32, 0x22, 0x32, // 00-0F
|
||||||
0x32, 0x52, 0x16, 0x1B, 0x3C, 0xA1, 0x54, 0x7B, 0x1B, 0x97, 0xA6, 0x93, 0x1A, 0x4B, 0xAA, 0xA6, // 10-1F
|
0x32, 0x52, 0x16, 0x1B, 0x3C, 0xA1, 0x54, 0x7B, 0x1B, 0x97, 0xA6, 0x93, 0x1A, 0x4B, 0xAA, 0xA6, // 10-1F
|
||||||
0x7A, 0x7B, 0x1B, 0x97, 0xA6, 0xF7, 0x02, 0xBB, 0xAA, 0xA6, 0xBB, 0xF7, 0x2A, 0x51, 0xBE, 0x03, // 20-2F
|
0x7A, 0x7B, 0x1B, 0x97, 0xA6, 0xF7, 0x02, 0xBB, 0xAA, 0xA6, 0xBB, 0xF7, 0x2A, 0x51, 0xBE, 0x03, // 20-2F
|
||||||
|
@ -412,23 +434,25 @@ static void scd_ogg_decrypt_v3_callback(void *ptr, size_t size, size_t nmemb, vo
|
||||||
0xE2, 0xA2, 0x67, 0x32, 0x32, 0x12, 0x32, 0xB2, 0x32, 0x32, 0x32, 0x32, 0x75, 0xA3, 0x26, 0x7B, // E0-EF
|
0xE2, 0xA2, 0x67, 0x32, 0x32, 0x12, 0x32, 0xB2, 0x32, 0x32, 0x32, 0x32, 0x75, 0xA3, 0x26, 0x7B, // E0-EF
|
||||||
0x83, 0x26, 0xF9, 0x83, 0x2E, 0xFF, 0xE3, 0x16, 0x7D, 0xC0, 0x1E, 0x63, 0x21, 0x07, 0xE3, 0x01, // F0-FF
|
0x83, 0x26, 0xF9, 0x83, 0x2E, 0xFF, 0xE3, 0x16, 0x7D, 0xC0, 0x1E, 0x63, 0x21, 0x07, 0xE3, 0x01, // F0-FF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
size_t bytes_read = size*nmemb;
|
||||||
ogg_vorbis_streamfile *ov_streamfile = (ogg_vorbis_streamfile*)datasource;
|
ogg_vorbis_streamfile *ov_streamfile = (ogg_vorbis_streamfile*)datasource;
|
||||||
|
|
||||||
/* file is XOR'd with a table (algorithm and table by Ioncannon) */
|
/* file is XOR'd with a table (algorithm and table by Ioncannon) */
|
||||||
if (ov_streamfile->offset < ov_streamfile->scd_xor_length) {
|
{ //if (ov_streamfile->offset < ov_streamfile->scd_xor_length)
|
||||||
int i, num_crypt;
|
int i, num_crypt;
|
||||||
uint8_t byte1, byte2, xorByte;
|
uint8_t byte1, byte2, xor_byte;
|
||||||
|
|
||||||
num_crypt = bytes_read;
|
num_crypt = bytes_read;
|
||||||
byte1 = ov_streamfile->scd_xor & 0x7F;
|
byte1 = ov_streamfile->scd_xor & 0x7F;
|
||||||
byte2 = ov_streamfile->scd_xor & 0x3F;
|
byte2 = ov_streamfile->scd_xor & 0x3F;
|
||||||
|
|
||||||
for (i = 0; i < num_crypt; i++) {
|
for (i = 0; i < num_crypt; i++) {
|
||||||
xorByte = scd_ogg_v3_lookuptable[(byte2 + ov_streamfile->offset + i) & 0xFF];
|
xor_byte = scd_ogg_v3_lookuptable[(byte2 + ov_streamfile->offset + i) & 0xFF];
|
||||||
xorByte &= 0xFF;
|
xor_byte &= 0xFF;
|
||||||
xorByte ^= ((uint8_t*)ptr)[i];
|
xor_byte ^= ((uint8_t*)ptr)[i];
|
||||||
xorByte ^= byte1;
|
xor_byte ^= byte1;
|
||||||
((uint8_t*)ptr)[i] = (uint8_t)xorByte;
|
((uint8_t*)ptr)[i] = (uint8_t)xor_byte;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,273 @@
|
||||||
|
#include "meta.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
|
|
||||||
|
static STREAMFILE* setup_sead_hca_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size);
|
||||||
|
|
||||||
|
/* SABF/MABF - Square Enix's "Sead" audio games [Dragon Quest Builders (PS3), Dissidia Opera Omnia (mobile), FF XV (PS4)] */
|
||||||
|
VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) {
|
||||||
|
VGMSTREAM * vgmstream = NULL;
|
||||||
|
off_t start_offset, mtrl_offset, meta_offset, post_meta_offset; //, info_offset, name_offset = 0;
|
||||||
|
size_t stream_size, subheader_size; //, name_size = 0;
|
||||||
|
|
||||||
|
int loop_flag = 0, channel_count, codec, sample_rate, loop_start, loop_end;
|
||||||
|
int is_sab = 0, is_mab = 0;
|
||||||
|
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||||
|
|
||||||
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||||
|
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/* check extensions (.sab: sound/bgm, .mab: music, .sbin: Dissidia Opera Omnia .sab) */
|
||||||
|
if ( !check_extensions(streamFile,"sab,mab,sbin"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
|
/** main header **/
|
||||||
|
if (read_32bitBE(0x00,streamFile) == 0x73616266) { /* "sabf" */
|
||||||
|
is_sab = 1;
|
||||||
|
} else if (read_32bitBE(0x00,streamFile) == 0x6D616266) { /* "mabf" */
|
||||||
|
is_mab = 1;
|
||||||
|
} else {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (read_8bit(0x04,streamFile) != 0x02) /* version? */
|
||||||
|
// goto fail;
|
||||||
|
/* 0x04(1): version? (usually 0x02, rarely 0x01, ex FF XV title) */
|
||||||
|
/* 0x05(1): 0x00/01? */
|
||||||
|
/* 0x06(2): chunk size? (usually 0x10, rarely 0x20) */
|
||||||
|
if (read_16bitBE(0x06,streamFile) < 0x100) { /* use size as no apparent flag */
|
||||||
|
read_32bit = read_32bitBE;
|
||||||
|
read_16bit = read_16bitBE;
|
||||||
|
} else {
|
||||||
|
read_32bit = read_32bitLE;
|
||||||
|
read_16bit = read_16bitLE;
|
||||||
|
}
|
||||||
|
/* 0x08(1): ?, 0x09(1): ?, 0x0a(2): ? */
|
||||||
|
if (read_32bit(0x0c,streamFile) != get_streamfile_size(streamFile))
|
||||||
|
goto fail;
|
||||||
|
/* 0x10(10): file descriptor ("BGM", "Music", "SE", etc) */
|
||||||
|
|
||||||
|
|
||||||
|
/** offset tables **/
|
||||||
|
if (is_sab) {
|
||||||
|
if (read_32bitBE(0x20,streamFile) != 0x736E6420) goto fail; /* "snd " (info) */
|
||||||
|
if (read_32bitBE(0x30,streamFile) != 0x73657120) goto fail; /* "seq " (unknown) */
|
||||||
|
if (read_32bitBE(0x40,streamFile) != 0x74726B20) goto fail; /* "trk " (unknown) */
|
||||||
|
if (read_32bitBE(0x50,streamFile) != 0x6D74726C) goto fail; /* "mtrl" (headers/streams) */
|
||||||
|
//info_offset = read_32bit(0x28,streamFile);
|
||||||
|
//seq_offset = read_32bit(0x38,streamFile);
|
||||||
|
//trk_offset = read_32bit(0x48,streamFile);
|
||||||
|
mtrl_offset = read_32bit(0x58,streamFile);
|
||||||
|
}
|
||||||
|
else if (is_mab) {
|
||||||
|
if (read_32bitBE(0x20,streamFile) != 0x6D757363) goto fail; /* "musc" (info) */
|
||||||
|
if (read_32bitBE(0x30,streamFile) != 0x696E7374) goto fail; /* "inst" (unknown) */
|
||||||
|
if (read_32bitBE(0x40,streamFile) != 0x6D74726C) goto fail; /* "mtrl" (headers/streams) */
|
||||||
|
//info_offset = read_32bit(0x28,streamFile);
|
||||||
|
//inst_offset = read_32bit(0x38,streamFile);
|
||||||
|
mtrl_offset = read_32bit(0x48,streamFile);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
/* each section starts with:
|
||||||
|
* 0x00(2): 0x00/01?, 0x02: size? (0x10), 0x04(2): entries, 0x06+: padded to 0x10
|
||||||
|
* 0x10+0x04*entry: offset from section start, also padded to 0x10 at the end */
|
||||||
|
|
||||||
|
/* find meta_offset in mtrl and total subsongs */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int entries = read_16bit(mtrl_offset+0x04,streamFile);
|
||||||
|
off_t entries_offset = mtrl_offset + 0x10;
|
||||||
|
|
||||||
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
|
total_subsongs = 0;
|
||||||
|
meta_offset = 0;
|
||||||
|
|
||||||
|
/* manually find subsongs as entries can be dummy (ex. sfx banks in Dissidia Opera Omnia) */
|
||||||
|
for (i = 0; i < entries; i++) {
|
||||||
|
off_t entry_offset = mtrl_offset + read_32bit(entries_offset + i*0x04,streamFile);
|
||||||
|
|
||||||
|
if (read_8bit(entry_offset+0x05,streamFile) == 0)
|
||||||
|
continue; /* codec 0 when dummy */
|
||||||
|
|
||||||
|
total_subsongs++;
|
||||||
|
if (!meta_offset && total_subsongs == target_subsong)
|
||||||
|
meta_offset = entry_offset;
|
||||||
|
}
|
||||||
|
if (meta_offset == 0) goto fail;
|
||||||
|
/* SAB can contain 0 entries too */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** stream header **/
|
||||||
|
/* 0x00(2): 0x00/01? */
|
||||||
|
/* 0x02(2): base entry size? (0x20) */
|
||||||
|
channel_count = read_8bit(meta_offset+0x04,streamFile);
|
||||||
|
codec = read_8bit(meta_offset+0x05,streamFile);
|
||||||
|
//entry_id = read_16bit(meta_offset+0x06,streamFile);
|
||||||
|
sample_rate = read_32bit(meta_offset+0x08,streamFile);
|
||||||
|
loop_start = read_32bit(meta_offset+0x0c,streamFile); /* in samples but usually ignored */
|
||||||
|
|
||||||
|
loop_end = read_32bit(meta_offset+0x10,streamFile);
|
||||||
|
subheader_size = read_32bit(meta_offset+0x14,streamFile); /* including subfile header */
|
||||||
|
stream_size = read_32bit(meta_offset+0x18,streamFile); /* not including subfile header */
|
||||||
|
/* 0x1c: null? */
|
||||||
|
|
||||||
|
loop_flag = (loop_end > 0);
|
||||||
|
post_meta_offset = meta_offset + 0x20;
|
||||||
|
|
||||||
|
|
||||||
|
/** info section (get stream name) **/
|
||||||
|
//if (is_sab) { //todo load name based on entry id
|
||||||
|
/* "snd ": unknown flags/sizes and name */
|
||||||
|
/* 0x08(2): file number within descriptor */
|
||||||
|
/* 0x1a(2): base_entry size (-0x10?) */
|
||||||
|
//name_size = read_32bit(snd_offset+0x20,streamFile);
|
||||||
|
//name_offset = snd_offset+0x70;
|
||||||
|
/* 0x24(4): unique id? (referenced in "seq" section) */
|
||||||
|
//}
|
||||||
|
//else if (is_mab) {
|
||||||
|
/* "musc": unknown flags sizes and names, another format */
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
/* build the VGMSTREAM */
|
||||||
|
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
vgmstream->sample_rate = sample_rate;
|
||||||
|
vgmstream->num_streams = total_subsongs;
|
||||||
|
vgmstream->stream_size = stream_size;
|
||||||
|
vgmstream->meta_type = is_sab ? meta_SQEX_SAB : meta_SQEX_MAB;
|
||||||
|
|
||||||
|
switch(codec) {
|
||||||
|
|
||||||
|
case 0x02: { /* MSADPCM [Dragon Quest Builders (Vita) sfx] */
|
||||||
|
start_offset = post_meta_offset + subheader_size;
|
||||||
|
|
||||||
|
/* 0x00 (2): null?, 0x02(2): entry size? */
|
||||||
|
vgmstream->coding_type = coding_MSADPCM;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
vgmstream->interleave_block_size = read_16bit(post_meta_offset+0x04,streamFile);
|
||||||
|
|
||||||
|
/* much like AKBs, there are slightly different loop values here, probably more accurate
|
||||||
|
* (if no loop, loop_end doubles as num_samples) */
|
||||||
|
vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, vgmstream->interleave_block_size, vgmstream->channels);
|
||||||
|
vgmstream->loop_start_sample = read_32bit(post_meta_offset+0x08, streamFile); //loop_start
|
||||||
|
vgmstream->loop_end_sample = read_32bit(post_meta_offset+0x0c, streamFile); //loop_end
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef VGM_USE_ATRAC9
|
||||||
|
case 0x04: { /* ATRAC9 [Dragon Quest Builders (Vita), Final Fantaxy XV (PS4)] */
|
||||||
|
atrac9_config cfg = {0};
|
||||||
|
|
||||||
|
start_offset = post_meta_offset + subheader_size;
|
||||||
|
/* post header has various typical ATRAC9 values */
|
||||||
|
cfg.channels = vgmstream->channels;
|
||||||
|
cfg.config_data = read_32bit(post_meta_offset+0x0c,streamFile);
|
||||||
|
cfg.encoder_delay = read_32bit(post_meta_offset+0x18,streamFile);
|
||||||
|
VGM_LOG("1\n");
|
||||||
|
vgmstream->codec_data = init_atrac9(&cfg);
|
||||||
|
if (!vgmstream->codec_data) goto fail;
|
||||||
|
vgmstream->coding_type = coding_ATRAC9;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
VGM_LOG("2\n");
|
||||||
|
vgmstream->sample_rate = read_32bit(post_meta_offset+0x1c,streamFile); /* SAB's sample rate can be different but it's ignored */
|
||||||
|
vgmstream->num_samples = read_32bit(post_meta_offset+0x10,streamFile); /* loop values above are also weird and ignored */
|
||||||
|
vgmstream->loop_start_sample = read_32bit(post_meta_offset+0x20, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_start
|
||||||
|
vgmstream->loop_end_sample = read_32bit(post_meta_offset+0x24, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_end
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VGM_USE_MPEG
|
||||||
|
case 0x06: { /* MSF subfile (MPEG mode) [Dragon Quest Builders (PS3)] */
|
||||||
|
mpeg_codec_data *mpeg_data = NULL;
|
||||||
|
mpeg_custom_config cfg = {0};
|
||||||
|
|
||||||
|
start_offset = post_meta_offset + subheader_size;
|
||||||
|
/* post header is a proper MSF, but sample rate/loops are ignored in favor of SAB's */
|
||||||
|
|
||||||
|
mpeg_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_STANDARD, &cfg);
|
||||||
|
if (!mpeg_data) goto fail;
|
||||||
|
vgmstream->codec_data = mpeg_data;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
|
vgmstream->num_samples = mpeg_bytes_to_samples(stream_size, mpeg_data);
|
||||||
|
vgmstream->loop_start_sample = loop_start;
|
||||||
|
vgmstream->loop_end_sample = loop_end;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case 0x07: { /* HCA subfile [Dissidia Opera Omnia (Mobile), Final Fantaxy XV (PS4)] */
|
||||||
|
//todo there is no easy way to use the HCA decoder; try subfile hack for now
|
||||||
|
VGMSTREAM *temp_vgmstream = NULL;
|
||||||
|
STREAMFILE *temp_streamFile = NULL;
|
||||||
|
off_t subfile_offset = post_meta_offset + 0x10;
|
||||||
|
size_t subfile_size = stream_size + subheader_size - 0x10;
|
||||||
|
/* post header has 0x10 unknown + HCA header */
|
||||||
|
|
||||||
|
|
||||||
|
temp_streamFile = setup_sead_hca_streamfile(streamFile, subfile_offset, subfile_size);
|
||||||
|
if (!temp_streamFile) goto fail;
|
||||||
|
|
||||||
|
temp_vgmstream = init_vgmstream_hca(temp_streamFile);
|
||||||
|
if (temp_vgmstream) {
|
||||||
|
/* loops can be slightly different (~1000 samples) but probably HCA's are more accurate */
|
||||||
|
temp_vgmstream->num_streams = vgmstream->num_streams;
|
||||||
|
temp_vgmstream->stream_size = vgmstream->stream_size;
|
||||||
|
temp_vgmstream->meta_type = vgmstream->meta_type;
|
||||||
|
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return temp_vgmstream;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x00: /* dummy entry */
|
||||||
|
default:
|
||||||
|
VGM_LOG("SQEX SEAD: unknown codec %x\n", codec);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open the file for reading */
|
||||||
|
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||||
|
goto fail;
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static STREAMFILE* setup_sead_hca_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size) {
|
||||||
|
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||||
|
|
||||||
|
/* setup subfile */
|
||||||
|
new_streamFile = open_wrap_streamfile(streamFile);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"hca");
|
||||||
|
if (!new_streamFile) goto fail;
|
||||||
|
temp_streamFile = new_streamFile;
|
||||||
|
|
||||||
|
return temp_streamFile;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_streamfile(temp_streamFile);
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -7,13 +7,13 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
STREAMFILE * streamHeader = NULL;
|
STREAMFILE * streamHeader = NULL;
|
||||||
off_t start_offset, chunk_offset, first_offset = 0x60, name_offset = 0;
|
off_t start_offset, chunk_offset, first_offset = 0x60, name_offset = 0;
|
||||||
size_t chunk_size;
|
size_t chunk_size, stream_size = 0;
|
||||||
|
|
||||||
int is_separate;
|
int is_separate;
|
||||||
int loop_flag, channels, codec;
|
int loop_flag, channels, codec;
|
||||||
int sample_rate, num_samples, loop_start_sample, loop_end_sample;
|
int sample_rate, num_samples, loop_start_sample, loop_end_sample;
|
||||||
uint32_t at9_config_data = 0;
|
uint32_t at9_config_data = 0;
|
||||||
int total_streams, target_stream = streamFile->stream_index;
|
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||||
|
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* check extension, case insensitive */
|
||||||
|
@ -38,16 +38,16 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||||
if (!find_chunk_le(streamHeader, 0x57415645,first_offset,0, &chunk_offset,&chunk_size)) goto fail; /* "WAVE" */
|
if (!find_chunk_le(streamHeader, 0x57415645,first_offset,0, &chunk_offset,&chunk_size)) goto fail; /* "WAVE" */
|
||||||
|
|
||||||
/* check multi-streams (usually only in SFX containers) */
|
/* check multi-streams (usually only in SFX containers) */
|
||||||
total_streams = read_32bitLE(chunk_offset+0x04,streamHeader);
|
total_subsongs = read_32bitLE(chunk_offset+0x04,streamHeader);
|
||||||
if (target_stream == 0) target_stream = 1;
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
if (target_stream < 0 || target_stream > total_streams || total_streams < 1) goto fail;
|
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||||
|
|
||||||
/* read stream header */
|
/* read stream header */
|
||||||
{
|
{
|
||||||
off_t table_offset, header_offset, stream_offset;
|
off_t table_offset, header_offset, stream_offset;
|
||||||
|
|
||||||
/* get target offset using table of relative offsets within WAVE */
|
/* get target offset using table of relative offsets within WAVE */
|
||||||
table_offset = chunk_offset + 0x08 + 4*(target_stream-1);
|
table_offset = chunk_offset + 0x08 + 4*(target_subsong-1);
|
||||||
header_offset = table_offset + read_32bitLE(table_offset,streamHeader);
|
header_offset = table_offset + read_32bitLE(table_offset,streamHeader);
|
||||||
|
|
||||||
/* 0x00(4): type/location? (00/01=sxd/RAM?, 02/03=sxd2/stream?) */
|
/* 0x00(4): type/location? (00/01=sxd/RAM?, 02/03=sxd2/stream?) */
|
||||||
|
@ -59,7 +59,7 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||||
num_samples = read_32bitLE(header_offset+0x14,streamHeader);
|
num_samples = read_32bitLE(header_offset+0x14,streamHeader);
|
||||||
loop_start_sample = read_32bitLE(header_offset+0x18,streamHeader);
|
loop_start_sample = read_32bitLE(header_offset+0x18,streamHeader);
|
||||||
loop_end_sample = read_32bitLE(header_offset+0x1c,streamHeader);
|
loop_end_sample = read_32bitLE(header_offset+0x1c,streamHeader);
|
||||||
/* 0x20(4): data size */
|
stream_size = read_32bitLE(header_offset+0x20,streamHeader);
|
||||||
stream_offset = read_32bitLE(header_offset+0x24,streamHeader);
|
stream_offset = read_32bitLE(header_offset+0x24,streamHeader);
|
||||||
|
|
||||||
/* Extra data, variable sized and uses some kind of TLVs (HEVAG's is optional and much smaller).
|
/* Extra data, variable sized and uses some kind of TLVs (HEVAG's is optional and much smaller).
|
||||||
|
@ -100,7 +100,7 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||||
int num_entries = read_16bitLE(chunk_offset+0x04,streamHeader); /* can be bigger than streams */
|
int num_entries = read_16bitLE(chunk_offset+0x04,streamHeader); /* can be bigger than streams */
|
||||||
for (i = 0; i < num_entries; i++) {
|
for (i = 0; i < num_entries; i++) {
|
||||||
uint32_t index = (uint32_t)read_32bitLE(chunk_offset+0x08 + 0x08 + i*0x0c,streamHeader);
|
uint32_t index = (uint32_t)read_32bitLE(chunk_offset+0x08 + 0x08 + i*0x0c,streamHeader);
|
||||||
if (index+1 == target_stream) {
|
if (index+1 == target_subsong) {
|
||||||
name_offset = chunk_offset+0x08 + 0x00 + i*0x0c + read_32bitLE(chunk_offset+0x08 + 0x00 + i*0x0c,streamHeader);
|
name_offset = chunk_offset+0x08 + 0x00 + i*0x0c + read_32bitLE(chunk_offset+0x08 + 0x00 + i*0x0c,streamHeader);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -116,20 +116,27 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||||
vgmstream->num_samples = num_samples;
|
vgmstream->num_samples = num_samples;
|
||||||
vgmstream->loop_start_sample = loop_start_sample;
|
vgmstream->loop_start_sample = loop_start_sample;
|
||||||
vgmstream->loop_end_sample = loop_end_sample;
|
vgmstream->loop_end_sample = loop_end_sample;
|
||||||
vgmstream->num_streams = total_streams;
|
vgmstream->num_streams = total_subsongs;
|
||||||
|
vgmstream->stream_size = stream_size;
|
||||||
vgmstream->meta_type = meta_SXD;
|
vgmstream->meta_type = meta_SXD;
|
||||||
if (name_offset)
|
if (name_offset)
|
||||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamHeader);
|
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamHeader);
|
||||||
|
|
||||||
switch (codec) {
|
switch (codec) {
|
||||||
case 0x21: /* HEVAG */
|
case 0x20: /* PS-ADPCM [Hot Shots Golf: World Invitational (Vita) sfx] */
|
||||||
|
vgmstream->coding_type = coding_PSX;
|
||||||
|
vgmstream->layout_type = layout_interleave;
|
||||||
|
vgmstream->interleave_block_size = 0x10;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: /* HEVAG [Gravity Rush (Vita) sfx] */
|
||||||
vgmstream->coding_type = coding_HEVAG;
|
vgmstream->coding_type = coding_HEVAG;
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = 0x10;
|
vgmstream->interleave_block_size = 0x10;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef VGM_USE_ATRAC9
|
#ifdef VGM_USE_ATRAC9
|
||||||
case 0x42: { /* ATRAC9 */
|
case 0x42: { /* ATRAC9 [Soul Sacrifice (Vita), Freedom Wars (Vita)] */
|
||||||
atrac9_config cfg = {0};
|
atrac9_config cfg = {0};
|
||||||
|
|
||||||
cfg.channels = vgmstream->channels;
|
cfg.channels = vgmstream->channels;
|
||||||
|
@ -142,9 +149,9 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
//case 0x28: /* dummy codec? (found with 0 samples) [Hot Shots Golf: World Invitational (Vita) sfx] */
|
||||||
default:
|
default:
|
||||||
VGM_LOG("SXD: unknown codec 0x%x", codec);
|
VGM_LOG("SXD: unknown codec 0x%x\n", codec);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,7 @@ VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
vgmstream->sample_rate = sb.sample_rate;
|
vgmstream->sample_rate = sb.sample_rate;
|
||||||
vgmstream->num_streams = sb.total_streams;
|
vgmstream->num_streams = sb.total_streams;
|
||||||
|
vgmstream->stream_size = sb.stream_size;
|
||||||
vgmstream->meta_type = meta_UBI_SB;
|
vgmstream->meta_type = meta_UBI_SB;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ VGMSTREAM * init_vgmstream_vxn(STREAMFILE *streamFile) {
|
||||||
int loop_flag = 0, channel_count, codec, sample_rate, block_align, bits, num_samples;
|
int loop_flag = 0, channel_count, codec, sample_rate, block_align, bits, num_samples;
|
||||||
off_t start_offset, stream_offset, chunk_offset, first_offset = 0x00;
|
off_t start_offset, stream_offset, chunk_offset, first_offset = 0x00;
|
||||||
size_t stream_size;
|
size_t stream_size;
|
||||||
int total_streams, target_stream = streamFile->stream_index;
|
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||||
|
|
||||||
/* check extensions */
|
/* check extensions */
|
||||||
if (!check_extensions(streamFile,"vxn"))
|
if (!check_extensions(streamFile,"vxn"))
|
||||||
|
@ -31,13 +31,13 @@ VGMSTREAM * init_vgmstream_vxn(STREAMFILE *streamFile) {
|
||||||
* (the "Plst" and "Rule" chunks may have order info) */
|
* (the "Plst" and "Rule" chunks may have order info) */
|
||||||
if (!find_chunk_le(streamFile, 0x5365676D,first_offset,0, &chunk_offset,NULL)) /* "Segm" */
|
if (!find_chunk_le(streamFile, 0x5365676D,first_offset,0, &chunk_offset,NULL)) /* "Segm" */
|
||||||
goto fail;
|
goto fail;
|
||||||
total_streams = read_32bitLE(chunk_offset+0x00, streamFile);
|
total_subsongs = read_32bitLE(chunk_offset+0x00, streamFile);
|
||||||
if (target_stream == 0) target_stream = 1;
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
if (target_stream < 0 || target_stream > total_streams || total_streams < 1) goto fail;
|
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||||
|
|
||||||
stream_offset = read_32bitLE(chunk_offset+0x04 + (target_stream-1)*0x18 + 0x00, streamFile);
|
stream_offset = read_32bitLE(chunk_offset+0x04 + (target_subsong-1)*0x18 + 0x00, streamFile);
|
||||||
stream_size = read_32bitLE(chunk_offset+0x04 + (target_stream-1)*0x18 + 0x04, streamFile);
|
stream_size = read_32bitLE(chunk_offset+0x04 + (target_subsong-1)*0x18 + 0x04, streamFile);
|
||||||
num_samples = read_32bitLE(chunk_offset+0x04 + (target_stream-1)*0x18 + 0x08, streamFile);
|
num_samples = read_32bitLE(chunk_offset+0x04 + (target_subsong-1)*0x18 + 0x08, streamFile);
|
||||||
|
|
||||||
if (!find_chunk_le(streamFile, 0x44617461,first_offset,0, &chunk_offset,NULL)) /* "Data" */
|
if (!find_chunk_le(streamFile, 0x44617461,first_offset,0, &chunk_offset,NULL)) /* "Data" */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -50,8 +50,8 @@ VGMSTREAM * init_vgmstream_vxn(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
vgmstream->sample_rate = sample_rate;
|
vgmstream->sample_rate = sample_rate;
|
||||||
vgmstream->num_samples = num_samples;
|
vgmstream->num_samples = num_samples;
|
||||||
vgmstream->num_streams = total_streams;
|
vgmstream->num_streams = total_subsongs;
|
||||||
|
vgmstream->stream_size = stream_size;
|
||||||
vgmstream->meta_type = meta_VXN;
|
vgmstream->meta_type = meta_VXN;
|
||||||
|
|
||||||
switch (codec) {
|
switch (codec) {
|
||||||
|
|
|
@ -233,25 +233,25 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||||
case 0x28: /* early (~2009), ex. The Lord of the Rings: Conquest PC */
|
case 0x28: /* early (~2009), ex. The Lord of the Rings: Conquest PC */
|
||||||
data_offsets = 0x18;
|
data_offsets = 0x18;
|
||||||
block_offsets = 0; /* no need, full headers are present */
|
block_offsets = 0; /* no need, full headers are present */
|
||||||
cfg.header_type = TYPE_8;
|
cfg.header_type = WWV_TYPE_8;
|
||||||
cfg.packet_type = STANDARD;
|
cfg.packet_type = WWV_STANDARD;
|
||||||
cfg.setup_type = HEADER_TRIAD;
|
cfg.setup_type = WWV_HEADER_TRIAD;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//case 0x32: /* ? */
|
//case 0x32: /* ? */
|
||||||
case 0x34: /* common (2010~2011) */
|
case 0x34: /* common (2010~2011) */
|
||||||
data_offsets = 0x18;
|
data_offsets = 0x18;
|
||||||
block_offsets = 0x30;
|
block_offsets = 0x30;
|
||||||
cfg.header_type = TYPE_6;
|
cfg.header_type = WWV_TYPE_6;
|
||||||
cfg.packet_type = STANDARD;
|
cfg.packet_type = WWV_STANDARD;
|
||||||
cfg.setup_type = EXTERNAL_CODEBOOKS; /* setup_type will be corrected later */
|
cfg.setup_type = WWV_EXTERNAL_CODEBOOKS; /* setup_type will be corrected later */
|
||||||
break;
|
break;
|
||||||
case 0x2a: /* uncommon (mid 2011), ex. infamous 2 PS3 */
|
case 0x2a: /* uncommon (mid 2011), ex. infamous 2 PS3 */
|
||||||
data_offsets = 0x10;
|
data_offsets = 0x10;
|
||||||
block_offsets = 0x28;
|
block_offsets = 0x28;
|
||||||
cfg.header_type = TYPE_2;
|
cfg.header_type = WWV_TYPE_2;
|
||||||
cfg.packet_type = MODIFIED;
|
cfg.packet_type = WWV_MODIFIED;
|
||||||
cfg.setup_type = EXTERNAL_CODEBOOKS;
|
cfg.setup_type = WWV_EXTERNAL_CODEBOOKS;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
VGM_LOG("WWISE: unknown vorb size 0x%x\n", vorb_size);
|
VGM_LOG("WWISE: unknown vorb size 0x%x\n", vorb_size);
|
||||||
|
@ -277,11 +277,11 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
/* if the setup after header starts with "(data)BCV" it's an inline codebook) */
|
/* if the setup after header starts with "(data)BCV" it's an inline codebook) */
|
||||||
if ((id & 0x00FFFFFF) == 0x00424356) { /* 0"BCV" */
|
if ((id & 0x00FFFFFF) == 0x00424356) { /* 0"BCV" */
|
||||||
cfg.setup_type = FULL_SETUP;
|
cfg.setup_type = WWV_FULL_SETUP;
|
||||||
}
|
}
|
||||||
/* if the setup is suspiciously big it's probably trimmed inline codebooks */
|
/* if the setup is suspiciously big it's probably trimmed inline codebooks */
|
||||||
else if (setup_size > 0x200) { /* an external setup it's ~0x100 max + some threshold */
|
else if (setup_size > 0x200) { /* an external setup it's ~0x100 max + some threshold */
|
||||||
cfg.setup_type = INLINE_CODEBOOKS;
|
cfg.setup_type = WWV_INLINE_CODEBOOKS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,13 +297,13 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||||
case 0x30:
|
case 0x30:
|
||||||
data_offsets = 0x10;
|
data_offsets = 0x10;
|
||||||
block_offsets = 0x28;
|
block_offsets = 0x28;
|
||||||
cfg.header_type = TYPE_2;
|
cfg.header_type = WWV_TYPE_2;
|
||||||
cfg.packet_type = MODIFIED;
|
cfg.packet_type = WWV_MODIFIED;
|
||||||
|
|
||||||
/* setup not detectable by header, so we'll try both; hopefully libvorbis will reject wrong codebooks
|
/* setup not detectable by header, so we'll try both; hopefully libvorbis will reject wrong codebooks
|
||||||
* - standard: early (<2012), ex. The King of Fighters XIII X360 (2011/11), .ogg (cbs are from aoTuV, too)
|
* - standard: early (<2012), ex. The King of Fighters XIII X360 (2011/11), .ogg (cbs are from aoTuV, too)
|
||||||
* - aoTuV603: later (>2012), ex. Sonic & All-Stars Racing Transformed PC (2012/11), .wem */
|
* - aoTuV603: later (>2012), ex. Sonic & All-Stars Racing Transformed PC (2012/11), .wem */
|
||||||
cfg.setup_type = is_wem ? AOTUV603_CODEBOOKS : EXTERNAL_CODEBOOKS; /* aoTuV came along .wem */
|
cfg.setup_type = is_wem ? WWV_AOTUV603_CODEBOOKS : WWV_EXTERNAL_CODEBOOKS; /* aoTuV came along .wem */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//case 0x2a: /* Rocksmith 2011 X360? */
|
//case 0x2a: /* Rocksmith 2011 X360? */
|
||||||
|
@ -326,14 +326,14 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||||
/* all blocksizes I've seen are 0x08+0x0B except Oddworld PSV, that uses 0x09+0x09
|
/* all blocksizes I've seen are 0x08+0x0B except Oddworld PSV, that uses 0x09+0x09
|
||||||
* (maybe lower spec machines = needs simpler packets) */
|
* (maybe lower spec machines = needs simpler packets) */
|
||||||
if (cfg.blocksize_0_exp == cfg.blocksize_1_exp)
|
if (cfg.blocksize_0_exp == cfg.blocksize_1_exp)
|
||||||
cfg.packet_type = STANDARD;
|
cfg.packet_type = WWV_STANDARD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try with the selected codebooks */
|
/* try with the selected codebooks */
|
||||||
vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg);
|
vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg);
|
||||||
if (!vgmstream->codec_data) {
|
if (!vgmstream->codec_data) {
|
||||||
/* codebooks failed: try again with the other type */
|
/* codebooks failed: try again with the other type */
|
||||||
cfg.setup_type = is_wem ? EXTERNAL_CODEBOOKS : AOTUV603_CODEBOOKS;
|
cfg.setup_type = is_wem ? WWV_EXTERNAL_CODEBOOKS : WWV_AOTUV603_CODEBOOKS;
|
||||||
vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg);
|
vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg);
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
#include "../util.h"
|
#include "../layout/layout.h"
|
||||||
|
|
||||||
|
|
||||||
static int ps_adpcm_find_loop_offsets(STREAMFILE *streamFile, int channel_count, off_t start_offset, off_t * loop_start, off_t * loop_end);
|
static int ps_adpcm_find_loop_offsets(STREAMFILE *streamFile, int channel_count, off_t start_offset, off_t * loop_start, off_t * loop_end);
|
||||||
|
|
||||||
|
@ -10,12 +11,12 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||||
int loop_flag = 0, channel_count, codec;
|
int loop_flag = 0, channel_count, codec;
|
||||||
int big_endian;
|
int big_endian;
|
||||||
int sample_rate, num_samples, multiplier, multistreams = 0;
|
int sample_rate, num_samples, interleave_factor, multistreams = 0;
|
||||||
int total_subsongs = 0, target_subsong = streamFile->stream_index;
|
int total_subsongs = 0, target_subsong = streamFile->stream_index;
|
||||||
|
|
||||||
off_t start_offset, loop_start, loop_end, chunk_offset;
|
off_t start_offset, loop_start = 0, loop_end = 0, chunk_offset;
|
||||||
off_t first_offset = 0x20;
|
off_t first_offset = 0x20;
|
||||||
size_t chunk_size;
|
size_t chunk_size, stream_size;
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* check extension, case insensitive */
|
||||||
if (!check_extensions(streamFile,"xvag"))
|
if (!check_extensions(streamFile,"xvag"))
|
||||||
|
@ -37,7 +38,7 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
/* 0x08: flags? (&0x01=big endian, 0x02=?, 0x06=full RIFF AT9?)
|
/* 0x08: flags? (&0x01=big endian, 0x02=?, 0x06=full RIFF AT9?)
|
||||||
* 0x09: flags2? (0x00/0x01/0x04, speaker mode?)
|
* 0x09: flags2? (0x00/0x01/0x04, speaker mode?)
|
||||||
* 0x0a: always 0?
|
* 0x0a: always 0?
|
||||||
* 0x0b: version-flag? (0x5f/0x60/0x61, last has extra data) */
|
* 0x0b: version-flag? (0x5f/0x60/0x61/0x62/etc) */
|
||||||
|
|
||||||
/* "fmat": base format (always first) */
|
/* "fmat": base format (always first) */
|
||||||
if (!find_chunk(streamFile, 0x666D6174,first_offset,0, &chunk_offset,&chunk_size, big_endian, 1)) /*"fmat"*/
|
if (!find_chunk(streamFile, 0x666D6174,first_offset,0, &chunk_offset,&chunk_size, big_endian, 1)) /*"fmat"*/
|
||||||
|
@ -48,14 +49,20 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
/* 0x0c: samples again? playable section? */
|
/* 0x0c: samples again? playable section? */
|
||||||
VGM_ASSERT(num_samples != read_32bit(chunk_offset+0x0c,streamFile), "XVAG: num_samples values don't match\n");
|
VGM_ASSERT(num_samples != read_32bit(chunk_offset+0x0c,streamFile), "XVAG: num_samples values don't match\n");
|
||||||
|
|
||||||
multiplier = read_32bit(chunk_offset+0x10,streamFile); /* 'interleave factor' */
|
interleave_factor = read_32bit(chunk_offset+0x10,streamFile);
|
||||||
sample_rate = read_32bit(chunk_offset+0x14,streamFile);
|
sample_rate = read_32bit(chunk_offset+0x14,streamFile);
|
||||||
/* 0x18: datasize */
|
stream_size = read_32bit(chunk_offset+0x18,streamFile);
|
||||||
|
|
||||||
/* extra data, seen in MPEG/ATRAC9 */
|
/* extra data, seen in versions 0x61+ */
|
||||||
if (chunk_size > 0x1c) {
|
if (chunk_size > 0x1c) {
|
||||||
total_subsongs = read_32bit(chunk_offset+0x1c,streamFile); /* number of interleaved layers */
|
/* number of interleaved subsong layers */
|
||||||
multistreams = read_32bit(chunk_offset+0x20,streamFile); /* number of bitstreams per layer (for multistream Nch MPEG/ATRAC9) */
|
total_subsongs = read_32bit(chunk_offset+0x1c,streamFile);
|
||||||
|
/* number of interleaved bitstreams per layer (multistreams * channels_per_stream = channels) */
|
||||||
|
multistreams = read_32bit(chunk_offset+0x20,streamFile);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
total_subsongs = 1;
|
||||||
|
multistreams = 1;
|
||||||
}
|
}
|
||||||
if (target_subsong == 0) target_subsong = 1;
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||||
|
@ -66,9 +73,9 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
/* "cues": cue/labels (rare) */
|
/* "cues": cue/labels (rare) */
|
||||||
/* "0000": end chunk before start_offset */
|
/* "0000": end chunk before start_offset */
|
||||||
|
|
||||||
/* some XVAG seem to do full loops, this should detect them as looping */
|
/* some XVAG seem to do full loops, this should detect them as looping (basically tests is last frame is empty) */
|
||||||
//todo remove, looping seems external and specified in Scream Tool's bank formats
|
//todo remove, looping seems external and specified in Scream Tool's bank formats
|
||||||
if (codec == 0x06) {
|
if (codec == 0x06 && total_subsongs == 1) {
|
||||||
loop_flag = ps_adpcm_find_loop_offsets(streamFile, channel_count, start_offset, &loop_start, &loop_end);
|
loop_flag = ps_adpcm_find_loop_offsets(streamFile, channel_count, start_offset, &loop_start, &loop_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,30 +86,45 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
vgmstream->sample_rate = sample_rate;
|
vgmstream->sample_rate = sample_rate;
|
||||||
vgmstream->num_samples = num_samples;
|
vgmstream->num_samples = num_samples;
|
||||||
vgmstream->num_streams = total_subsongs;
|
vgmstream->num_streams = total_subsongs;
|
||||||
|
vgmstream->stream_size = (stream_size / total_subsongs);
|
||||||
vgmstream->meta_type = meta_XVAG;
|
vgmstream->meta_type = meta_XVAG;
|
||||||
|
|
||||||
switch (codec) {
|
switch (codec) {
|
||||||
//case 0x??: /* PCM? */
|
|
||||||
case 0x06: /* VAG (PS ADPCM): God of War III (PS3), Uncharted 1/2 (PS3), Ratchet and Clank Future (PS3) */
|
case 0x06: /* VAG (PS ADPCM): God of War III (PS3), Uncharted 1/2 (PS3), Ratchet and Clank Future (PS3) */
|
||||||
case 0x07: /* SVAG? (PS ADPCM with extended table): inFamous 1 (PS3) */
|
case 0x07: /* SVAG? (PS ADPCM with extended table): inFamous 1 (PS3) */
|
||||||
if (total_subsongs > 1 || multistreams > 1) goto fail;
|
if (multistreams > 1 && multistreams != vgmstream->channels) goto fail;
|
||||||
if (multiplier > 1) goto fail;
|
if (total_subsongs > 1 && multistreams > 1) goto fail;
|
||||||
|
if (total_subsongs > 1 && vgmstream->channels > 1) goto fail; /* unknown layout */
|
||||||
|
|
||||||
vgmstream->layout_type = layout_interleave;
|
|
||||||
vgmstream->interleave_block_size = 0x10;
|
|
||||||
vgmstream->coding_type = coding_PSX;
|
vgmstream->coding_type = coding_PSX;
|
||||||
|
|
||||||
|
if (total_subsongs > 1) { /* God of War 3 (PS4) */
|
||||||
|
vgmstream->layout_type = layout_blocked_xvag_subsong;
|
||||||
|
vgmstream->interleave_block_size = 0x10;
|
||||||
|
vgmstream->full_block_size = 0x10 * interleave_factor * total_subsongs;
|
||||||
|
vgmstream->current_block_size = 0x10 * interleave_factor;
|
||||||
|
start_offset += 0x10 * interleave_factor * (target_subsong-1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vgmstream->layout_type = layout_interleave;
|
||||||
|
vgmstream->interleave_block_size = 0x10 * interleave_factor; /* usually 1, bigger in GoW3 PS4 */
|
||||||
|
}
|
||||||
|
|
||||||
if (loop_flag) {
|
if (loop_flag) {
|
||||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, vgmstream->channels);
|
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, vgmstream->channels);
|
||||||
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, vgmstream->channels);
|
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, vgmstream->channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef VGM_USE_MPEG
|
#ifdef VGM_USE_MPEG
|
||||||
case 0x08: { /* MPEG: The Last of Us (PS3), Uncharted 3 (PS3), Medieval Moves (PS3) */
|
case 0x08: { /* MPEG: The Last of Us (PS3), Uncharted 3 (PS3), Medieval Moves (PS3) */
|
||||||
mpeg_custom_config cfg = {0};
|
mpeg_custom_config cfg = {0};
|
||||||
|
|
||||||
if (total_subsongs > 1 || (multistreams > 1 && multistreams == vgmstream->channels)) goto fail;
|
/* often 2ch per MPEG and rarely 1ch (GoW3 PS4) */
|
||||||
|
if (multistreams > 1 && !(multistreams*1 == vgmstream->channels || multistreams*2 == vgmstream->channels)) goto fail;
|
||||||
|
if (total_subsongs > 1) goto fail;
|
||||||
|
//todo rare test file in The Last of Us PS4 uses 6ch with 1 2ch stream, surround MPEG/mp3pro?
|
||||||
|
|
||||||
/* "mpin": mpeg info */
|
/* "mpin": mpeg info */
|
||||||
/* 0x00/04: mpeg version/layer? other: unknown or repeats of "fmat" */
|
/* 0x00/04: mpeg version/layer? other: unknown or repeats of "fmat" */
|
||||||
|
@ -110,7 +132,7 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
cfg.chunk_size = read_32bit(chunk_offset+0x1c,streamFile); /* fixed frame size */
|
cfg.chunk_size = read_32bit(chunk_offset+0x1c,streamFile); /* fixed frame size */
|
||||||
cfg.interleave = cfg.chunk_size * multiplier;
|
cfg.interleave = cfg.chunk_size * interleave_factor;
|
||||||
|
|
||||||
vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_XVAG, &cfg);
|
vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_XVAG, &cfg);
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
|
@ -138,7 +160,7 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
else if (total_subsongs > 1) {
|
else if (total_subsongs > 1) {
|
||||||
/* interleaves 'multiplier' superframes per subsong (all share config_data) */
|
/* interleaves 'multiplier' superframes per subsong (all share config_data) */
|
||||||
cfg.interleave_skip = read_32bit(chunk_offset+0x00,streamFile) * multiplier;
|
cfg.interleave_skip = read_32bit(chunk_offset+0x00,streamFile) * interleave_factor;
|
||||||
cfg.subsong_skip = total_subsongs;
|
cfg.subsong_skip = total_subsongs;
|
||||||
/* start in subsong's first superframe */
|
/* start in subsong's first superframe */
|
||||||
start_offset += (target_subsong-1) * cfg.interleave_skip * (cfg.subsong_skip-1);
|
start_offset += (target_subsong-1) * cfg.interleave_skip * (cfg.subsong_skip-1);
|
||||||
|
@ -158,6 +180,7 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//case 0x??: /* PCM? */
|
||||||
default:
|
default:
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -167,6 +190,9 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
|
||||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
if (vgmstream->layout_type == layout_blocked_xvag_subsong)
|
||||||
|
block_update_xvag_subsong(start_offset, vgmstream);
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
/* the x.x version is just to make it clearer, MS only classifies XACT as 1/2/3 */
|
/* the x.x version is just to make it clearer, MS only classifies XACT as 1/2/3 */
|
||||||
#define XACT1_0_MAX 1 /* Project Gotham Racing 2 (v1), Silent Hill 4 (v1) */
|
#define XACT1_0_MAX 1 /* Project Gotham Racing 2 (v1), Silent Hill 4 (v1) */
|
||||||
#define XACT1_1_MAX 3 /* The King of Fighters 2003 (v3) */
|
#define XACT1_1_MAX 3 /* Unreal Championship (v2), The King of Fighters 2003 (v3) */
|
||||||
#define XACT2_0_MAX 34 /* Dead or Alive 4 (v17), Kameo (v23), Table Tennis (v34) */ // v35/36/37 too?
|
#define XACT2_0_MAX 34 /* Dead or Alive 4 (v17), Kameo (v23), Table Tennis (v34) */ // v35/36/37 too?
|
||||||
#define XACT2_1_MAX 38 /* Prey (v38) */ // v39 too?
|
#define XACT2_1_MAX 38 /* Prey (v38) */ // v39 too?
|
||||||
#define XACT2_2_MAX 41 /* Blue Dragon (v40) */
|
#define XACT2_2_MAX 41 /* Blue Dragon (v40) */
|
||||||
|
@ -354,47 +354,45 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
|
||||||
vgmstream->loop_start_sample = xwb.loop_start_sample;
|
vgmstream->loop_start_sample = xwb.loop_start_sample;
|
||||||
vgmstream->loop_end_sample = xwb.loop_end_sample;
|
vgmstream->loop_end_sample = xwb.loop_end_sample;
|
||||||
vgmstream->num_streams = xwb.streams;
|
vgmstream->num_streams = xwb.streams;
|
||||||
|
vgmstream->stream_size = xwb.stream_size;
|
||||||
vgmstream->meta_type = meta_XWB;
|
vgmstream->meta_type = meta_XWB;
|
||||||
get_xsb_name(vgmstream->stream_name,STREAM_NAME_SIZE, target_stream, &xwb, streamFile);
|
get_xsb_name(vgmstream->stream_name,STREAM_NAME_SIZE, target_stream, &xwb, streamFile);
|
||||||
|
|
||||||
switch(xwb.codec) {
|
switch(xwb.codec) {
|
||||||
case PCM:
|
case PCM: /* Unreal Championship (Xbox)[PCM8], KOF2003 (Xbox)[PCM16LE], Otomedius (X360)[PCM16BE] */
|
||||||
vgmstream->coding_type = xwb.bits_per_sample == 0 ? coding_PCM8 :
|
vgmstream->coding_type = xwb.bits_per_sample == 0 ? coding_PCM8_U :
|
||||||
(xwb.little_endian ? coding_PCM16LE : coding_PCM16BE);
|
(xwb.little_endian ? coding_PCM16LE : coding_PCM16BE);
|
||||||
vgmstream->layout_type = xwb.channels > 1 ? layout_interleave : layout_none;
|
vgmstream->layout_type = xwb.channels > 1 ? layout_interleave : layout_none;
|
||||||
vgmstream->interleave_block_size = xwb.bits_per_sample == 0 ? 0x01 : 0x02;
|
vgmstream->interleave_block_size = xwb.bits_per_sample == 0 ? 0x01 : 0x02;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XBOX_ADPCM:
|
case XBOX_ADPCM: /* Silent Hill 4 (Xbox) */
|
||||||
vgmstream->coding_type = coding_XBOX;
|
vgmstream->coding_type = coding_XBOX;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MS_ADPCM:
|
case MS_ADPCM: /* Persona 4 Ultimax (AC) */
|
||||||
vgmstream->coding_type = coding_MSADPCM;
|
vgmstream->coding_type = coding_MSADPCM;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
vgmstream->interleave_block_size = (xwb.block_align + 22) * xwb.channels; /*22=CONVERSION_OFFSET (?)*/
|
vgmstream->interleave_block_size = (xwb.block_align + 22) * xwb.channels; /*22=CONVERSION_OFFSET (?)*/
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
case XMA1: {
|
case XMA1: { /* Kameo (X360) */
|
||||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
|
||||||
uint8_t buf[100];
|
uint8_t buf[100];
|
||||||
int bytes;
|
int bytes;
|
||||||
|
|
||||||
bytes = ffmpeg_make_riff_xma1(buf, 100, vgmstream->num_samples, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, 0);
|
bytes = ffmpeg_make_riff_xma1(buf, 100, vgmstream->num_samples, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, 0);
|
||||||
if (bytes <= 0) goto fail;
|
if (bytes <= 0) goto fail;
|
||||||
|
|
||||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, xwb.stream_offset,xwb.stream_size);
|
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, xwb.stream_offset,xwb.stream_size);
|
||||||
if ( !ffmpeg_data ) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
vgmstream->codec_data = ffmpeg_data;
|
|
||||||
vgmstream->coding_type = coding_FFmpeg;
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case XMA2: {
|
case XMA2: { /* Blue Dragon (X360) */
|
||||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
|
||||||
uint8_t buf[100];
|
uint8_t buf[100];
|
||||||
int bytes, block_size, block_count;
|
int bytes, block_size, block_count;
|
||||||
|
|
||||||
|
@ -404,15 +402,14 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
|
||||||
bytes = ffmpeg_make_riff_xma2(buf, 100, vgmstream->num_samples, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
|
bytes = ffmpeg_make_riff_xma2(buf, 100, vgmstream->num_samples, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
|
||||||
if (bytes <= 0) goto fail;
|
if (bytes <= 0) goto fail;
|
||||||
|
|
||||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, xwb.stream_offset,xwb.stream_size);
|
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, xwb.stream_offset,xwb.stream_size);
|
||||||
if ( !ffmpeg_data ) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
vgmstream->codec_data = ffmpeg_data;
|
|
||||||
vgmstream->coding_type = coding_FFmpeg;
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WMA: { /* WMAudio1 (WMA v1) */
|
case WMA: { /* WMAudio1 (WMA v1): Prince of Persia 2 port (Xbox) */
|
||||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||||
|
|
||||||
ffmpeg_data = init_ffmpeg_offset(streamFile, xwb.stream_offset,xwb.stream_size);
|
ffmpeg_data = init_ffmpeg_offset(streamFile, xwb.stream_offset,xwb.stream_size);
|
||||||
|
@ -427,8 +424,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case XWMA: { /* WMAudio2 (WMA v2), WMAudio3 (WMA Pro) */
|
case XWMA: { /* WMAudio2 (WMA v2): BlazBlue (X360), WMAudio3 (WMA Pro): ? */
|
||||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
|
||||||
uint8_t buf[100];
|
uint8_t buf[100];
|
||||||
int bytes, bps_index, block_align, block_index, avg_bps, wma_codec;
|
int bytes, bps_index, block_align, block_index, avg_bps, wma_codec;
|
||||||
|
|
||||||
|
@ -444,15 +440,14 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
|
||||||
bytes = ffmpeg_make_riff_xwma(buf, 100, wma_codec, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, avg_bps, block_align);
|
bytes = ffmpeg_make_riff_xwma(buf, 100, wma_codec, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, avg_bps, block_align);
|
||||||
if (bytes <= 0) goto fail;
|
if (bytes <= 0) goto fail;
|
||||||
|
|
||||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, xwb.stream_offset,xwb.stream_size);
|
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, xwb.stream_offset,xwb.stream_size);
|
||||||
if ( !ffmpeg_data ) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
vgmstream->codec_data = ffmpeg_data;
|
|
||||||
vgmstream->coding_type = coding_FFmpeg;
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ATRAC3: { /* Techland PS3 extension */
|
case ATRAC3: { /* Techland PS3 extension: Sniper Ghost Warrior (PS3) */
|
||||||
uint8_t buf[200];
|
uint8_t buf[200];
|
||||||
int bytes;
|
int bytes;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
#include "meta.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
|
/* .XWC - Starbreeze games [Chronicles of Riddick: Assault on Dark Athena, Syndicate] */
|
||||||
|
VGMSTREAM * init_vgmstream_xwc(STREAMFILE *streamFile) {
|
||||||
|
VGMSTREAM * vgmstream = NULL;
|
||||||
|
off_t start_offset;
|
||||||
|
size_t data_size;
|
||||||
|
int loop_flag, channel_count, codec;
|
||||||
|
|
||||||
|
/* check extensions (.xwc is the extension of the bigfile, individual files don't have one) */
|
||||||
|
if ( !check_extensions(streamFile,"xwc"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if(read_32bitBE(0x00,streamFile) != 0x00040000 && /* version? */
|
||||||
|
read_32bitBE(0x04,streamFile) != 0x00900000)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
data_size = read_32bitLE(0x08, streamFile); /* including subheader */
|
||||||
|
channel_count = read_32bitLE(0x0c, streamFile);
|
||||||
|
/* 0x10: num_samples */
|
||||||
|
/* 0x14: 0x8000? */
|
||||||
|
codec = read_32bitBE(0x24, streamFile);
|
||||||
|
/* 0x28: num_samples */
|
||||||
|
/* 0x2c: config data? (first nibble: 0x4=mono, 0x8=stereo) */
|
||||||
|
/* 0x30+: codec dependant */
|
||||||
|
loop_flag = 0; /* seemingly not in the file */
|
||||||
|
|
||||||
|
|
||||||
|
/* build the VGMSTREAM */
|
||||||
|
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
vgmstream->num_samples = read_32bitLE(0x28, streamFile);
|
||||||
|
vgmstream->meta_type = meta_XWC;
|
||||||
|
|
||||||
|
switch(codec) {
|
||||||
|
#ifdef VGM_USE_MPEG
|
||||||
|
case 0x4D504547: { /* "MPEG" (PS3) */
|
||||||
|
mpeg_custom_config cfg = {0};
|
||||||
|
|
||||||
|
start_offset = 0x800;
|
||||||
|
vgmstream->num_samples = read_32bitLE(0x30, streamFile); /* with encoder delay */ //todo improve
|
||||||
|
cfg.data_size = read_32bitLE(0x34, streamFile); //data_size - 0x28;
|
||||||
|
|
||||||
|
vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_STANDARD, &cfg);
|
||||||
|
if (!vgmstream->codec_data) goto fail;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
|
vgmstream->sample_rate = ((mpeg_codec_data*)vgmstream->codec_data)->sample_rate_per_frame;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef VGM_USE_FFMPEG
|
||||||
|
case 0x584D4100: { /* "XMA\0" (X360) */
|
||||||
|
uint8_t buf[0x100];
|
||||||
|
int32_t bytes, seek_size, block_size, block_count, sample_rate;
|
||||||
|
|
||||||
|
seek_size = read_32bitLE(0x30, streamFile);
|
||||||
|
start_offset = 0x34 + seek_size + read_32bitLE(0x34+seek_size, streamFile) + 0x08;
|
||||||
|
start_offset += (start_offset % 0x800) ? 0x800 - (start_offset % 0x800) : 0; /* padded */
|
||||||
|
|
||||||
|
sample_rate = read_32bitBE(0x34+seek_size+0x10, streamFile);
|
||||||
|
block_size = read_32bitBE(0x34+seek_size+0x1c, streamFile);
|
||||||
|
block_count = read_32bitBE(0x34+seek_size+0x28, streamFile);
|
||||||
|
/* others: scrambled RIFF fmt BE values */
|
||||||
|
|
||||||
|
bytes = ffmpeg_make_riff_xma2(buf,0x100, vgmstream->num_samples, data_size, vgmstream->channels, sample_rate, block_count, block_size);
|
||||||
|
if (bytes <= 0) goto fail;
|
||||||
|
|
||||||
|
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size - start_offset - 0x28);
|
||||||
|
if (!vgmstream->codec_data) goto fail;
|
||||||
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
|
vgmstream->sample_rate = sample_rate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x564F5242: { /* "VORB" (PC) */
|
||||||
|
start_offset = 0x30;
|
||||||
|
|
||||||
|
vgmstream->codec_data = init_ffmpeg_offset(streamFile, start_offset, data_size - start_offset - 0x28);
|
||||||
|
if ( !vgmstream->codec_data ) goto fail;
|
||||||
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
|
vgmstream->sample_rate = read_32bitLE(start_offset + 0x28, streamFile);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vgmstream->sample_rate != 48000) { /* get from config data instead of codecs? */
|
||||||
|
VGM_LOG("XWC: unexpected sample rate %i\n",vgmstream->sample_rate);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||||
|
goto fail;
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -22,10 +22,6 @@ typedef struct {
|
||||||
uint8_t * buffer; /* data buffer */
|
uint8_t * buffer; /* data buffer */
|
||||||
size_t buffersize; /* max buffer size */
|
size_t buffersize; /* max buffer size */
|
||||||
size_t filesize; /* cached file size (max offset) */
|
size_t filesize; /* cached file size (max offset) */
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
size_t bytes_read;
|
|
||||||
int error_count;
|
|
||||||
#endif
|
|
||||||
} STDIOSTREAMFILE;
|
} STDIOSTREAMFILE;
|
||||||
|
|
||||||
static STREAMFILE * open_stdio_streamfile_buffer(const char * const filename, size_t buffersize);
|
static STREAMFILE * open_stdio_streamfile_buffer(const char * const filename, size_t buffersize);
|
||||||
|
@ -77,9 +73,6 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST
|
||||||
/* position to new offset */
|
/* position to new offset */
|
||||||
if (fseeko(streamfile->infile,offset,SEEK_SET)) {
|
if (fseeko(streamfile->infile,offset,SEEK_SET)) {
|
||||||
streamfile->offset = streamfile->filesize;
|
streamfile->offset = streamfile->filesize;
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
streamfile->error_count++;
|
|
||||||
#endif
|
|
||||||
return 0; /* fail miserably (fseek shouldn't fail and reach this) */
|
return 0; /* fail miserably (fseek shouldn't fail and reach this) */
|
||||||
}
|
}
|
||||||
streamfile->offset = offset;
|
streamfile->offset = offset;
|
||||||
|
@ -94,15 +87,6 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST
|
||||||
length_read = fread(streamfile->buffer,sizeof(uint8_t),streamfile->buffersize,streamfile->infile);
|
length_read = fread(streamfile->buffer,sizeof(uint8_t),streamfile->buffersize,streamfile->infile);
|
||||||
streamfile->validsize = length_read;
|
streamfile->validsize = length_read;
|
||||||
|
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
if (ferror(streamfile->infile)) {
|
|
||||||
clearerr(streamfile->infile);
|
|
||||||
streamfile->error_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
streamfile->bytes_read += length_read;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* if we can't get enough to satisfy the request (EOF) we give up */
|
/* if we can't get enough to satisfy the request (EOF) we give up */
|
||||||
if (length_read < length_to_read) {
|
if (length_read < length_to_read) {
|
||||||
memcpy(dest,streamfile->buffer,length_read);
|
memcpy(dest,streamfile->buffer,length_read);
|
||||||
|
@ -154,10 +138,6 @@ static size_t read_stdio(STDIOSTREAMFILE *streamfile,uint8_t * dest, off_t offse
|
||||||
/* request outside buffer: new fread */
|
/* request outside buffer: new fread */
|
||||||
{
|
{
|
||||||
size_t length_read = read_the_rest(dest,offset,length,streamfile);
|
size_t length_read = read_the_rest(dest,offset,length,streamfile);
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
if (length_read < length)
|
|
||||||
streamfile->error_count++;
|
|
||||||
#endif
|
|
||||||
return length_read;
|
return length_read;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,15 +161,6 @@ static void get_name_stdio(STDIOSTREAMFILE *streamfile,char *buffer,size_t lengt
|
||||||
buffer[length-1]='\0';
|
buffer[length-1]='\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
static size_t get_bytes_read_stdio(STDIOSTREAMFILE *streamFile) {
|
|
||||||
return streamFile->bytes_read;
|
|
||||||
}
|
|
||||||
static size_t get_error_count_stdio(STDIOSTREAMFILE *streamFile) {
|
|
||||||
return streamFile->error_count;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static STREAMFILE *open_stdio(STDIOSTREAMFILE *streamFile,const char * const filename,size_t buffersize) {
|
static STREAMFILE *open_stdio(STDIOSTREAMFILE *streamFile,const char * const filename,size_t buffersize) {
|
||||||
int newfd;
|
int newfd;
|
||||||
FILE *newfile;
|
FILE *newfile;
|
||||||
|
@ -237,10 +208,6 @@ static STREAMFILE * open_stdio_streamfile_buffer_by_file(FILE *infile,const char
|
||||||
streamfile->sf.get_realname = (void*)get_name_stdio;
|
streamfile->sf.get_realname = (void*)get_name_stdio;
|
||||||
streamfile->sf.open = (void*)open_stdio;
|
streamfile->sf.open = (void*)open_stdio;
|
||||||
streamfile->sf.close = (void*)close_stdio;
|
streamfile->sf.close = (void*)close_stdio;
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
streamfile->sf.get_bytes_read = (void*)get_bytes_read_stdio;
|
|
||||||
streamfile->sf.get_error_count = (void*)get_error_count_stdio;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
streamfile->infile = infile;
|
streamfile->infile = infile;
|
||||||
streamfile->buffersize = buffersize;
|
streamfile->buffersize = buffersize;
|
||||||
|
@ -280,6 +247,439 @@ STREAMFILE * open_stdio_streamfile_by_file(FILE * file, const char * filename) {
|
||||||
return open_stdio_streamfile_buffer_by_file(file,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
return open_stdio_streamfile_buffer_by_file(file,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* **************************************************** */
|
||||||
|
|
||||||
|
//todo stream_index: copy? pass? funtion? external?
|
||||||
|
//todo use realnames on reopen? simplify?
|
||||||
|
//todo use safe string ops, this ain't easy
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
STREAMFILE sf;
|
||||||
|
|
||||||
|
STREAMFILE *inner_sf;
|
||||||
|
} WRAP_STREAMFILE;
|
||||||
|
|
||||||
|
static size_t wrap_read(WRAP_STREAMFILE *streamfile, uint8_t * dest, off_t offset, size_t length) {
|
||||||
|
return streamfile->inner_sf->read(streamfile->inner_sf, dest, offset, length); /* default */
|
||||||
|
}
|
||||||
|
static size_t wrap_get_size(WRAP_STREAMFILE * streamfile) {
|
||||||
|
return streamfile->inner_sf->get_size(streamfile->inner_sf); /* default */
|
||||||
|
}
|
||||||
|
static size_t wrap_get_offset(WRAP_STREAMFILE * streamfile) {
|
||||||
|
return streamfile->inner_sf->get_offset(streamfile->inner_sf); /* default */
|
||||||
|
}
|
||||||
|
static void wrap_get_name(WRAP_STREAMFILE *streamfile, char *buffer, size_t length) {
|
||||||
|
streamfile->inner_sf->get_name(streamfile->inner_sf, buffer, length); /* default */
|
||||||
|
}
|
||||||
|
static void wrap_get_realname(WRAP_STREAMFILE *streamfile, char *buffer, size_t length) {
|
||||||
|
streamfile->inner_sf->get_realname(streamfile->inner_sf, buffer, length); /* default */
|
||||||
|
}
|
||||||
|
static void wrap_open(WRAP_STREAMFILE *streamfile, const char * const filename, size_t buffersize) {
|
||||||
|
streamfile->inner_sf->open(streamfile->inner_sf, filename, buffersize); /* default (don't wrap) */
|
||||||
|
}
|
||||||
|
static void wrap_close(WRAP_STREAMFILE *streamfile) {
|
||||||
|
//streamfile->inner_sf->close(streamfile->inner_sf); /* don't close */
|
||||||
|
free(streamfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
STREAMFILE *open_wrap_streamfile(STREAMFILE *streamfile) {
|
||||||
|
WRAP_STREAMFILE *this_sf;
|
||||||
|
|
||||||
|
if (!streamfile) return NULL;
|
||||||
|
|
||||||
|
this_sf = calloc(1,sizeof(WRAP_STREAMFILE));
|
||||||
|
if (!this_sf) return NULL;
|
||||||
|
|
||||||
|
/* set callbacks and internals */
|
||||||
|
this_sf->sf.read = (void*)wrap_read;
|
||||||
|
this_sf->sf.get_size = (void*)wrap_get_size;
|
||||||
|
this_sf->sf.get_offset = (void*)wrap_get_offset;
|
||||||
|
this_sf->sf.get_name = (void*)wrap_get_name;
|
||||||
|
this_sf->sf.get_realname = (void*)wrap_get_realname;
|
||||||
|
this_sf->sf.open = (void*)wrap_open;
|
||||||
|
this_sf->sf.close = (void*)wrap_close;
|
||||||
|
this_sf->sf.stream_index = streamfile->stream_index;
|
||||||
|
|
||||||
|
this_sf->inner_sf = streamfile;
|
||||||
|
|
||||||
|
return &this_sf->sf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* **************************************************** */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
STREAMFILE sf;
|
||||||
|
|
||||||
|
STREAMFILE *inner_sf;
|
||||||
|
off_t start;
|
||||||
|
size_t size;
|
||||||
|
} CLAMP_STREAMFILE;
|
||||||
|
|
||||||
|
static size_t clamp_read(CLAMP_STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length) {
|
||||||
|
off_t inner_offset = streamfile->start + offset;
|
||||||
|
size_t clamp_length = length > (streamfile->size - offset) ? (streamfile->size - offset) : length;
|
||||||
|
return streamfile->inner_sf->read(streamfile->inner_sf, dest, inner_offset, clamp_length);
|
||||||
|
}
|
||||||
|
static size_t clamp_get_size(CLAMP_STREAMFILE *streamfile) {
|
||||||
|
return streamfile->size;
|
||||||
|
}
|
||||||
|
static off_t clamp_get_offset(CLAMP_STREAMFILE *streamfile) {
|
||||||
|
return streamfile->inner_sf->get_offset(streamfile->inner_sf) - streamfile->start;
|
||||||
|
}
|
||||||
|
static void clamp_get_name(CLAMP_STREAMFILE *streamfile, char *buffer, size_t length) {
|
||||||
|
streamfile->inner_sf->get_name(streamfile->inner_sf, buffer, length); /* default */
|
||||||
|
}
|
||||||
|
static void clamp_get_realname(CLAMP_STREAMFILE *streamfile, char *buffer, size_t length) {
|
||||||
|
streamfile->inner_sf->get_realname(streamfile->inner_sf, buffer, length); /* default */
|
||||||
|
}
|
||||||
|
static STREAMFILE *clamp_open(CLAMP_STREAMFILE *streamfile, const char * const filename, size_t buffersize) {
|
||||||
|
char original_filename[PATH_LIMIT];
|
||||||
|
STREAMFILE *new_inner_sf;
|
||||||
|
|
||||||
|
new_inner_sf = streamfile->inner_sf->open(streamfile->inner_sf,filename,buffersize);
|
||||||
|
streamfile->inner_sf->get_name(streamfile->inner_sf, original_filename, PATH_LIMIT);
|
||||||
|
|
||||||
|
/* detect re-opening the file */
|
||||||
|
if (strcmp(filename, original_filename) == 0) {
|
||||||
|
return open_clamp_streamfile(new_inner_sf, streamfile->start, streamfile->size); /* clamp again */
|
||||||
|
} else {
|
||||||
|
return new_inner_sf; /**/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void clamp_close(CLAMP_STREAMFILE *streamfile) {
|
||||||
|
streamfile->inner_sf->close(streamfile->inner_sf);
|
||||||
|
free(streamfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
STREAMFILE *open_clamp_streamfile(STREAMFILE *streamfile, off_t start, size_t size) {
|
||||||
|
CLAMP_STREAMFILE *this_sf;
|
||||||
|
|
||||||
|
if (!streamfile || !size) return NULL;
|
||||||
|
if (start + size > get_streamfile_size(streamfile)) return NULL;
|
||||||
|
|
||||||
|
this_sf = calloc(1,sizeof(CLAMP_STREAMFILE));
|
||||||
|
if (!this_sf) return NULL;
|
||||||
|
|
||||||
|
/* set callbacks and internals */
|
||||||
|
this_sf->sf.read = (void*)clamp_read;
|
||||||
|
this_sf->sf.get_size = (void*)clamp_get_size;
|
||||||
|
this_sf->sf.get_offset = (void*)clamp_get_offset;
|
||||||
|
this_sf->sf.get_name = (void*)clamp_get_name;
|
||||||
|
this_sf->sf.get_realname = (void*)clamp_get_realname;
|
||||||
|
this_sf->sf.open = (void*)clamp_open;
|
||||||
|
this_sf->sf.close = (void*)clamp_close;
|
||||||
|
this_sf->sf.stream_index = streamfile->stream_index;
|
||||||
|
|
||||||
|
this_sf->inner_sf = streamfile;
|
||||||
|
this_sf->start = start;
|
||||||
|
this_sf->size = size;
|
||||||
|
|
||||||
|
return &this_sf->sf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* **************************************************** */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
STREAMFILE sf;
|
||||||
|
|
||||||
|
STREAMFILE *inner_sf;
|
||||||
|
void* data;
|
||||||
|
size_t data_size;
|
||||||
|
size_t (*read_callback)(STREAMFILE *, uint8_t *, off_t, size_t, void*);
|
||||||
|
} IO_STREAMFILE;
|
||||||
|
|
||||||
|
static size_t io_read(IO_STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length) {
|
||||||
|
return streamfile->read_callback(streamfile->inner_sf, dest, offset, length, streamfile->data);
|
||||||
|
}
|
||||||
|
static size_t io_get_size(IO_STREAMFILE *streamfile) {
|
||||||
|
return streamfile->inner_sf->get_size(streamfile->inner_sf); /* default */
|
||||||
|
}
|
||||||
|
static off_t io_get_offset(IO_STREAMFILE *streamfile) {
|
||||||
|
return streamfile->inner_sf->get_offset(streamfile->inner_sf); /* default */
|
||||||
|
}
|
||||||
|
static void io_get_name(IO_STREAMFILE *streamfile, char *buffer, size_t length) {
|
||||||
|
streamfile->inner_sf->get_name(streamfile->inner_sf, buffer, length); /* default */
|
||||||
|
}
|
||||||
|
static void io_get_realname(IO_STREAMFILE *streamfile, char *buffer, size_t length) {
|
||||||
|
streamfile->inner_sf->get_realname(streamfile->inner_sf, buffer, length); /* default */
|
||||||
|
}
|
||||||
|
static STREAMFILE *io_open(IO_STREAMFILE *streamfile, const char * const filename, size_t buffersize) {
|
||||||
|
//todo should have some flag to decide if opening other files with IO
|
||||||
|
STREAMFILE *new_inner_sf = streamfile->inner_sf->open(streamfile->inner_sf,filename,buffersize);
|
||||||
|
return open_io_streamfile(new_inner_sf, streamfile->data, streamfile->data_size, streamfile->read_callback);
|
||||||
|
}
|
||||||
|
static void io_close(IO_STREAMFILE *streamfile) {
|
||||||
|
streamfile->inner_sf->close(streamfile->inner_sf);
|
||||||
|
free(streamfile->data);
|
||||||
|
free(streamfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_size, void* read_callback) {
|
||||||
|
IO_STREAMFILE *this_sf;
|
||||||
|
|
||||||
|
if (!streamfile) return NULL;
|
||||||
|
if ((data && !data_size) || (!data && data_size)) return NULL;
|
||||||
|
|
||||||
|
this_sf = calloc(1,sizeof(IO_STREAMFILE));
|
||||||
|
if (!this_sf) return NULL;
|
||||||
|
|
||||||
|
/* set callbacks and internals */
|
||||||
|
this_sf->sf.read = (void*)io_read;
|
||||||
|
this_sf->sf.get_size = (void*)io_get_size;
|
||||||
|
this_sf->sf.get_offset = (void*)io_get_offset;
|
||||||
|
this_sf->sf.get_name = (void*)io_get_name;
|
||||||
|
this_sf->sf.get_realname = (void*)io_get_realname;
|
||||||
|
this_sf->sf.open = (void*)io_open;
|
||||||
|
this_sf->sf.close = (void*)io_close;
|
||||||
|
this_sf->sf.stream_index = streamfile->stream_index;
|
||||||
|
|
||||||
|
this_sf->inner_sf = streamfile;
|
||||||
|
if (data) {
|
||||||
|
this_sf->data = malloc(data_size);
|
||||||
|
if (!this_sf->data) {
|
||||||
|
free(this_sf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(this_sf->data, data, data_size);
|
||||||
|
}
|
||||||
|
this_sf->data_size = data_size;
|
||||||
|
this_sf->read_callback = read_callback;
|
||||||
|
|
||||||
|
return &this_sf->sf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* **************************************************** */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
STREAMFILE sf;
|
||||||
|
|
||||||
|
STREAMFILE *inner_sf;
|
||||||
|
char fakename[PATH_LIMIT];
|
||||||
|
} FAKENAME_STREAMFILE;
|
||||||
|
|
||||||
|
static size_t fakename_read(FAKENAME_STREAMFILE *streamfile, uint8_t * dest, off_t offset, size_t length) {
|
||||||
|
return streamfile->inner_sf->read(streamfile->inner_sf, dest, offset, length); /* default */
|
||||||
|
}
|
||||||
|
static size_t fakename_get_size(FAKENAME_STREAMFILE * streamfile) {
|
||||||
|
return streamfile->inner_sf->get_size(streamfile->inner_sf); /* default */
|
||||||
|
}
|
||||||
|
static size_t fakename_get_offset(FAKENAME_STREAMFILE * streamfile) {
|
||||||
|
return streamfile->inner_sf->get_offset(streamfile->inner_sf); /* default */
|
||||||
|
}
|
||||||
|
static void fakename_get_name(FAKENAME_STREAMFILE *streamfile, char *buffer, size_t length) {
|
||||||
|
strncpy(buffer,streamfile->fakename,length);
|
||||||
|
buffer[length-1]='\0';
|
||||||
|
}
|
||||||
|
static void fakename_get_realname(FAKENAME_STREAMFILE *streamfile, char *buffer, size_t length) {
|
||||||
|
fakename_get_name(streamfile, buffer, length);
|
||||||
|
}
|
||||||
|
static STREAMFILE *fakename_open(FAKENAME_STREAMFILE *streamfile, const char * const filename, size_t buffersize) {
|
||||||
|
/* detect re-opening the file */
|
||||||
|
if (strcmp(filename, streamfile->fakename) == 0) {
|
||||||
|
STREAMFILE *new_inner_sf;
|
||||||
|
char original_filename[PATH_LIMIT];
|
||||||
|
|
||||||
|
streamfile->inner_sf->get_name(streamfile->inner_sf, original_filename, PATH_LIMIT);
|
||||||
|
new_inner_sf = streamfile->inner_sf->open(streamfile->inner_sf, original_filename, buffersize);
|
||||||
|
return open_fakename_streamfile(new_inner_sf, streamfile->fakename, NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return streamfile->inner_sf->open(streamfile->inner_sf, filename, buffersize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void fakename_close(FAKENAME_STREAMFILE *streamfile) {
|
||||||
|
streamfile->inner_sf->close(streamfile->inner_sf);
|
||||||
|
free(streamfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, char * fakename, char* fakeext) {
|
||||||
|
FAKENAME_STREAMFILE *this_sf;
|
||||||
|
|
||||||
|
if (!streamfile || (!fakename && !fakeext)) return NULL;
|
||||||
|
|
||||||
|
this_sf = calloc(1,sizeof(FAKENAME_STREAMFILE));
|
||||||
|
if (!this_sf) return NULL;
|
||||||
|
|
||||||
|
/* set callbacks and internals */
|
||||||
|
this_sf->sf.read = (void*)fakename_read;
|
||||||
|
this_sf->sf.get_size = (void*)fakename_get_size;
|
||||||
|
this_sf->sf.get_offset = (void*)fakename_get_offset;
|
||||||
|
this_sf->sf.get_name = (void*)fakename_get_name;
|
||||||
|
this_sf->sf.get_realname = (void*)fakename_get_realname;
|
||||||
|
this_sf->sf.open = (void*)fakename_open;
|
||||||
|
this_sf->sf.close = (void*)fakename_close;
|
||||||
|
this_sf->sf.stream_index = streamfile->stream_index;
|
||||||
|
|
||||||
|
this_sf->inner_sf = streamfile;
|
||||||
|
|
||||||
|
/* copy passed name or retain current, and swap extension if expected */
|
||||||
|
if (fakename) {
|
||||||
|
strcpy(this_sf->fakename,fakename);
|
||||||
|
} else {
|
||||||
|
streamfile->get_name(streamfile, this_sf->fakename, PATH_LIMIT);
|
||||||
|
}
|
||||||
|
if (fakeext) {
|
||||||
|
char * ext = strrchr(this_sf->fakename,'.');
|
||||||
|
if (ext != NULL)
|
||||||
|
ext[1] = '\0'; /* truncate past dot */
|
||||||
|
strcat(this_sf->fakename, fakeext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return &this_sf->sf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* **************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
STREAMFILE sf;
|
||||||
|
|
||||||
|
STREAMFILE **inner_sfs;
|
||||||
|
size_t inner_sfs_size;
|
||||||
|
size_t *sizes;
|
||||||
|
off_t size;
|
||||||
|
off_t offset;
|
||||||
|
} MULTIFILE_STREAMFILE;
|
||||||
|
|
||||||
|
static size_t multifile_read(MULTIFILE_STREAMFILE *streamfile, uint8_t * dest, off_t offset, size_t length) {
|
||||||
|
int i, segment = 0;
|
||||||
|
off_t segment_offset = 0;
|
||||||
|
size_t done = 0;
|
||||||
|
|
||||||
|
if (offset > streamfile->size) {
|
||||||
|
streamfile->offset = streamfile->size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* map external offset to multifile offset */
|
||||||
|
for (i = 0; i < streamfile->inner_sfs_size; i++) {
|
||||||
|
size_t segment_size = streamfile->sizes[i];
|
||||||
|
/* check if offset falls in this segment */
|
||||||
|
if (offset >= segment_offset && offset < segment_offset + segment_size) {
|
||||||
|
segment = i;
|
||||||
|
segment_offset = offset - segment_offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
segment_offset += segment_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reads can span multiple segments */
|
||||||
|
while(done < length) {
|
||||||
|
if (segment >= streamfile->inner_sfs_size) /* over last segment, not fully done */
|
||||||
|
break;
|
||||||
|
/* reads over segment size are ok, will return smaller value and continue next segment */
|
||||||
|
done += streamfile->inner_sfs[segment]->read(streamfile->inner_sfs[segment], dest+done, segment_offset, length - done);
|
||||||
|
segment++;
|
||||||
|
segment_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
streamfile->offset = offset + done;
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
static size_t multifile_get_size(MULTIFILE_STREAMFILE *streamfile) {
|
||||||
|
return streamfile->size;
|
||||||
|
}
|
||||||
|
static size_t multifile_get_offset(MULTIFILE_STREAMFILE * streamfile) {
|
||||||
|
return streamfile->offset;
|
||||||
|
}
|
||||||
|
static void multifile_get_name(MULTIFILE_STREAMFILE *streamfile, char *buffer, size_t length) {
|
||||||
|
streamfile->inner_sfs[0]->get_name(streamfile->inner_sfs[0], buffer, length);
|
||||||
|
}
|
||||||
|
static void multifile_get_realname(MULTIFILE_STREAMFILE *streamfile, char *buffer, size_t length) {
|
||||||
|
multifile_get_name(streamfile, buffer, length);
|
||||||
|
}
|
||||||
|
static STREAMFILE *multifile_open(MULTIFILE_STREAMFILE *streamfile, const char * const filename, size_t buffersize) {
|
||||||
|
char original_filename[PATH_LIMIT];
|
||||||
|
STREAMFILE *new_sf = NULL;
|
||||||
|
STREAMFILE **new_inner_sfs = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
streamfile->inner_sfs[0]->get_name(streamfile->inner_sfs[0], original_filename, PATH_LIMIT);
|
||||||
|
|
||||||
|
/* detect re-opening the file */
|
||||||
|
if (strcmp(filename, original_filename) == 0) { /* same multifile */
|
||||||
|
new_inner_sfs = calloc(streamfile->inner_sfs_size, sizeof(STREAMFILE*));
|
||||||
|
if (!new_inner_sfs) goto fail;
|
||||||
|
|
||||||
|
for (i = 0; i < streamfile->inner_sfs_size; i++) {
|
||||||
|
streamfile->inner_sfs[i]->get_name(streamfile->inner_sfs[i], original_filename, PATH_LIMIT);
|
||||||
|
new_inner_sfs[i] = streamfile->inner_sfs[i]->open(streamfile->inner_sfs[i], original_filename, buffersize);
|
||||||
|
if (!new_inner_sfs[i]) goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_sf = open_multifile_streamfile(new_inner_sfs, streamfile->inner_sfs_size);
|
||||||
|
if (!new_sf) goto fail;
|
||||||
|
|
||||||
|
return new_sf;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return streamfile->inner_sfs[0]->open(streamfile->inner_sfs[0], filename, buffersize); /* regular file */
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (new_inner_sfs) {
|
||||||
|
for (i = 0; i < streamfile->inner_sfs_size; i++)
|
||||||
|
close_streamfile(new_inner_sfs[i]);
|
||||||
|
}
|
||||||
|
free(new_inner_sfs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
static void multifile_close(MULTIFILE_STREAMFILE *streamfile) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < streamfile->inner_sfs_size; i++) {
|
||||||
|
for (i = 0; i < streamfile->inner_sfs_size; i++)
|
||||||
|
close_streamfile(streamfile->inner_sfs[i]);
|
||||||
|
}
|
||||||
|
free(streamfile->inner_sfs);
|
||||||
|
free(streamfile->sizes);
|
||||||
|
free(streamfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
STREAMFILE *open_multifile_streamfile(STREAMFILE **streamfiles, size_t streamfiles_size) {
|
||||||
|
MULTIFILE_STREAMFILE *this_sf;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!streamfiles || !streamfiles_size) return NULL;
|
||||||
|
for (i = 0; i < streamfiles_size; i++) {
|
||||||
|
if (!streamfiles[i]) return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
this_sf = calloc(1,sizeof(MULTIFILE_STREAMFILE));
|
||||||
|
if (!this_sf) goto fail;
|
||||||
|
|
||||||
|
/* set callbacks and internals */
|
||||||
|
this_sf->sf.read = (void*)multifile_read;
|
||||||
|
this_sf->sf.get_size = (void*)multifile_get_size;
|
||||||
|
this_sf->sf.get_offset = (void*)multifile_get_offset;
|
||||||
|
this_sf->sf.get_name = (void*)multifile_get_name;
|
||||||
|
this_sf->sf.get_realname = (void*)multifile_get_realname;
|
||||||
|
this_sf->sf.open = (void*)multifile_open;
|
||||||
|
this_sf->sf.close = (void*)multifile_close;
|
||||||
|
this_sf->sf.stream_index = streamfiles[0]->stream_index;
|
||||||
|
|
||||||
|
this_sf->inner_sfs_size = streamfiles_size;
|
||||||
|
this_sf->inner_sfs = calloc(streamfiles_size, sizeof(STREAMFILE*));
|
||||||
|
if (!this_sf->inner_sfs) goto fail;
|
||||||
|
this_sf->sizes = calloc(streamfiles_size, sizeof(size_t));
|
||||||
|
if (!this_sf->sizes) goto fail;
|
||||||
|
|
||||||
|
for (i = 0; i < this_sf->inner_sfs_size; i++) {
|
||||||
|
this_sf->inner_sfs[i] = streamfiles[i];
|
||||||
|
this_sf->sizes[i] = streamfiles[i]->get_size(streamfiles[i]);
|
||||||
|
this_sf->size += this_sf->sizes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return &this_sf->sf;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (this_sf) {
|
||||||
|
free(this_sf->inner_sfs);
|
||||||
|
free(this_sf->sizes);
|
||||||
|
}
|
||||||
|
free(this_sf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* **************************************************** */
|
/* **************************************************** */
|
||||||
|
|
||||||
|
@ -393,17 +793,15 @@ STREAMFILE * open_stream_name(STREAMFILE *streamFile, const char * name) {
|
||||||
return streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
return streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* Opens a file containing decryption keys and copies to buffer.
|
||||||
* open file containing decryption keys and copy to buffer
|
* Tries combinations of keynames based on the original filename.
|
||||||
* tries combinations of keynames based on the original filename
|
* returns size of key if found and copied */
|
||||||
*
|
size_t read_key_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile) {
|
||||||
* returns true if found and copied
|
|
||||||
*/
|
|
||||||
int read_key_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile) {
|
|
||||||
char keyname[PATH_LIMIT];
|
char keyname[PATH_LIMIT];
|
||||||
char filename[PATH_LIMIT];
|
char filename[PATH_LIMIT];
|
||||||
const char *path, *ext;
|
const char *path, *ext;
|
||||||
STREAMFILE * streamFileKey = NULL;
|
STREAMFILE * streamFileKey = NULL;
|
||||||
|
size_t keysize;
|
||||||
|
|
||||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||||
|
|
||||||
|
@ -456,17 +854,17 @@ int read_key_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
found:
|
found:
|
||||||
if (get_streamfile_size(streamFileKey) != bufsize) goto fail;
|
keysize = get_streamfile_size(streamFileKey);
|
||||||
|
if (keysize > bufsize) goto fail;
|
||||||
|
|
||||||
if (read_streamfile(buf, 0, bufsize, streamFileKey)!=bufsize) goto fail;
|
if (read_streamfile(buf, 0, keysize, streamFileKey) != keysize)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
close_streamfile(streamFileKey);
|
close_streamfile(streamFileKey);
|
||||||
|
return keysize;
|
||||||
return 1;
|
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (streamFileKey) close_streamfile(streamFileKey);
|
close_streamfile(streamFileKey);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,13 +55,8 @@ typedef struct _STREAMFILE {
|
||||||
struct _STREAMFILE * (*open)(struct _STREAMFILE *,const char * const filename,size_t buffersize);
|
struct _STREAMFILE * (*open)(struct _STREAMFILE *,const char * const filename,size_t buffersize);
|
||||||
void (*close)(struct _STREAMFILE *);
|
void (*close)(struct _STREAMFILE *);
|
||||||
|
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
size_t (*get_bytes_read)(struct _STREAMFILE *);
|
|
||||||
int (*get_error_count)(struct _STREAMFILE *);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
/* Substream selection for files with subsongs. Manually used in metas if supported.
|
||||||
/* Substream selection for files with multiple streams. Manually used in metas if supported.
|
|
||||||
* Not ideal here, but it's the simplest way to pass to all init_vgmstream_x functions. */
|
* Not ideal here, but it's the simplest way to pass to all init_vgmstream_x functions. */
|
||||||
int stream_index; /* 0=default/auto (first), 1=first, N=Nth */
|
int stream_index; /* 0=default/auto (first), 1=first, N=Nth */
|
||||||
|
|
||||||
|
@ -73,9 +68,34 @@ STREAMFILE * open_stdio_streamfile(const char * filename);
|
||||||
/* create a STREAMFILE from pre-opened file path */
|
/* create a STREAMFILE from pre-opened file path */
|
||||||
STREAMFILE * open_stdio_streamfile_by_file(FILE * file, const char * filename);
|
STREAMFILE * open_stdio_streamfile_by_file(FILE * file, const char * filename);
|
||||||
|
|
||||||
|
/* A STREAMFILE that doesn't close the underlying stream.
|
||||||
|
* Calls to open won't wrap the new SF (assumes it needs to be closed).
|
||||||
|
* Can be used in metas to test custom IO without closing the external SF. */
|
||||||
|
STREAMFILE *open_wrap_streamfile(STREAMFILE *streamfile);
|
||||||
|
|
||||||
|
/* A STREAMFILE that clamps IO to a section of a larger stream.
|
||||||
|
* Can be used with subfiles inside a bigger file, so it looks standard to a meta. */
|
||||||
|
STREAMFILE *open_clamp_streamfile(STREAMFILE *streamfile, off_t start, size_t size);
|
||||||
|
|
||||||
|
/* A STREAMFILE with custom IO, that clamps IO to a section of a larger stream.
|
||||||
|
* Can be used with subfiles inside a bigger file, so it looks standard to a meta. */
|
||||||
|
STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_size, void* read_callback);//void* size_callback, void* seek_callback);
|
||||||
|
|
||||||
|
/* A STREAMFILE that reports a fake name, but still re-opens itself properly.
|
||||||
|
* Can be used to trick a meta's extension check (to call from another, with a modified SF).
|
||||||
|
* When fakename isn't supplied it's read from the streamfile, and the extension swapped with fakeext.
|
||||||
|
* If the fakename is an existing file, open won't work on it as it'll reopen the fake-named streamfile. */
|
||||||
|
STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, char * fakename, char * fakeext);
|
||||||
|
|
||||||
|
/* A streamfile formed from multiple streamfiles, their data joined during reads.
|
||||||
|
* Can be used when data is segmented in multiple separate files.
|
||||||
|
* The first streamfile is used to get names, stream index and so on. */
|
||||||
|
STREAMFILE *open_multifile_streamfile(STREAMFILE **streamfiles, size_t streamfiles_size);
|
||||||
|
|
||||||
|
|
||||||
/* close a file, destroy the STREAMFILE object */
|
/* close a file, destroy the STREAMFILE object */
|
||||||
static inline void close_streamfile(STREAMFILE * streamfile) {
|
static inline void close_streamfile(STREAMFILE * streamfile) {
|
||||||
|
if (streamfile==NULL) return;
|
||||||
streamfile->close(streamfile);
|
streamfile->close(streamfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,23 +109,6 @@ static inline size_t get_streamfile_size(STREAMFILE * streamfile) {
|
||||||
return streamfile->get_size(streamfile);
|
return streamfile->get_size(streamfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PROFILE_STREAMFILE
|
|
||||||
/* return how many bytes we read into buffers */
|
|
||||||
static inline size_t get_streamfile_bytes_read(STREAMFILE * streamfile) {
|
|
||||||
if (streamfile->get_bytes_read)
|
|
||||||
return streamfile->get_bytes_read(streamfile);
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return how many times we encountered a read error */
|
|
||||||
static inline int get_streamfile_error_count(STREAMFILE * streamfile) {
|
|
||||||
if (streamfile->get_error_count)
|
|
||||||
return streamfile->get_error_count(streamfile);
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Sometimes you just need an int, and we're doing the buffering.
|
/* Sometimes you just need an int, and we're doing the buffering.
|
||||||
* Note, however, that if these fail to read they'll return -1,
|
* Note, however, that if these fail to read they'll return -1,
|
||||||
|
@ -163,7 +166,7 @@ STREAMFILE * open_stream_name(STREAMFILE *streamFile, const char * ext);
|
||||||
|
|
||||||
int read_string(char * buf, size_t bufsize, off_t offset, STREAMFILE *streamFile);
|
int read_string(char * buf, size_t bufsize, off_t offset, STREAMFILE *streamFile);
|
||||||
|
|
||||||
int read_key_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile);
|
size_t read_key_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile);
|
||||||
int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile);
|
int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile);
|
||||||
|
|
||||||
int check_extensions(STREAMFILE *streamFile, const char * cmp_exts);
|
int check_extensions(STREAMFILE *streamFile, const char * cmp_exts);
|
||||||
|
|
|
@ -373,6 +373,13 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||||
init_vgmstream_ngc_vid1,
|
init_vgmstream_ngc_vid1,
|
||||||
init_vgmstream_flx,
|
init_vgmstream_flx,
|
||||||
init_vgmstream_mogg,
|
init_vgmstream_mogg,
|
||||||
|
init_vgmstream_kma9,
|
||||||
|
init_vgmstream_fsb_encrypted,
|
||||||
|
init_vgmstream_xwc,
|
||||||
|
init_vgmstream_atsl3,
|
||||||
|
init_vgmstream_sps_n1,
|
||||||
|
init_vgmstream_atx,
|
||||||
|
init_vgmstream_sqex_sead,
|
||||||
|
|
||||||
init_vgmstream_txth, /* should go at the end (lower priority) */
|
init_vgmstream_txth, /* should go at the end (lower priority) */
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
|
@ -973,6 +980,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
|
||||||
case layout_blocked_awc:
|
case layout_blocked_awc:
|
||||||
case layout_blocked_vgs:
|
case layout_blocked_vgs:
|
||||||
case layout_blocked_vawx:
|
case layout_blocked_vawx:
|
||||||
|
case layout_blocked_xvag_subsong:
|
||||||
render_vgmstream_blocked(buffer,sample_count,vgmstream);
|
render_vgmstream_blocked(buffer,sample_count,vgmstream);
|
||||||
break;
|
break;
|
||||||
case layout_acm:
|
case layout_acm:
|
||||||
|
@ -2192,6 +2200,11 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||||
}
|
}
|
||||||
concatn(length,desc,temp);
|
concatn(length,desc,temp);
|
||||||
|
|
||||||
|
snprintf(temp,TEMPSIZE,
|
||||||
|
"\nbitrate: %d kbps",
|
||||||
|
get_vgmstream_average_bitrate(vgmstream) / 1000);
|
||||||
|
concatn(length,desc,temp);
|
||||||
|
|
||||||
/* only interesting if more than one */
|
/* only interesting if more than one */
|
||||||
if (vgmstream->num_streams > 1) {
|
if (vgmstream->num_streams > 1) {
|
||||||
snprintf(temp,TEMPSIZE,
|
snprintf(temp,TEMPSIZE,
|
||||||
|
@ -2440,9 +2453,11 @@ static STREAMFILE * get_vgmstream_average_bitrate_channel_streamfile(VGMSTREAM *
|
||||||
return vgmstream->ch[channel].streamfile;
|
return vgmstream->ch[channel].streamfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_vgmstream_average_bitrate_from_size(size_t size, int sample_rate, int length_samples) {
|
||||||
|
return (int)((int64_t)size * 8 * sample_rate / length_samples);
|
||||||
|
}
|
||||||
static int get_vgmstream_average_bitrate_from_streamfile(STREAMFILE * streamfile, int sample_rate, int length_samples) {
|
static int get_vgmstream_average_bitrate_from_streamfile(STREAMFILE * streamfile, int sample_rate, int length_samples) {
|
||||||
// todo: not correct in subsongs or formats which only use part of the data
|
return get_vgmstream_average_bitrate_from_size(get_streamfile_size(streamfile), sample_rate, length_samples);
|
||||||
return (int)((int64_t)get_streamfile_size(streamfile) * 8 * sample_rate / length_samples);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the average bitrate in bps of all unique files contained within this stream. */
|
/* Return the average bitrate in bps of all unique files contained within this stream. */
|
||||||
|
@ -2460,6 +2475,11 @@ int get_vgmstream_average_bitrate(VGMSTREAM * vgmstream) {
|
||||||
if (!sample_rate || !channels || !length_samples)
|
if (!sample_rate || !channels || !length_samples)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* subsongs need to report this to properly calculate */
|
||||||
|
if (vgmstream->stream_size) {
|
||||||
|
return get_vgmstream_average_bitrate_from_size(vgmstream->stream_size, sample_rate, length_samples);
|
||||||
|
}
|
||||||
|
|
||||||
if (channels >= 1) {
|
if (channels >= 1) {
|
||||||
streamFile = get_vgmstream_average_bitrate_channel_streamfile(vgmstream, 0);
|
streamFile = get_vgmstream_average_bitrate_channel_streamfile(vgmstream, 0);
|
||||||
if (streamFile) {
|
if (streamFile) {
|
||||||
|
|
|
@ -258,6 +258,7 @@ typedef enum {
|
||||||
layout_blocked_awc, /* Rockstar AWC */
|
layout_blocked_awc, /* Rockstar AWC */
|
||||||
layout_blocked_vgs, /* Guitar Hero II (PS2) */
|
layout_blocked_vgs, /* Guitar Hero II (PS2) */
|
||||||
layout_blocked_vawx, /* No More Heroes 6ch (PS3) */
|
layout_blocked_vawx, /* No More Heroes 6ch (PS3) */
|
||||||
|
layout_blocked_xvag_subsong, /* XVAG subsongs [God of War III (PS4)] */
|
||||||
|
|
||||||
/* otherwise odd */
|
/* otherwise odd */
|
||||||
layout_acm, /* libacm layout */
|
layout_acm, /* libacm layout */
|
||||||
|
@ -652,16 +653,20 @@ typedef enum {
|
||||||
meta_NGC_VID1, /* Neversoft .ogg (Gun GC) */
|
meta_NGC_VID1, /* Neversoft .ogg (Gun GC) */
|
||||||
meta_PC_FLX, /* Ultima IX PC */
|
meta_PC_FLX, /* Ultima IX PC */
|
||||||
meta_MOGG, /* Harmonix Music Systems MOGG Vorbis */
|
meta_MOGG, /* Harmonix Music Systems MOGG Vorbis */
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
meta_OGG_VORBIS, /* Ogg Vorbis */
|
meta_OGG_VORBIS, /* Ogg Vorbis */
|
||||||
meta_OGG_SLI, /* Ogg Vorbis file w/ companion .sli for looping */
|
meta_OGG_SLI, /* Ogg Vorbis file w/ companion .sli for looping */
|
||||||
meta_OGG_SLI2, /* Ogg Vorbis file w/ different styled .sli for looping */
|
meta_OGG_SLI2, /* Ogg Vorbis file w/ different styled .sli for looping */
|
||||||
meta_OGG_SFL, /* Ogg Vorbis file w/ .sfl (RIFF SFPL) for looping */
|
meta_OGG_SFL, /* Ogg Vorbis file w/ .sfl (RIFF SFPL) for looping */
|
||||||
meta_OGG_UM3, /* Ogg Vorbis with first 0x800 bytes XOR 0xFF */
|
meta_OGG_UM3, /* Ogg Vorbis with optional encryption */
|
||||||
meta_OGG_KOVS, /* Ogg Vorbis with exta header and 0x100 bytes XOR */
|
meta_OGG_KOVS, /* Ogg Vorbis with encryption (Koei Tecmo Games) */
|
||||||
meta_OGG_PSYCH, /* Ogg Vorbis with all bytes -0x23*/
|
meta_OGG_PSYCHIC, /* Ogg Vorbis with encryption */
|
||||||
#endif
|
meta_OGG_SNGW, /* Ogg Vorbis with optional encryption (Capcom PC games) */
|
||||||
|
meta_OGG_ISD, /* Ogg Vorbis with encryption (Azure Striker Gunvolt PC) */
|
||||||
|
meta_KMA9, /* Koei Tecmo [Nobunaga no Yabou - Souzou (Vita)] */
|
||||||
|
meta_XWC, /* Starbreeze games */
|
||||||
|
meta_SQEX_SAB, /* Square-Enix newest middleware (sound) */
|
||||||
|
meta_SQEX_MAB, /* Square-Enix newest middleware (music) */
|
||||||
|
|
||||||
#ifdef VGM_USE_MP4V2
|
#ifdef VGM_USE_MP4V2
|
||||||
meta_MP4, /* AAC (iOS) */
|
meta_MP4, /* AAC (iOS) */
|
||||||
#endif
|
#endif
|
||||||
|
@ -739,6 +744,7 @@ typedef struct {
|
||||||
int num_streams; /* for multi-stream formats (0=not set/one stream, 1=one stream) */
|
int num_streams; /* for multi-stream formats (0=not set/one stream, 1=one stream) */
|
||||||
int stream_index; /* selected stream (also 1-based) */
|
int stream_index; /* selected stream (also 1-based) */
|
||||||
char stream_name[STREAM_NAME_SIZE]; /* name of the current stream (info), if the file stores it and it's filled */
|
char stream_name[STREAM_NAME_SIZE]; /* name of the current stream (info), if the file stores it and it's filled */
|
||||||
|
size_t stream_size; /* info to properly calculate bitrate */
|
||||||
|
|
||||||
/* looping */
|
/* looping */
|
||||||
int loop_flag; /* is this stream looped? */
|
int loop_flag; /* is this stream looped? */
|
||||||
|
@ -801,15 +807,16 @@ typedef struct {
|
||||||
/* Ogg with Vorbis */
|
/* Ogg with Vorbis */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
STREAMFILE *streamfile;
|
STREAMFILE *streamfile;
|
||||||
ogg_int64_t offset;
|
ogg_int64_t start; /* file offset where the Ogg starts */
|
||||||
ogg_int64_t size;
|
ogg_int64_t offset; /* virtual offset, from 0 to size */
|
||||||
ogg_int64_t other_header_bytes;
|
ogg_int64_t size; /* virtual size of the Ogg */
|
||||||
|
|
||||||
/* XOR setup (SCD) */
|
/* decryption setup */
|
||||||
int decryption_enabled;
|
void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource);
|
||||||
void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read);
|
|
||||||
uint8_t scd_xor;
|
uint8_t scd_xor;
|
||||||
off_t scd_xor_length;
|
off_t scd_xor_length;
|
||||||
|
uint32_t sngw_xor;
|
||||||
|
|
||||||
} ogg_vorbis_streamfile;
|
} ogg_vorbis_streamfile;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -831,9 +838,9 @@ typedef enum {
|
||||||
} vorbis_custom_t;
|
} vorbis_custom_t;
|
||||||
|
|
||||||
/* config for Wwise Vorbis (3 types for flexibility though not all combinations exist) */
|
/* config for Wwise Vorbis (3 types for flexibility though not all combinations exist) */
|
||||||
typedef enum { HEADER_TRIAD, FULL_SETUP, INLINE_CODEBOOKS, EXTERNAL_CODEBOOKS, AOTUV603_CODEBOOKS } wwise_setup_t; /* Vorbis setup style */
|
typedef enum { WWV_HEADER_TRIAD, WWV_FULL_SETUP, WWV_INLINE_CODEBOOKS, WWV_EXTERNAL_CODEBOOKS, WWV_AOTUV603_CODEBOOKS } wwise_setup_t;
|
||||||
typedef enum { TYPE_8, TYPE_6, TYPE_2 } wwise_header_t; /* size of packet headers */
|
typedef enum { WWV_TYPE_8, WWV_TYPE_6, WWV_TYPE_2 } wwise_header_t;
|
||||||
typedef enum { STANDARD, MODIFIED } wwise_packet_t; /* type of Vorbis packets */
|
typedef enum { WWV_STANDARD, WWV_MODIFIED } wwise_packet_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* to reconstruct init packets */
|
/* to reconstruct init packets */
|
||||||
|
@ -1001,6 +1008,7 @@ typedef struct {
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ATRAC9_DEFAULT = 0, /* ATRAC9 standard */
|
ATRAC9_DEFAULT = 0, /* ATRAC9 standard */
|
||||||
ATRAC9_XVAG, /* Sony XVAG: interleaved subsongs, Vita multichannel interleaves 2ch xN superframes */
|
ATRAC9_XVAG, /* Sony XVAG: interleaved subsongs, Vita multichannel interleaves 2ch xN superframes */
|
||||||
|
ATRAC9_KMA9, /* Koei Tecmo KMA9: interleaved subsongs */
|
||||||
//ATRAC9_FSB, /* FMOD FSB: Vita multichannel interleaves 2ch xN superframes */
|
//ATRAC9_FSB, /* FMOD FSB: Vita multichannel interleaves 2ch xN superframes */
|
||||||
//ATRAC9_EATRAX, /* EA EATrax: buffered ATRAC9 in SPS blocks (superframes can be split between blocks) */
|
//ATRAC9_EATRAX, /* EA EATrax: buffered ATRAC9 in SPS blocks (superframes can be split between blocks) */
|
||||||
} atrac9_custom_t;
|
} atrac9_custom_t;
|
||||||
|
@ -1100,7 +1108,6 @@ typedef enum {
|
||||||
FFMPEG_STANDARD, /* default FFmpeg */
|
FFMPEG_STANDARD, /* default FFmpeg */
|
||||||
FFMPEG_SWITCH_OPUS, /* Opus without Ogg layer */
|
FFMPEG_SWITCH_OPUS, /* Opus without Ogg layer */
|
||||||
FFMPEG_EA_XMA, /* XMA with padding removed and custom streams in SNS blocks */
|
FFMPEG_EA_XMA, /* XMA with padding removed and custom streams in SNS blocks */
|
||||||
FFMPEG_BGW_ATRAC3, /* Encrypted raw ATRAC3 */
|
|
||||||
//FFMPEG_EA_SCHL, /* Normal header+data (ex. ATRAC3) in SCxx blocks */
|
//FFMPEG_EA_SCHL, /* Normal header+data (ex. ATRAC3) in SCxx blocks */
|
||||||
//FFMPEG_SFH, /* ATRAC3plus header+data in SFH blocks */
|
//FFMPEG_SFH, /* ATRAC3plus header+data in SFH blocks */
|
||||||
//FFMPEG_AWC_XMA, /* XMA data in AWC blocks, 1 streams per channel */
|
//FFMPEG_AWC_XMA, /* XMA data in AWC blocks, 1 streams per channel */
|
||||||
|
@ -1118,7 +1125,6 @@ typedef struct {
|
||||||
/* internal sequences, when needed */
|
/* internal sequences, when needed */
|
||||||
int sequence;
|
int sequence;
|
||||||
int samples_done;
|
int samples_done;
|
||||||
uint8_t * key;
|
|
||||||
} ffmpeg_custom_config;
|
} ffmpeg_custom_config;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
Loading…
Reference in New Issue