Updated VGMStream to r1050-449-gd2fac791.

CQTexperiment
Christopher Snowhill 2017-04-22 21:20:23 -07:00
parent c291a4885b
commit 22fa3a3df0
42 changed files with 12649 additions and 1173 deletions

View File

@ -10,12 +10,27 @@
48C2650F1A5D420800A0A3D6 /* vorbisfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 48C2650E1A5D420800A0A3D6 /* vorbisfile.h */; };
8313E3E61902020400B4B6F1 /* mpg123.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8313E3431901FBDD00B4B6F1 /* mpg123.framework */; };
8313E3E71902021800B4B6F1 /* mpg123.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8313E3431901FBDD00B4B6F1 /* mpg123.framework */; };
831BA6181EAC61A500CF89B0 /* adx.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA60E1EAC61A500CF89B0 /* adx.c */; };
831BA6191EAC61A500CF89B0 /* ogl.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA60F1EAC61A500CF89B0 /* ogl.c */; };
831BA61A1EAC61A500CF89B0 /* ps2_vds_vdm.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6101EAC61A500CF89B0 /* ps2_vds_vdm.c */; };
831BA61B1EAC61A500CF89B0 /* sgxd.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6111EAC61A500CF89B0 /* sgxd.c */; };
831BA61C1EAC61A500CF89B0 /* sxd.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6121EAC61A500CF89B0 /* sxd.c */; };
831BA61D1EAC61A500CF89B0 /* ubi_raki.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6131EAC61A500CF89B0 /* ubi_raki.c */; };
831BA61E1EAC61A500CF89B0 /* vawx.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6141EAC61A500CF89B0 /* vawx.c */; };
831BA61F1EAC61A500CF89B0 /* x360_cxs.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6151EAC61A500CF89B0 /* x360_cxs.c */; };
831BA6201EAC61A500CF89B0 /* x360_nub.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6161EAC61A500CF89B0 /* x360_nub.c */; };
831BA6211EAC61A500CF89B0 /* x360_pasx.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6171EAC61A500CF89B0 /* x360_pasx.c */; };
831BA6281EAC61CB00CF89B0 /* coding_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6221EAC61CB00CF89B0 /* coding_utils.c */; };
831BA6291EAC61CB00CF89B0 /* ogl_vorbis_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6231EAC61CB00CF89B0 /* ogl_vorbis_decoder.c */; };
831BA62A1EAC61CB00CF89B0 /* wwise_vorbis_data.h in Headers */ = {isa = PBXBuildFile; fileRef = 831BA6241EAC61CB00CF89B0 /* wwise_vorbis_data.h */; };
831BA62B1EAC61CB00CF89B0 /* wwise_vorbis_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6251EAC61CB00CF89B0 /* wwise_vorbis_decoder.c */; };
831BA62C1EAC61CB00CF89B0 /* wwise_vorbis_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA6261EAC61CB00CF89B0 /* wwise_vorbis_utils.c */; };
831BA62D1EAC61CB00CF89B0 /* wwise_vorbis_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 831BA6271EAC61CB00CF89B0 /* wwise_vorbis_utils.h */; };
8321405A1E8758D7001A8A5E /* fsb_vorbis_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 832140591E8758D7001A8A5E /* fsb_vorbis_decoder.c */; };
8323894A1D22419B00482226 /* clHCA.c in Sources */ = {isa = PBXBuildFile; fileRef = 832389481D22419B00482226 /* clHCA.c */; };
8323894B1D22419B00482226 /* clHCA.h in Headers */ = {isa = PBXBuildFile; fileRef = 832389491D22419B00482226 /* clHCA.h */; settings = {ATTRIBUTES = (Public, ); }; };
832389501D2246C300482226 /* hca.c in Sources */ = {isa = PBXBuildFile; fileRef = 8323894F1D2246C300482226 /* hca.c */; };
832389521D224C0800482226 /* hca_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 832389511D224C0800482226 /* hca_decoder.c */; };
83299FC61E76606B003A3242 /* ffmpeg_decoder_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 83299FC51E76606B003A3242 /* ffmpeg_decoder_utils.c */; };
83299FCC1E76607A003A3242 /* header.c in Sources */ = {isa = PBXBuildFile; fileRef = 83299FCA1E76607A003A3242 /* header.c */; };
83299FCD1E76607A003A3242 /* header.h in Headers */ = {isa = PBXBuildFile; fileRef = 83299FCB1E76607A003A3242 /* header.h */; };
83299FD01E7660C7003A3242 /* bik.c in Sources */ = {isa = PBXBuildFile; fileRef = 83299FCE1E7660C7003A3242 /* bik.c */; };
@ -95,7 +110,6 @@
836F6F6618BDC2190095E648 /* aax.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2A18BDC2180095E648 /* aax.c */; };
836F6F6718BDC2190095E648 /* acm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2B18BDC2180095E648 /* acm.c */; };
836F6F6818BDC2190095E648 /* ads.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2C18BDC2180095E648 /* ads.c */; };
836F6F6918BDC2190095E648 /* adx_header.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2D18BDC2180095E648 /* adx_header.c */; };
836F6F6A18BDC2190095E648 /* afc_header.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2E18BDC2180095E648 /* afc_header.c */; };
836F6F6B18BDC2190095E648 /* agsc.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E2F18BDC2180095E648 /* agsc.c */; };
836F6F6C18BDC2190095E648 /* ahx.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E3018BDC2180095E648 /* ahx.c */; };
@ -267,8 +281,6 @@
836F701318BDC2190095E648 /* ps3_klbs.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED718BDC2190095E648 /* ps3_klbs.c */; };
836F701418BDC2190095E648 /* ps3_msf.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED818BDC2190095E648 /* ps3_msf.c */; };
836F701518BDC2190095E648 /* ps3_past.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED918BDC2190095E648 /* ps3_past.c */; };
836F701618BDC2190095E648 /* ps3_sgh_sgb.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EDA18BDC2190095E648 /* ps3_sgh_sgb.c */; };
836F701718BDC2190095E648 /* ps3_vawx.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EDB18BDC2190095E648 /* ps3_vawx.c */; };
836F701818BDC2190095E648 /* ps3_xvag.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EDC18BDC2190095E648 /* ps3_xvag.c */; };
836F701918BDC2190095E648 /* psx_cdxa.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EDD18BDC2190095E648 /* psx_cdxa.c */; };
836F701A18BDC2190095E648 /* psx_fag.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EDE18BDC2190095E648 /* psx_fag.c */; };
@ -353,8 +365,6 @@
83A3F0741E3AD8B900D6A794 /* formats.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A3F0711E3AD8B900D6A794 /* formats.c */; };
83A3F0751E3AD8B900D6A794 /* formats.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A3F0721E3AD8B900D6A794 /* formats.h */; };
83A3F0761E3AD8B900D6A794 /* stack_alloc.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A3F0731E3AD8B900D6A794 /* stack_alloc.h */; };
83A3F07C1E3AD92400D6A794 /* ps2.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A3F07A1E3AD92400D6A794 /* ps2.c */; };
83A3F07D1E3AD92400D6A794 /* x360.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A3F07B1E3AD92400D6A794 /* x360.c */; };
83A5F75F198DF021009AF94C /* bfwav.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A5F75E198DF021009AF94C /* bfwav.c */; };
83AB8C751E8072A100086084 /* nub_vag.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AB8C731E8072A100086084 /* nub_vag.c */; };
83AB8C761E8072A100086084 /* x360_ast.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AB8C741E8072A100086084 /* x360_ast.c */; };
@ -475,12 +485,27 @@
/* Begin PBXFileReference section */
48C2650E1A5D420800A0A3D6 /* vorbisfile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = vorbisfile.h; path = ../Vorbis/include/vorbis/vorbisfile.h; sourceTree = "<group>"; };
8313E33D1901FBDC00B4B6F1 /* mpg123.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = mpg123.xcodeproj; path = ../mpg123/mpg123.xcodeproj; sourceTree = "<group>"; };
831BA60E1EAC61A500CF89B0 /* adx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adx.c; sourceTree = "<group>"; };
831BA60F1EAC61A500CF89B0 /* ogl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ogl.c; sourceTree = "<group>"; };
831BA6101EAC61A500CF89B0 /* ps2_vds_vdm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_vds_vdm.c; sourceTree = "<group>"; };
831BA6111EAC61A500CF89B0 /* sgxd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sgxd.c; sourceTree = "<group>"; };
831BA6121EAC61A500CF89B0 /* sxd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sxd.c; sourceTree = "<group>"; };
831BA6131EAC61A500CF89B0 /* ubi_raki.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ubi_raki.c; sourceTree = "<group>"; };
831BA6141EAC61A500CF89B0 /* vawx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vawx.c; sourceTree = "<group>"; };
831BA6151EAC61A500CF89B0 /* x360_cxs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x360_cxs.c; sourceTree = "<group>"; };
831BA6161EAC61A500CF89B0 /* x360_nub.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x360_nub.c; sourceTree = "<group>"; };
831BA6171EAC61A500CF89B0 /* x360_pasx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x360_pasx.c; sourceTree = "<group>"; };
831BA6221EAC61CB00CF89B0 /* coding_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = coding_utils.c; sourceTree = "<group>"; };
831BA6231EAC61CB00CF89B0 /* ogl_vorbis_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ogl_vorbis_decoder.c; sourceTree = "<group>"; };
831BA6241EAC61CB00CF89B0 /* wwise_vorbis_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wwise_vorbis_data.h; sourceTree = "<group>"; };
831BA6251EAC61CB00CF89B0 /* wwise_vorbis_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wwise_vorbis_decoder.c; sourceTree = "<group>"; };
831BA6261EAC61CB00CF89B0 /* wwise_vorbis_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wwise_vorbis_utils.c; sourceTree = "<group>"; };
831BA6271EAC61CB00CF89B0 /* wwise_vorbis_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wwise_vorbis_utils.h; sourceTree = "<group>"; };
832140591E8758D7001A8A5E /* fsb_vorbis_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fsb_vorbis_decoder.c; sourceTree = "<group>"; };
832389481D22419B00482226 /* clHCA.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = clHCA.c; sourceTree = "<group>"; };
832389491D22419B00482226 /* clHCA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = clHCA.h; sourceTree = "<group>"; };
8323894F1D2246C300482226 /* hca.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hca.c; sourceTree = "<group>"; };
832389511D224C0800482226 /* hca_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hca_decoder.c; sourceTree = "<group>"; };
83299FC51E76606B003A3242 /* ffmpeg_decoder_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffmpeg_decoder_utils.c; sourceTree = "<group>"; };
83299FCA1E76607A003A3242 /* header.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = header.c; sourceTree = "<group>"; };
83299FCB1E76607A003A3242 /* header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = header.h; sourceTree = "<group>"; };
83299FCE1E7660C7003A3242 /* bik.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bik.c; sourceTree = "<group>"; };
@ -561,7 +586,6 @@
836F6E2A18BDC2180095E648 /* aax.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aax.c; sourceTree = "<group>"; };
836F6E2B18BDC2180095E648 /* acm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = acm.c; sourceTree = "<group>"; };
836F6E2C18BDC2180095E648 /* ads.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ads.c; sourceTree = "<group>"; };
836F6E2D18BDC2180095E648 /* adx_header.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adx_header.c; sourceTree = "<group>"; };
836F6E2E18BDC2180095E648 /* afc_header.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = afc_header.c; sourceTree = "<group>"; };
836F6E2F18BDC2180095E648 /* agsc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = agsc.c; sourceTree = "<group>"; };
836F6E3018BDC2180095E648 /* ahx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ahx.c; sourceTree = "<group>"; };
@ -733,8 +757,6 @@
836F6ED718BDC2190095E648 /* ps3_klbs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_klbs.c; sourceTree = "<group>"; };
836F6ED818BDC2190095E648 /* ps3_msf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_msf.c; sourceTree = "<group>"; };
836F6ED918BDC2190095E648 /* ps3_past.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_past.c; sourceTree = "<group>"; };
836F6EDA18BDC2190095E648 /* ps3_sgh_sgb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_sgh_sgb.c; sourceTree = "<group>"; };
836F6EDB18BDC2190095E648 /* ps3_vawx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_vawx.c; sourceTree = "<group>"; };
836F6EDC18BDC2190095E648 /* ps3_xvag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_xvag.c; sourceTree = "<group>"; };
836F6EDD18BDC2190095E648 /* psx_cdxa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = psx_cdxa.c; sourceTree = "<group>"; };
836F6EDE18BDC2190095E648 /* psx_fag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = psx_fag.c; sourceTree = "<group>"; };
@ -819,8 +841,6 @@
83A3F0711E3AD8B900D6A794 /* formats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = formats.c; sourceTree = "<group>"; };
83A3F0721E3AD8B900D6A794 /* formats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = formats.h; sourceTree = "<group>"; };
83A3F0731E3AD8B900D6A794 /* stack_alloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stack_alloc.h; sourceTree = "<group>"; };
83A3F07A1E3AD92400D6A794 /* ps2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2.c; sourceTree = "<group>"; };
83A3F07B1E3AD92400D6A794 /* x360.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x360.c; sourceTree = "<group>"; };
83A5F75E198DF021009AF94C /* bfwav.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bfwav.c; sourceTree = "<group>"; };
83AB8C731E8072A100086084 /* nub_vag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nub_vag.c; sourceTree = "<group>"; };
83AB8C741E8072A100086084 /* x360_ast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x360_ast.c; sourceTree = "<group>"; };
@ -974,9 +994,14 @@
836F6DDF18BDC2180095E648 /* coding */ = {
isa = PBXGroup;
children = (
831BA6221EAC61CB00CF89B0 /* coding_utils.c */,
831BA6231EAC61CB00CF89B0 /* ogl_vorbis_decoder.c */,
831BA6241EAC61CB00CF89B0 /* wwise_vorbis_data.h */,
831BA6251EAC61CB00CF89B0 /* wwise_vorbis_decoder.c */,
831BA6261EAC61CB00CF89B0 /* wwise_vorbis_utils.c */,
831BA6271EAC61CB00CF89B0 /* wwise_vorbis_utils.h */,
836E15DD1E88A3380029F8AD /* fsb_vorbis_data.h */,
832140591E8758D7001A8A5E /* fsb_vorbis_decoder.c */,
83299FC51E76606B003A3242 /* ffmpeg_decoder_utils.c */,
838BDB6B1D3AFAB10022CA6F /* ffmpeg_decoder.c */,
832389511D224C0800482226 /* hca_decoder.c */,
83D7318B1A749EEE00CA1366 /* g719_decoder.c */,
@ -1059,13 +1084,21 @@
836F6E2718BDC2180095E648 /* meta */ = {
isa = PBXGroup;
children = (
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 */,
831BA6161EAC61A500CF89B0 /* x360_nub.c */,
831BA6171EAC61A500CF89B0 /* x360_pasx.c */,
83FF0EBB1E93282100C58054 /* wwise.c */,
83AB8C731E8072A100086084 /* nub_vag.c */,
83AB8C741E8072A100086084 /* x360_ast.c */,
83299FCE1E7660C7003A3242 /* bik.c */,
83299FCF1E7660C7003A3242 /* dsp_adx.c */,
83A3F07A1E3AD92400D6A794 /* ps2.c */,
83A3F07B1E3AD92400D6A794 /* x360.c */,
8350C0591E071990009E0A93 /* ps2_svag_snk.c */,
8350C0541E071881009E0A93 /* xma.c */,
838BDB6D1D3B043C0022CA6F /* ffmpeg.c */,
@ -1080,7 +1113,6 @@
836F6E2A18BDC2180095E648 /* aax.c */,
836F6E2B18BDC2180095E648 /* acm.c */,
836F6E2C18BDC2180095E648 /* ads.c */,
836F6E2D18BDC2180095E648 /* adx_header.c */,
836F6E2E18BDC2180095E648 /* afc_header.c */,
836F6E2F18BDC2180095E648 /* agsc.c */,
836F6E3018BDC2180095E648 /* ahx.c */,
@ -1252,8 +1284,6 @@
836F6ED718BDC2190095E648 /* ps3_klbs.c */,
836F6ED818BDC2190095E648 /* ps3_msf.c */,
836F6ED918BDC2190095E648 /* ps3_past.c */,
836F6EDA18BDC2190095E648 /* ps3_sgh_sgb.c */,
836F6EDB18BDC2190095E648 /* ps3_vawx.c */,
836F6EDC18BDC2190095E648 /* ps3_xvag.c */,
836F6EDD18BDC2190095E648 /* psx_cdxa.c */,
836F6EDE18BDC2190095E648 /* psx_fag.c */,
@ -1353,12 +1383,14 @@
files = (
836F705518BDC2190095E648 /* streamtypes.h in Headers */,
836F6F1F18BDC2190095E648 /* acm_decoder.h in Headers */,
831BA62A1EAC61CB00CF89B0 /* wwise_vorbis_data.h in Headers */,
836F6F3518BDC2190095E648 /* nwa_decoder.h in Headers */,
836F6F2718BDC2190095E648 /* g72x_state.h in Headers */,
836F705418BDC2190095E648 /* streamfile.h in Headers */,
83A3F0761E3AD8B900D6A794 /* stack_alloc.h in Headers */,
8323894B1D22419B00482226 /* clHCA.h in Headers */,
83A3F0751E3AD8B900D6A794 /* formats.h in Headers */,
831BA62D1EAC61CB00CF89B0 /* wwise_vorbis_utils.h in Headers */,
83299FCD1E76607A003A3242 /* header.h in Headers */,
836F705918BDC2190095E648 /* vgmstream.h in Headers */,
48C2650F1A5D420800A0A3D6 /* vorbisfile.h in Headers */,
@ -1532,7 +1564,6 @@
836F6FD418BDC2190095E648 /* ps2_dxh.c in Sources */,
836F700C18BDC2190095E648 /* ps2_wb.c in Sources */,
836F6F7D18BDC2190095E648 /* dc_str.c in Sources */,
836F701718BDC2190095E648 /* ps3_vawx.c in Sources */,
83A5F75F198DF021009AF94C /* bfwav.c in Sources */,
836F702018BDC2190095E648 /* rkv.c in Sources */,
836F703218BDC2190095E648 /* str_asr.c in Sources */,
@ -1589,10 +1620,10 @@
836F6F2418BDC2190095E648 /* eaxa_decoder.c in Sources */,
836F6F7A18BDC2190095E648 /* dc_dcsw_dcs.c in Sources */,
836F6F5318BDC2190095E648 /* ps2_iab_blocked.c in Sources */,
831BA61A1EAC61A500CF89B0 /* ps2_vds_vdm.c in Sources */,
836F6FF218BDC2190095E648 /* ps2_rnd.c in Sources */,
836F6FA818BDC2190095E648 /* nds_swav.c in Sources */,
836F6F3F18BDC2190095E648 /* ast_blocked.c in Sources */,
83299FC61E76606B003A3242 /* ffmpeg_decoder_utils.c in Sources */,
836F6F5018BDC2190095E648 /* mxch_blocked.c in Sources */,
836F6FB518BDC2190095E648 /* ngc_pdt.c in Sources */,
836F6F4F18BDC2190095E648 /* mus_acm_layout.c in Sources */,
@ -1643,7 +1674,6 @@
836F700A18BDC2190095E648 /* ps2_vpk.c in Sources */,
836F6F7318BDC2190095E648 /* bcstm.c in Sources */,
83299FD11E7660C7003A3242 /* dsp_adx.c in Sources */,
83A3F07D1E3AD92400D6A794 /* x360.c in Sources */,
836F704018BDC2190095E648 /* wii_sng.c in Sources */,
8350C0551E071881009E0A93 /* xma.c in Sources */,
836F6F3218BDC2190095E648 /* ngc_dsp_decoder.c in Sources */,
@ -1694,7 +1724,6 @@
836F6F3118BDC2190095E648 /* ngc_afc_decoder.c in Sources */,
836F6FE718BDC2190095E648 /* ps2_mib.c in Sources */,
836F6FAB18BDC2190095E648 /* ngc_bo2.c in Sources */,
83A3F07C1E3AD92400D6A794 /* ps2.c in Sources */,
836F6F9918BDC2190095E648 /* maxis_xa.c in Sources */,
836F702118BDC2190095E648 /* rs03.c in Sources */,
836F6F8418BDC2190095E648 /* emff.c in Sources */,
@ -1703,6 +1732,7 @@
836F6F4618BDC2190095E648 /* filp_blocked.c in Sources */,
836F6FE518BDC2190095E648 /* ps2_lpcm.c in Sources */,
836F6FB318BDC2190095E648 /* ngc_lps.c in Sources */,
831BA6201EAC61A500CF89B0 /* x360_nub.c in Sources */,
836F6FC018BDC2190095E648 /* p3d.c in Sources */,
836F6FC718BDC2190095E648 /* pona.c in Sources */,
836F6FE618BDC2190095E648 /* ps2_mcg.c in Sources */,
@ -1710,19 +1740,24 @@
836F6F5118BDC2190095E648 /* nolayout.c in Sources */,
836F702918BDC2190095E648 /* sat_sap.c in Sources */,
836F6F3718BDC2190095E648 /* pcm_decoder.c in Sources */,
831BA6281EAC61CB00CF89B0 /* coding_utils.c in Sources */,
836F6F5B18BDC2190095E648 /* ws_aud_blocked.c in Sources */,
836F700218BDC2190095E648 /* ps2_tk5.c in Sources */,
831BA61D1EAC61A500CF89B0 /* ubi_raki.c in Sources */,
836F703F18BDC2190095E648 /* wii_smp.c in Sources */,
836F6FB818BDC2190095E648 /* ngc_tydsp.c in Sources */,
836F701518BDC2190095E648 /* ps3_past.c in Sources */,
836F6F7C18BDC2190095E648 /* dc_kcey.c in Sources */,
836F6FED18BDC2190095E648 /* ps2_npsf.c in Sources */,
836F6F9E18BDC2190095E648 /* mus_acm.c in Sources */,
831BA6191EAC61A500CF89B0 /* ogl.c in Sources */,
831BA61F1EAC61A500CF89B0 /* x360_cxs.c in Sources */,
836F6FCD18BDC2190095E648 /* ps2_ass.c in Sources */,
836F6FFE18BDC2190095E648 /* ps2_str.c in Sources */,
836F6F4A18BDC2190095E648 /* interleave.c in Sources */,
836F6FFD18BDC2190095E648 /* ps2_stm.c in Sources */,
83EDE5D81A70951A005F5D84 /* mca.c in Sources */,
831BA61B1EAC61A500CF89B0 /* sgxd.c in Sources */,
838BDB6C1D3AFAB10022CA6F /* ffmpeg_decoder.c in Sources */,
836F6FA518BDC2190095E648 /* nds_rrds.c in Sources */,
836F702F18BDC2190095E648 /* spt_spd.c in Sources */,
@ -1736,6 +1771,7 @@
836F6F5418BDC2190095E648 /* ps2_strlr_blocked.c in Sources */,
836F703D18BDC2190095E648 /* wii_mus.c in Sources */,
836F700D18BDC2190095E648 /* ps2_wmus.c in Sources */,
831BA61C1EAC61A500CF89B0 /* sxd.c in Sources */,
836F6F8018BDC2190095E648 /* dsp_bdsp.c in Sources */,
836F6F9618BDC2190095E648 /* lsf.c in Sources */,
836F6FC818BDC2190095E648 /* pos.c in Sources */,
@ -1750,6 +1786,7 @@
836F703318BDC2190095E648 /* str_snds.c in Sources */,
836F703718BDC2190095E648 /* tun.c in Sources */,
836F700B18BDC2190095E648 /* ps2_wad.c in Sources */,
831BA61E1EAC61A500CF89B0 /* vawx.c in Sources */,
836F702A18BDC2190095E648 /* sd9.c in Sources */,
836F6FB418BDC2190095E648 /* ngc_nst_dsp.c in Sources */,
836F6F4418BDC2190095E648 /* ea_block.c in Sources */,
@ -1768,11 +1805,14 @@
836F6F2118BDC2190095E648 /* aica_decoder.c in Sources */,
836F700318BDC2190095E648 /* ps2_vag.c in Sources */,
836F6FAA18BDC2190095E648 /* ngc_bh2pcm.c in Sources */,
831BA6211EAC61A500CF89B0 /* x360_pasx.c in Sources */,
836F6F4318BDC2190095E648 /* de2_blocked.c in Sources */,
836F6F3018BDC2190095E648 /* nds_procyon_decoder.c in Sources */,
831BA6181EAC61A500CF89B0 /* adx.c in Sources */,
836F6F5A18BDC2190095E648 /* vs_blocked.c in Sources */,
836F6FB118BDC2190095E648 /* ngc_ffcc_str.c in Sources */,
836F6FC218BDC2190095E648 /* pc_mxst.c in Sources */,
831BA62B1EAC61CB00CF89B0 /* wwise_vorbis_decoder.c in Sources */,
836F6FC918BDC2190095E648 /* ps2_2pfs.c in Sources */,
836F704818BDC2190095E648 /* xbox_ims.c in Sources */,
836F6F4918BDC2190095E648 /* ims_block.c in Sources */,
@ -1792,7 +1832,6 @@
836F703E18BDC2190095E648 /* wii_ras.c in Sources */,
836F6FF518BDC2190095E648 /* ps2_rxw.c in Sources */,
836F6FEA18BDC2190095E648 /* ps2_msa.c in Sources */,
836F701618BDC2190095E648 /* ps3_sgh_sgb.c in Sources */,
836F6F3618BDC2190095E648 /* ogg_vorbis_decoder.c in Sources */,
836F704718BDC2190095E648 /* xbox_hlwav.c in Sources */,
836F701C18BDC2190095E648 /* psx_str_mgav.c in Sources */,
@ -1807,10 +1846,12 @@
836F6F3818BDC2190095E648 /* psx_decoder.c in Sources */,
836F6F2D18BDC2190095E648 /* mpeg_decoder.c in Sources */,
836F6F2618BDC2190095E648 /* g7221_decoder.c in Sources */,
831BA6291EAC61CB00CF89B0 /* ogl_vorbis_decoder.c in Sources */,
836F6FA218BDC2190095E648 /* naomi_adpcm.c in Sources */,
836F6FBF18BDC2190095E648 /* otm.c in Sources */,
836F6FDD18BDC2190095E648 /* ps2_ikm.c in Sources */,
836F6FBD18BDC2190095E648 /* nwa.c in Sources */,
831BA62C1EAC61CB00CF89B0 /* wwise_vorbis_utils.c in Sources */,
836F6FC418BDC2190095E648 /* pc_snds.c in Sources */,
836F704E18BDC2190095E648 /* xss.c in Sources */,
836F6FD118BDC2190095E648 /* ps2_bg00.c in Sources */,
@ -1820,7 +1861,6 @@
838BDB6E1D3B043C0022CA6F /* ffmpeg.c in Sources */,
836F6F5D18BDC2190095E648 /* xa_blocked.c in Sources */,
836F6F3418BDC2190095E648 /* nwa_decoder.c in Sources */,
836F6F6918BDC2190095E648 /* adx_header.c in Sources */,
836F6F2E18BDC2190095E648 /* msadpcm_decoder.c in Sources */,
836F6F9218BDC2190095E648 /* ish_isd.c in Sources */,
836F6F2A18BDC2190095E648 /* lsf_decoder.c in Sources */,

View File

@ -32,5 +32,8 @@ libcoding_la_SOURCES += mtaf_decoder.c
libcoding_la_SOURCES += g719_decoder.c
libcoding_la_SOURCES += hca_decoder.c
libcoding_la_SOURCES += fsb_vorbis_decoder.c
libcoding_la_SOURCES += wwise_vorbis_decoder.c
libcoding_la_SOURCES += wwise_vorbis_utils.c
libcoding_la_SOURCES += ogl_vorbis_decoder.c
EXTRA_DIST = coding.h g72x_state.h clHCA.h

View File

@ -27,11 +27,13 @@ void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelsp
void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels);
/* ngc_dsp_decoder */
void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ngc_dsp_mem(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, uint8_t * mem);
size_t dsp_bytes_to_samples(size_t bytes, int channels);
int32_t dsp_nibbles_to_samples(int32_t nibbles);
void dsp_read_coefs_be(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t offset, off_t spacing);
void dsp_read_coefs_le(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t offset, off_t spacing);
@ -53,6 +55,7 @@ void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
/* psx_decoder */
void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
@ -60,6 +63,7 @@ void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
void decode_psx_bmdx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size);
void decode_hevag(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
size_t ps_bytes_to_samples(size_t bytes, int channels);
/* xa_decoder */
void decode_xa(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
@ -87,9 +91,9 @@ void decode_acm(ACMStream * acm, sample * outbuf, int32_t samples_to_do, int cha
void decode_nwa(NWAData *nwa, sample *outbuf, int32_t samples_to_do);
/* msadpcm_decoder */
long msadpcm_bytes_to_samples(long bytes, int block_size, int channels);
void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do);
void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do);
long msadpcm_bytes_to_samples(long bytes, int block_size, int channels);
/* aica_decoder */
void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
@ -124,6 +128,23 @@ void decode_fsb_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_t
void free_fsb_vorbis(vorbis_codec_data *data);
void reset_fsb_vorbis(VGMSTREAM *vgmstream);
void seek_fsb_vorbis(VGMSTREAM *vgmstream, int32_t num_sample);
/* wwise_vorbis_decoder */
vorbis_codec_data * init_wwise_vorbis_codec_data(STREAMFILE *streamfile, off_t start_offset, int channels, int sample_rate, int blocksize_0_exp, int blocksize_1_exp,
wwise_setup_type setup_type, wwise_header_type header_type, wwise_packet_type packet_type, int big_endian);
void decode_wwise_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels);
void free_wwise_vorbis(vorbis_codec_data *data);
void reset_wwise_vorbis(VGMSTREAM *vgmstream);
void seek_wwise_vorbis(VGMSTREAM *vgmstream, int32_t num_sample);
/* ogl_vorbis_decoder */
vorbis_codec_data * init_ogl_vorbis_codec_data(STREAMFILE *streamFile, off_t start_offset, off_t * data_start_offset);
void decode_ogl_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels);
void free_ogl_vorbis(vorbis_codec_data *data);
void reset_ogl_vorbis(VGMSTREAM *vgmstream);
void seek_ogl_vorbis(VGMSTREAM *vgmstream, int32_t num_sample);
#endif
/* mpeg_decoder */
@ -163,33 +184,35 @@ void decode_mp4_aac(mp4_aac_codec_data * data, sample * outbuf, int32_t samples_
void decode_at3plus(VGMSTREAM *vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
#endif
#ifdef VGM_USE_FFMPEG
/* ffmpeg_decoder */
#ifdef VGM_USE_FFMPEG
void decode_ffmpeg(VGMSTREAM *stream, sample * outbuf, int32_t samples_to_do, int channels);
void reset_ffmpeg(VGMSTREAM *vgmstream);
void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample);
void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples);
#endif
/* ffmpeg_decoder_utils */
/* coding_utils */
int ffmpeg_fmt_chunk_swap_endian(uint8_t * chunk, size_t chunk_size, uint16_t codec);
int ffmpeg_make_riff_atrac3(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int joint_stereo, int encoder_delay);
int ffmpeg_make_riff_atrac3plus(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int encoder_delay);
int ffmpeg_make_riff_xma1(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int stream_mode);
int ffmpeg_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_count, int block_size);
int ffmpeg_make_riff_xma_from_fmt(uint8_t * buf, size_t buf_size, off_t fmt_offset, size_t fmt_size, size_t data_size, STREAMFILE *streamFile, int big_endian);
int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t sample_count, size_t data_size, int channels, int sample_rate, int avg_bps, int block_align);
int ffmpeg_make_riff_xma_from_fmt_chunk(uint8_t * buf, size_t buf_size, off_t fmt_offset, size_t fmt_size, size_t data_size, STREAMFILE *streamFile, int big_endian);
int ffmpeg_make_riff_xma2_from_xma2_chunk(uint8_t * buf, size_t buf_size, off_t xma2_offset, size_t xma2_size, size_t data_size, STREAMFILE *streamFile);
int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t data_size, int channels, int sample_rate, int avg_bps, int block_align);
/* XMA sample parser info (struct to avoid passing so much stuff, separate for reusing) */
/* MS audio format's sample info (struct to avoid passing so much stuff, separate for reusing) */
typedef struct {
int xma_version;
int channels;
int stream_mode;
off_t data_offset;
size_t data_size;
int loop_flag;
/* frame offsets */
int loop_flag;
uint32_t loop_start_b;
uint32_t loop_end_b;
uint32_t loop_start_subframe;
@ -200,9 +223,17 @@ typedef struct {
int32_t skip_samples;
int32_t loop_start_sample;
int32_t loop_end_sample;
} xma_sample_data;
void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile);
} ms_sample_data;
void xma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile);
void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags);
void wma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags);
void xma1_parse_fmt_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * channels, int * sample_rate, int * loop_flag, int32_t * loop_start_b, int32_t * loop_end_b, int32_t * loop_subframe, int be);
void xma2_parse_fmt_chunk_extra(STREAMFILE *streamFile, off_t chunk_offset, int * loop_flag, int32_t * num_samples, int32_t * loop_start_sample, int32_t * loop_end_sample, int be);
void xma2_parse_xma2_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * channels, int * sample_rate, int * loop_flag, int32_t * num_samples, int32_t * loop_start_sample, int32_t * loop_end_sample);
size_t atrac3_bytes_to_samples(size_t bytes, int full_block_align);
size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align);
#endif
#endif /*_CODING_H*/

View File

@ -1,12 +1,15 @@
#include "coding.h"
#include "math.h"
#include "../vgmstream.h"
#ifdef VGM_USE_FFMPEG
#define XMA_CHECK_SKIPS 0
#define XMA_BYTES_PER_PACKET 2048
#define XMA_SAMPLES_PER_FRAME 512
#define XMA_SAMPLES_PER_SUBFRAME 128
/**
* Various utils for formats that aren't handled their own decoder or meta
*
* ffmpeg_make_riff_* utils don't depend on FFmpeg, but rather, they make headers that FFmpeg
* can use (it doesn't understand all valid RIFF headers, nor the utils make 100% correct headers).
*/
/* ******************************************** */
/* INTERNAL UTILS */
@ -256,11 +259,13 @@ int ffmpeg_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, s
return riff_size;
}
int ffmpeg_make_riff_xma_from_fmt(uint8_t * buf, size_t buf_size, off_t fmt_offset, size_t fmt_size, size_t data_size, STREAMFILE *streamFile, int big_endian) {
/* Makes a XMA1/2 RIFF header for FFmpeg using a "fmt " chunk (XMAWAVEFORMAT or XMA2WAVEFORMATEX) as a base:
* Useful to preserve the stream layout */
int ffmpeg_make_riff_xma_from_fmt_chunk(uint8_t * buf, size_t buf_size, off_t fmt_offset, size_t fmt_size, size_t data_size, STREAMFILE *streamFile, int big_endian) {
size_t riff_size = 4+4+ 4 + 4+4+fmt_size + 4+4;
uint8_t chunk[100];
uint8_t chunk[0x100];
if (buf_size < riff_size || fmt_size > 100)
if (buf_size < riff_size || fmt_size > 0x100)
goto fail;
if (read_streamfile(chunk,fmt_offset,fmt_size, streamFile) != fmt_size)
goto fail;
@ -287,7 +292,52 @@ fail:
return -1;
}
int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t sample_count, size_t data_size, int channels, int sample_rate, int avg_bps, int block_align) {
/* Makes a XMA2 RIFF header for FFmpeg using a "XMA2" chunk (XMA2WAVEFORMAT) as a base.
* Useful to preserve the stream layout */
int ffmpeg_make_riff_xma2_from_xma2_chunk(uint8_t * buf, size_t buf_size, off_t xma2_offset, size_t xma2_size, size_t data_size, STREAMFILE *streamFile) {
uint8_t chunk[0x100];
size_t riff_size;
size_t xma2_final_size = xma2_size;
int xma2_chunk_version = read_8bit(xma2_offset,streamFile);
/* FFmpeg can't parse v3 "XMA2" chunks so we'll have to extend (8 bytes in the middle) */
if (xma2_chunk_version == 3)
xma2_final_size += 0x8;
riff_size = 4+4+ 4 + 4+4+xma2_final_size + 4+4;
if (buf_size < riff_size || xma2_final_size > 0x100)
goto fail;
if (read_streamfile(chunk,xma2_offset,xma2_size, streamFile) != xma2_size)
goto fail;
memcpy(buf+0x00, "RIFF", 4);
put_32bitLE(buf+0x04, (int32_t)(riff_size-4-4 + data_size)); /* riff size */
memcpy(buf+0x08, "WAVE", 4);
memcpy(buf+0x0c, "XMA2", 4);
put_32bitLE(buf+0x10, xma2_final_size);
if (xma2_chunk_version == 3) {
/* old XMA2 v3: change to v4 (extra 8 bytes in the middle); always BE */
put_8bit (buf+0x14 + 0x00, 4); /* v4 */
memcpy (buf+0x14 + 0x01, chunk+1, 0xF); /* first v3 part (fixed) */
put_32bitBE(buf+0x14 + 0x10, 0x000010D6); /* extra v4 BE: "EncodeOptions" (not used by FFmpeg) */
put_32bitBE(buf+0x14 + 0x14, 0); /* extra v4 BE: "PsuedoBytesPerSec" (not used by FFmpeg) */
memcpy (buf+0x14 + 0x18, chunk+0x10, xma2_size - 0x10); /* second v3 part (variable size) */
} else {
memcpy(buf+0x14, chunk, xma2_size);
}
memcpy(buf+0x14+xma2_final_size, "data", 4);
put_32bitLE(buf+0x14+xma2_final_size+4, data_size); /* data size */
return riff_size;
fail:
return -1;
}
int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t data_size, int channels, int sample_rate, int avg_bps, int block_align) {
size_t riff_size = 4+4+ 4 + 0x1a + 4+4;
if (buf_size < riff_size)
@ -302,11 +352,11 @@ int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t samp
put_16bitLE(buf+0x14, codec);
put_16bitLE(buf+0x16, channels);
put_32bitLE(buf+0x18, sample_rate);
put_32bitLE(buf+0x1c, avg_bps); /* average bits per second, somehow vital for XWMA */
put_32bitLE(buf+0x1c, avg_bps); /* average bytes per second, somehow vital for XWMA */
put_16bitLE(buf+0x20, block_align); /* block align */
put_16bitLE(buf+0x22, 16); /* bits per sample */
put_16bitLE(buf+0x24, 0); /* unk */
/* here goes the "dpds" table, but it's not needed by FFmpeg */
put_16bitLE(buf+0x24, 0); /* extra size */
/* here goes the "dpds" table, but it's optional and not needed by FFmpeg */
memcpy(buf+0x26, "data", 4);
put_32bitLE(buf+0x2a, data_size); /* data size */
@ -374,33 +424,33 @@ fail:
/* ******************************************** */
/* XMA PARSING */
/* ******************************************** */
#define XMA_CHECK_SKIPS 0
/**
* Find total and loop samples by reading XMA frame headers.
* Find total and loop samples of Microsoft audio formats (WMAPRO/XMA1/XMA2) by reading frame headers.
*
* A XMA stream is made of packets, each containing N small frames of X samples.
* Frames are further divided into subframes for looping purposes.
* XMA1 and XMA2 only differ in the packet headers.
* The stream is made of packets, each containing N small frames of X samples. Frames are further divided into subframes.
* XMA1/XMA2/WMAPRO only differ in the packet headers.
*/
void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int bytes_per_packet, int samples_per_frame, int samples_per_subframe, int bits_frame_size) {
int frames = 0, samples = 0, loop_start_frame = 0, loop_end_frame = 0, skip_packets;
#if XMA_CHECK_SKIPS
int start_skip = 0, end_skip = 0, first_start_skip = 0, last_end_skip = 0;
#endif
uint32_t first_frame_b, packet_skip_count = 0, frame_size_b, packet_size_b;
uint32_t first_frame_b, packet_skip_count = 0, frame_size_b, packet_size_b, header_size_b;
uint64_t offset_b, packet_offset_b, frame_offset_b;
size_t size;
uint32_t packet_size = XMA_BYTES_PER_PACKET;
off_t offset = xma->data_offset;
uint32_t stream_offset_b = xma->data_offset * 8;
uint32_t packet_size = bytes_per_packet;
off_t offset = msd->data_offset;
uint32_t stream_offset_b = msd->data_offset * 8;
size = offset + xma->data_size;
size = offset + msd->data_size;
packet_size_b = packet_size * 8;
/* if we knew the streams mode then we could read just the first one and adjust samples later
* not a big deal but maybe important for skip stuff */
//streams = (xma->stream_mode==0 ? (xma->channels + 1) / 2 : xma->channels)
//streams = (msd->stream_mode==0 ? (msd->channels + 1) / 2 : msd->channels)
skip_packets = 0;
/* read packets */
@ -414,19 +464,28 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
continue;
}
/* XMA1 or XMA2 packet header */
if (xma->xma_version == 1) {
/* packet header */
if (msd->xma_version == 1) { /* XMA1 */
//packet_sequence = read_bitsBE_b(offset_b+0, 4, streamFile); /* numbered from 0 to N */
//unknown = read_bitsBE_b(offset_b+4, 2, streamFile); /* packet_metadata? (always 2) */
first_frame_b = read_bitsBE_b(offset_b+6, 15, streamFile); /* offset in bits inside the packet */
first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, streamFile); /* offset in bits inside the packet */
packet_skip_count = read_bitsBE_b(offset_b+21, 11, streamFile); /* packets to skip for next packet of this stream */
} else {
header_size_b = 32;
} else if (msd->xma_version == 2) { /* XMA2 */
//frame_count = read_bitsBE_b(offset_b+0, 6, streamFile); /* frames that begin in this packet */
first_frame_b = read_bitsBE_b(offset_b+6, 15, streamFile); /* offset in bits inside this packet */
first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, streamFile); /* offset in bits inside this packet */
//packet_metadata = read_bitsBE_b(offset_b+21, 3, streamFile); /* packet_metadata (always 1) */
packet_skip_count = read_bitsBE_b(offset_b+24, 8, streamFile); /* packets to skip for next packet of this stream */
header_size_b = 32;
} else { /* WMAPRO(v3) */
//packet_sequence = read_bitsBE_b(offset_b+0, 4, streamFile); /* numbered from 0 to N */
//unknown = read_bitsBE_b(offset_b+4, 2, streamFile); /* packet_metadata? (always 2) */
first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, streamFile); /* offset in bits inside the packet */
packet_skip_count = 0; /* xwma probably has no need to skip packets since it uses real multichannel ch audio */
header_size_b = 4+2+bits_frame_size; /* variable-size header */
}
/* full packet skip */
if (packet_skip_count == 0x7FF) {
packet_skip_count = 0;
@ -438,22 +497,22 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
VGM_ASSERT(packet_skip_count > 10, "XMA: found big packet skip %i\n", packet_skip_count);//a bit unusual...
//VGM_LOG("packet: off=%x, ff=%i, ps=%i\n", offset, first_frame_b, packet_skip_b);
packet_offset_b = 4*8 + first_frame_b; /* packet offset in bits */
packet_offset_b = header_size_b + first_frame_b; /* packet offset in bits */
/* read packet frames */
while (packet_offset_b < packet_size_b) {
frame_offset_b = offset_b + packet_offset_b; /* in bits for aligment stuff */
//todo not sure if frames or frames+1 (considering skip_samples)
if (xma->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == xma->loop_start_b)
if (msd->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == msd->loop_start_b)
loop_start_frame = frames;
if (xma->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == xma->loop_end_b)
if (msd->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == msd->loop_end_b)
loop_end_frame = frames;
/* XMA1/2 frame header */
frame_size_b = read_bitsBE_b(frame_offset_b, 15, streamFile);
frame_offset_b += 15;
/* frame header */
frame_size_b = read_bitsBE_b(frame_offset_b, bits_frame_size, streamFile);
frame_offset_b += bits_frame_size;
if (frame_size_b == 0) /* observed in some files with empty frames/packets */
break;
packet_offset_b += frame_size_b; /* including header */
@ -469,7 +528,7 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
// continue; // todo read packet end bit instead
}
#endif
frame_offset_b += 15;
frame_offset_b += 15; //todo bits_frame_size?
if (frame_size_b == 0x7FFF) { /* end packet frame marker */
break;
@ -481,14 +540,14 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
int flag;
/* ignore "postproc transform" */
if (xma->channels > 1) {
if (msd->channels > 1) {
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
frame_offset_b += 1;
if (flag) {
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
frame_offset_b += 1;
if (flag) {
frame_offset_b += 1 + 4 * xma->channels*xma->channels; /* 4-something per double channel? */
frame_offset_b += 1 + 4 * msd->channels*msd->channels; /* 4-something per double channel? */
}
}
}
@ -508,9 +567,9 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
frame_offset_b += 10;
VGM_ASSERT(start_skip, "XMA: more than one start_skip (%i)\n", new_skip);
if (new_skip > XMA_SAMPLES_PER_FRAME) { /* from xmaencode */
if (new_skip > samples_per_frame) { /* from xmaencode */
VGM_LOG("XMA: bad start_skip (%i)\n", new_skip);
new_skip = XMA_SAMPLES_PER_FRAME;
new_skip = samples_per_frame;
}
if (frames==0) first_start_skip = new_skip; /* sometimes in the middle */
@ -526,9 +585,9 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
frame_offset_b += 10;
VGM_ASSERT(end_skip, "XMA: more than one end_skip (%i)\n", new_skip);
if (new_skip > XMA_SAMPLES_PER_FRAME) { /* from xmaencode */
if (new_skip > samples_per_frame) { /* from xmaencode */
VGM_LOG("XMA: bad end_skip (%i)\n", new_skip);
new_skip = XMA_SAMPLES_PER_FRAME;
new_skip = samples_per_frame;
}
last_end_skip = new_skip; /* not seen */
@ -540,7 +599,7 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
}
#endif
samples += XMA_SAMPLES_PER_FRAME;
samples += samples_per_frame;
frames++;
}
}
@ -551,20 +610,208 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
samples = samples + 64 - start_skip;
samples = samples + 64 - end_skip;
xma->skip_samples = 64 + 512; //todo not always correct
msd->skip_samples = 64 + samples_per_frame; //todo not always correct
#endif
xma->num_samples = samples;
msd->num_samples = samples;
if (xma->loop_flag && loop_end_frame > loop_start_frame) {
xma->loop_start_sample = loop_start_frame * XMA_SAMPLES_PER_FRAME + xma->loop_start_subframe * XMA_SAMPLES_PER_SUBFRAME;
xma->loop_end_sample = loop_end_frame * XMA_SAMPLES_PER_FRAME + xma->loop_end_subframe * XMA_SAMPLES_PER_SUBFRAME;
if (msd->loop_flag && loop_end_frame > loop_start_frame) {
msd->loop_start_sample = loop_start_frame * samples_per_frame + msd->loop_start_subframe * samples_per_subframe;
msd->loop_end_sample = loop_end_frame * samples_per_frame + msd->loop_end_subframe * samples_per_subframe;
#if XMA_CHECK_SKIPS
/* maybe this is needed */
//xma->loop_start_sample -= xma->skip_samples;
//xma->loop_end_sample -= xma->skip_samples;
//msd->loop_start_sample -= msd->skip_samples;
//msd->loop_end_sample -= msd->skip_samples;
#endif
}
}
#endif
static int wma_get_samples_per_frame(int version, int sample_rate, uint32_t decode_flags) {
int frame_len_bits;
if (sample_rate <= 16000)
frame_len_bits = 9;
else if (sample_rate <= 22050 || (sample_rate <= 32000 && version == 1))
frame_len_bits = 10;
else if (sample_rate <= 48000 || version < 3)
frame_len_bits = 11;
else if (sample_rate <= 96000)
frame_len_bits = 12;
else
frame_len_bits = 13;
if (version == 3) {
int tmp = decode_flags & 0x6;
if (tmp == 0x2)
++frame_len_bits;
else if (tmp == 0x4)
--frame_len_bits;
else if (tmp == 0x6)
frame_len_bits -= 2;
}
return 1 << frame_len_bits;
}
void xma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile) {
const int bytes_per_packet = 2048;
const int samples_per_frame = 512;
const int samples_per_subframe = 128;
ms_audio_get_samples(msd, streamFile, bytes_per_packet, samples_per_frame, samples_per_subframe, 15);
}
void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags) {
const int version = 3; /* WMAPRO = WMAv3 */
int bytes_per_packet = block_align;
int samples_per_frame = 0;
int samples_per_subframe = 0;
int bits_frame_size = 0;
/* do some WMAPRO setup (code from ffmpeg) */
samples_per_frame = wma_get_samples_per_frame(version, sample_rate, decode_flags);
/* max bits needed to represent this block_align */
bits_frame_size = floor(log(block_align) / log(2)) + 4;
/* not really needed as I've never seen loop subframe data for WMA (probably possible though)
* (FFmpeg has code to get min_samples_per subframe) */
samples_per_subframe = 0;
/* signal it's not XMA */
msd->xma_version = 0;
ms_audio_get_samples(msd, streamFile, bytes_per_packet, samples_per_frame, samples_per_subframe, bits_frame_size);
}
void wma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags) {
const int version = 2; /* WMAv1 rarely used */
int use_bit_reservoir = 0; /* last packet frame can spill into the next packet */
int samples_per_frame = 0;
int num_frames = 0;
samples_per_frame = wma_get_samples_per_frame(version, sample_rate, decode_flags);
/* assumed (ASF has a flag for this but XWMA doesn't) */
if (version == 2)
use_bit_reservoir = 1;
if (!use_bit_reservoir) {
/* 1 frame per packet */
num_frames = msd->data_size / block_align + (msd->data_size % block_align ? 1 : 0);
}
else {
/* variable frames per packet (mini-header values) */
off_t offset = msd->data_offset;
while (offset < msd->data_size) { /* read packets (superframes) */
int packet_frames;
uint8_t header = read_8bit(offset, streamFile); /* upper nibble: index; lower nibble: frames */
/* frames starting in this packet (ie. counts frames that spill due to bit_reservoir) */
packet_frames = (header & 0xf);
num_frames += packet_frames;
offset += block_align;
}
}
msd->num_samples = num_frames * samples_per_frame;
}
/* ******************************************** */
/* HEADER PARSING */
/* ******************************************** */
/* Read values from a XMA1 RIFF "fmt" chunk (XMAWAVEFORMAT), starting from an offset *after* chunk type+size.
* Useful as custom X360 headers commonly have it lurking inside. */
void xma1_parse_fmt_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * channels, int * sample_rate, int * loop_flag, int32_t * loop_start_b, int32_t * loop_end_b, int32_t * loop_subframe, int be) {
int16_t (*read_16bit)(off_t,STREAMFILE*) = be ? read_16bitBE : read_16bitLE;
int32_t (*read_32bit)(off_t,STREAMFILE*) = be ? read_32bitBE : read_32bitLE;
int i, num_streams, total_channels = 0;
if (read_16bit(chunk_offset+0x00,streamFile) != 0x165) return;
num_streams = read_16bit(chunk_offset+0x08,streamFile);
if(loop_flag) *loop_flag = (uint8_t)read_8bit(chunk_offset+0xA,streamFile) > 0;
/* sample rate and loop bit offsets are defined per stream, but the first is enough */
if(sample_rate) *sample_rate = read_32bit(chunk_offset+0x10,streamFile);
if(loop_start_b) *loop_start_b = read_32bit(chunk_offset+0x14,streamFile);
if(loop_end_b) *loop_end_b = read_32bit(chunk_offset+0x18,streamFile);
if(loop_subframe) *loop_subframe = (uint8_t)read_8bit(chunk_offset+0x1C,streamFile);
/* channels is the sum of all streams */
for (i = 0; i < num_streams; i++) {
total_channels += read_8bit(chunk_offset+0x0C+0x11+i*0x10,streamFile);
}
if(channels) *channels = total_channels;
}
/* Read values from a 'new' XMA2 RIFF "fmt" chunk (XMA2WAVEFORMATEX), starting from an offset *after* chunk type+size.
* Useful as custom X360 headers commonly have it lurking inside. Only the extra data, the first part is a normal WAVEFORMATEX. */
void xma2_parse_fmt_chunk_extra(STREAMFILE *streamFile, off_t chunk_offset, int * loop_flag, int32_t * num_samples, int32_t * loop_start_sample, int32_t * loop_end_sample, int be) {
int16_t (*read_16bit)(off_t,STREAMFILE*) = be ? read_16bitBE : read_16bitLE;
int32_t (*read_32bit)(off_t,STREAMFILE*) = be ? read_32bitBE : read_32bitLE;
if (read_16bit(chunk_offset+0x00,streamFile) != 0x166) return;
/* up to extra data is a WAVEFORMATEX */
if (read_16bit(chunk_offset+0x10,streamFile) < 0x22) return; /* expected extra data size */
if(num_samples) *num_samples = read_32bit(chunk_offset+0x18,streamFile);
if(loop_start_sample) *loop_start_sample = read_32bit(chunk_offset+0x28,streamFile);
if(loop_end_sample) *loop_end_sample = read_32bit(chunk_offset+0x28,streamFile) + read_32bit(chunk_offset+0x2C,streamFile);
if(loop_flag) *loop_flag = (uint8_t)read_8bit(chunk_offset+0x30,streamFile) > 0 /* never set in practice */
|| read_32bit(chunk_offset+0x2C,streamFile); /*loop_end_sample*/
/* play_begin+end = probably pcm_samples (for original sample rate), don't seem to affect anything */
/* int32_t play_begin_sample = read_32bit(xma->chunk_offset+0x20,streamFile); */
/* int32_t play_end_sample = play_begin_sample + read_32bit(xma->chunk_offset+0x24,streamFile); */
}
/* Read values from an 'old' XMA2 RIFF "XMA2" chunk (XMA2WAVEFORMAT), starting from an offset *after* chunk type+size.
* Useful as custom X360 headers commonly have it lurking inside. */
void xma2_parse_xma2_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * channels, int * sample_rate, int * loop_flag, int32_t * num_samples, int32_t * loop_start_sample, int32_t * loop_end_sample) {
int32_t (*read_32bit)(off_t,STREAMFILE*) = read_32bitBE; /* XMA2WAVEFORMAT is always big endian */
int i, xma2_chunk_version, num_streams, total_channels = 0;
off_t off;
xma2_chunk_version = read_8bit(chunk_offset+0x00,streamFile);
num_streams = read_8bit(chunk_offset+0x01,streamFile);
if(loop_start_sample) *loop_start_sample = read_32bit(chunk_offset+0x04,streamFile);
if(loop_end_sample) *loop_end_sample = read_32bit(chunk_offset+0x08,streamFile);
if(loop_flag) *loop_flag = (uint8_t)read_8bit(chunk_offset+0x03,streamFile) > 0 /* rarely not set, encoder default */
|| read_32bit(chunk_offset+0x08,streamFile); /* loop_end_sample */
if(sample_rate) *sample_rate = read_32bit(chunk_offset+0x0c,streamFile);;
off = xma2_chunk_version == 3 ? 0x14 : 0x1C;
if(num_samples) *num_samples = read_32bit(chunk_offset+off,streamFile);
/*xma->pcm_samples = read_32bitBE(xma->chunk_offset+off+0x04,streamFile)*/
/* num_samples is the max samples in the file (apparently not including encoder delay) */
/* pcm_samples are original WAV's; not current since samples and sample rate may be adjusted for looping purposes */
off = xma2_chunk_version == 3 ? 0x20 : 0x28;
/* channels is the sum of all streams */
for (i = 0; i < num_streams; i++) {
total_channels += read_8bit(chunk_offset+off+i*0x04,streamFile);
}
if (channels) *channels = total_channels;
}
/* ******************************************** */
/* OTHER STUFF */
/* ******************************************** */
size_t atrac3_bytes_to_samples(size_t bytes, int full_block_align) {
/* ATRAC3 expects full block align since as is can mix joint stereo with mono blocks;
* so (full_block_align / channels) DOESN'T give the size of a single channel (uncommon in ATRAC3 though) */
return (bytes / full_block_align) * 1024;
}
size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align) {
/* ATRAC3plus expects full block align since as is can mix joint stereo with mono blocks;
* so (full_block_align / channels) DOESN'T give the size of a single channel (common in ATRAC3plus) */
return (bytes / full_block_align) * 2048;
}

View File

@ -1,12 +1,11 @@
#include "coding.h"
#include <math.h>
#ifdef VGM_USE_VORBIS
#include <vorbis/codec.h>
#define FSB_VORBIS_ON 1 //todo remove once battle-tested
#define FSB_VORBIS_USE_PRECOMPILED_FVS 1 /* if enabled vgmstream weights ~600kb more but doesn't need external .fvs packets */
#if FSB_VORBIS_ON
#if FSB_VORBIS_USE_PRECOMPILED_FVS
#include "fsb_vorbis_data.h"
#endif
@ -21,7 +20,6 @@ static int vorbis_make_header_setup(uint8_t * buf, size_t bufsize, uint32_t setu
static int load_fvs_file_single(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile);
static int load_fvs_file_multi(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile);
static int load_fvs_array(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile);
#endif
/**
* Inits a raw FSB vorbis stream.
@ -37,7 +35,6 @@ static int load_fvs_array(uint8_t * buf, size_t bufsize, uint32_t setup_id, STRE
* Also from the official docs (https://www.xiph.org/vorbis/doc/libvorbis/overview.html).
*/
vorbis_codec_data * init_fsb_vorbis_codec_data(STREAMFILE *streamfile, off_t start_offset, int channels, int sample_rate, uint32_t setup_id) {
#if FSB_VORBIS_ON
vorbis_codec_data * data = NULL;
/* init stuff */
@ -80,7 +77,6 @@ vorbis_codec_data * init_fsb_vorbis_codec_data(STREAMFILE *streamfile, off_t sta
fail:
free_fsb_vorbis(data);
#endif
return NULL;
}
@ -88,7 +84,6 @@ fail:
* Decodes raw FSB vorbis
*/
void decode_fsb_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels) {
#if FSB_VORBIS_ON
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
vorbis_codec_data * data = vgmstream->codec_data;
size_t stream_size = get_streamfile_size(stream->streamfile);
@ -177,10 +172,8 @@ void decode_fsb_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_t
decode_fail:
/* on error just put some 0 samples */
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample));
#endif
}
#if FSB_VORBIS_ON
static void pcm_convert_float_to_16(vorbis_codec_data * data, sample * outbuf, int samples_to_do, float ** pcm) {
/* mostly from Xiph's decoder_example.c */
@ -391,12 +384,9 @@ fail:
return 0;
}
#endif
/* ********************************************** */
void free_fsb_vorbis(vorbis_codec_data * data) {
#if FSB_VORBIS_ON
if (!data)
return;
@ -407,23 +397,26 @@ void free_fsb_vorbis(vorbis_codec_data * data) {
free(data->buffer);
free(data);
#endif
}
void reset_fsb_vorbis(VGMSTREAM *vgmstream) {
seek_fsb_vorbis(vgmstream, 0);
vorbis_codec_data *data = vgmstream->codec_data;
/* Seeking is provided by the Ogg layer, so with raw vorbis we need seek tables instead.
* To avoid having to parse different formats we'll just discard until the expected sample */
vorbis_synthesis_restart(&data->vd);
data->samples_to_discard = 0;
}
void seek_fsb_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) {
#if FSB_VORBIS_ON
vorbis_codec_data *data = vgmstream->codec_data;
/* Seeking is provided by the Ogg layer, so with raw vorbis we need seek tables instead.
* To avoid having to parse different formats we'll just discard until the expected sample */
vorbis_synthesis_restart(&data->vd);
data->samples_to_discard = num_sample;
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset;
#endif
if (vgmstream->loop_ch)
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset;
}
#endif

View File

@ -604,3 +604,57 @@ void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * o
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
}
void decode_wwise_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count = 0;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
//internal interleave (configurable size), block-interleave multichannel (ex. if block is 0xD8 in 6ch: 6 blocks of 4+0x20)
int block_samples = (vgmstream->interleave_block_size - 4*vgmstream->channels) * 2 / vgmstream->channels;
first_sample = first_sample % block_samples;
//block-interleaved header (1 header per channel block); can be LE or BE
if (first_sample == 0) {
int16_t (*read_16bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_16bitBE : read_16bitLE;
off_t header_offset = stream->offset + (vgmstream->interleave_block_size / vgmstream->channels)*channel;
hist1 = read_16bit(header_offset,stream->streamfile);
step_index = read_8bit(header_offset+2,stream->streamfile);
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
//must write history from header as last nibble/sample in block is almost always 0 / not encoded
outbuf[sample_count] = (short)(hist1);
sample_count += channelspacing;
first_sample += 1;
samples_to_do -= 1;
}
for (i=first_sample; i < first_sample + samples_to_do; i++) { /* first_sample + samples_to_do should be block_samples at most */
off_t byte_offset = stream->offset + (vgmstream->interleave_block_size / vgmstream->channels)*channel + 4 + (i-1)/2;
int nibble_shift = ((i-1)&1?4:0); //low nibble first
//last nibble/sample in block is ignored (next header sample contains it)
if (i < block_samples) {
ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
outbuf[sample_count] = (short)(hist1);
sample_count+=channelspacing;
//todo atenuation: apparently from hcs's analysis Wwise IMA decodes nibbles slightly different, reducing dbs
}
}
//internal interleave: increment offset on complete frame
if (i == block_samples) stream->offset += vgmstream->interleave_block_size;
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
}
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels) {
/* MS IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */
return (bytes / block_align) * (block_align - 4 * channels) * 2 / channels;
}

View File

@ -61,7 +61,7 @@ mpeg_codec_data *init_mpeg_codec_data(STREAMFILE *streamfile, off_t start_offset
rc = mpg123_decode(main_m, data->buffer,data->buffer_size, NULL,0, &bytes_done);
if (rc != MPG123_OK && rc != MPG123_NEW_FORMAT && rc != MPG123_NEED_MORE) {
VGM_LOG("MPEG: unable to set up mpp123 @ 0x%08lx to 0x%08lx\n", start_offset, read_offset);
VGM_LOG("MPEG: unable to set up mpg123 @ 0x%08lx to 0x%08lx\n", start_offset, read_offset);
goto fail; //todo handle MPG123_DONE?
}
if (read_offset > 0x5000) { /* don't hang in some incorrectly detected formats */
@ -170,7 +170,12 @@ mpeg_codec_data *init_mpeg_codec_data_interleaved(STREAMFILE *streamfile, off_t
/* get frame size from the first frame as it can be used externally to calc interleave */
if ( !update_frame_sizes(data, streamfile, start_offset) )
goto fail;
//VGM_LOG("ch=%i, sr=%i, spf=%i, v=%i, l=%i\n", data->channels_per_frame, data->sample_rate_per_frame, data->samples_per_frame, info.version, info.layer);
//mpg123_handle *main_m = data->m;
//struct mpg123_frameinfo mi;
//mpg123_info(main_m,&mi);
//VGM_LOG("mi.framesize=%x\n", mi.framesize);
/* unlikely, can fixed with bigger buffer or a feed loop */
if (info.frame_size > data->buffer_size)
goto fail;
@ -404,12 +409,16 @@ static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_
/* decode samples from 1 full frame */
do {
int rc;
//int first_frame = stream->offset == stream->channel_start_offset;
/* padded frame stuff */
rc = update_frame_sizes(data, stream->streamfile, stream->offset);
/* ignore any errors and continue; mpg123 will probably sync */
VGM_ASSERT(rc==0, "MPEG: frame error @ 0x%08lx (prev size=0x%x / padding=0x%x)\n", stream->offset, data->current_frame_size, data->current_padding);
/* extra EOF check for edge cases when the caller tries to read more samples than possible */
if (stream->offset > stream_size) {
memset(data->frame_buffer, 0, data->frame_buffer_size);
@ -421,6 +430,7 @@ static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_
/* read more raw data (only 1 frame, to check interleave block end) */
if (!data->buffer_full) {
data->bytes_in_buffer = read_streamfile(data->buffer,stream->offset,data->current_frame_size,stream->streamfile);
//VGM_LOG("read raw: cfs=%x, cp=%x, tot=%x, off=%x\n", data->current_frame_size, data->current_padding, data->current_frame_size + data->current_padding, stream->offset);
/* end of stream, fill frame buffer with 0s but continue normally with other streams */
if (!data->bytes_in_buffer) {
@ -436,16 +446,37 @@ static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_
if (block_size && ((stream->offset - stream->channel_start_offset) % block_size==0)) {
stream->offset += block_size * (data->ms_size-1); /* skip a block per stream if block done */
}
/*
/// TODO: skip very first frame but add fake silence?
//todo skip only if first frame is fully decodable? (ie.- blank below)
//todo for multich files idem
if (first_frame) {
data->buffer_full = 0;
VGM_LOG("skip first frame @ %x - %x\n", stream->offset, stream->channel_start_offset);
memset(data->frame_buffer, 0, data->frame_buffer_size);
bytes_done = data->frame_buffer_size;
break;
}
*/
}
/* feed new raw data to the decoder if needed, copy decoded results to frame buffer output */
if (!data->buffer_used) {
//VGM_LOG("feed unused: cfs=%x, cp=%x, tot=%x, off=%x\n", data->current_frame_size, data->current_padding, data->current_frame_size + data->current_padding, stream->offset);
//getchar();
rc = mpg123_decode(m,
data->buffer, data->bytes_in_buffer,
(unsigned char *)data->frame_buffer, data->frame_buffer_size,
&bytes_done);
data->buffer_used = 1;
} else {
//VGM_LOG("feed used: cfs=%x, cp=%x, tot=%x, off=%x\n", data->current_frame_size, data->current_padding, data->current_frame_size + data->current_padding, stream->offset);
//getchar();
rc = mpg123_decode(m,
NULL,0,
(unsigned char *)data->frame_buffer, data->frame_buffer_size,
@ -515,6 +546,9 @@ static int update_frame_sizes(mpeg_codec_data * data, STREAMFILE *streamfile, of
data->current_padding = (data->current_frame_size % data->fsb_padding) ?
data->fsb_padding - (data->current_frame_size % data->fsb_padding) : 0;
}
//VGM_LOG("off=%lx, ch=%i, sr=%i, spf=%i, fs=%x, v=%i, l=%i\n", offset, info.channels, info.sample_rate, info.frame_samples, info.frame_size, info.version, info.layer);
//getchar();
}
return 1;
@ -649,7 +683,6 @@ void reset_mpeg(VGMSTREAM *vgmstream) {
int i;
for (i=0; i < data->ms_size; i++) {
mpg123_feedseek(data->ms[i],0,SEEK_SET,&input_offset);
vgmstream->loop_ch[i].offset = vgmstream->loop_ch[i].channel_start_offset + input_offset;
}
data->bytes_in_interleave_buffer = 0;
@ -665,13 +698,15 @@ void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
/* seek multistream */
if (!data->interleaved) {
mpg123_feedseek(data->m, num_sample,SEEK_SET,&input_offset);
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset + input_offset;
if (vgmstream->loop_ch)
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset + input_offset;
} else {
int i;
/* re-start from 0 */
for (i=0; i < data->ms_size; i++) {
mpg123_feedseek(data->ms[i],0,SEEK_SET,&input_offset);
vgmstream->loop_ch[i].offset = vgmstream->loop_ch[i].channel_start_offset;
if (vgmstream->loop_ch)
vgmstream->loop_ch[i].offset = vgmstream->loop_ch[i].channel_start_offset;
}
/* manually add skip samples, since we don't really know the correct offset */
data->samples_to_discard = num_sample;
@ -793,6 +828,9 @@ static int mpeg_get_frame_info(STREAMFILE *streamfile, off_t offset, mpeg_frame_
case 576: info->frame_size = (72l * info->bit_rate * 1000l / info->sample_rate + padding); break;
case 1152: info->frame_size = (144l * info->bit_rate * 1000l / info->sample_rate + padding); break;
}
//int fs2 = (info->frame_samples / 8 * info->bit_rate * 1000l) / info->sample_rate + padding;
//VGM_LOG("fs=%x, fs2=%x, fsp=%i, br=%i\n", info->frame_size, fs2, info->frame_samples, info->bit_rate);
//getchar();
info->coding_type = coding_types[info->version-1][info->layer-1];

View File

@ -95,6 +95,10 @@ int32_t dsp_nibbles_to_samples(int32_t nibbles) {
else return whole_frames*14;
}
size_t dsp_bytes_to_samples(size_t bytes, int channels) {
return bytes / channels / 8 * 14;
}
/**
* reads DSP coefs built in the streamfile

View File

@ -0,0 +1,235 @@
#include "coding.h"
#include <math.h>
#ifdef VGM_USE_VORBIS
#include <vorbis/codec.h>
#define ogl_vorbis_DEFAULT_BUFFER_SIZE 0x8000 /* should be at least the size of the setup header, ~0x2000 */
static void pcm_convert_float_to_16(vorbis_codec_data * data, sample * outbuf, int samples_to_do, float ** pcm);
/**
* Inits a raw OGL vorbis stream.
*
* Vorbis packets are stored in .ogg, which is divided into ogg pages/packets, and the first packets contain necessary
* vorbis setup. For raw vorbis the setup is stored it elsewhere (i.e.- in the .exe), presumably to shave off some kb
* per stream and codec startup time. We'll read the external setup and raw data and decode it with libvorbis.
*
* OGL simply removes the Ogg layer and uses 16b packet headers, that have the size of the next packet, but
* the lower 2b need to be removed (usually 00 but 01 for the id packet, not sure about the meaning).
*/
vorbis_codec_data * init_ogl_vorbis_codec_data(STREAMFILE *streamFile, off_t start_offset, off_t * data_start_offset) {
vorbis_codec_data * data = NULL;
/* init stuff */
data = calloc(1,sizeof(vorbis_codec_data));
if (!data) goto fail;
data->buffer_size = ogl_vorbis_DEFAULT_BUFFER_SIZE;
data->buffer = calloc(sizeof(uint8_t), data->buffer_size);
if (!data->buffer) goto fail;
/* init vorbis stream state, using 3 fake Ogg setup packets (info, comments, setup/codebooks)
* libvorbis expects parsed Ogg pages, but we'll fake them with our raw data instead */
vorbis_info_init(&data->vi);
vorbis_comment_init(&data->vc);
data->op.packet = data->buffer;
data->op.b_o_s = 1; /* fake headers start */
{
/* read 3 packets with triad (id/comment/setup), each with an OGL header */
off_t offset = start_offset;
size_t packet_size;
/* normal identificacion packet */
packet_size = (uint16_t)read_16bitLE(offset, streamFile) >> 2;
if (packet_size > data->buffer_size) goto fail;
data->op.bytes = read_streamfile(data->buffer,offset+2,packet_size, streamFile);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse identification header */
offset += 2+packet_size;
/* normal comment packet */
packet_size = (uint16_t)read_16bitLE(offset, streamFile) >> 2;
if (packet_size > data->buffer_size) goto fail;
data->op.bytes = read_streamfile(data->buffer,offset+2,packet_size, streamFile);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) !=0 ) goto fail; /* parse comment header */
offset += 2+packet_size;
/* normal setup packet */
packet_size = (uint16_t)read_16bitLE(offset, streamFile) >> 2;
if (packet_size > data->buffer_size) goto fail;
data->op.bytes = read_streamfile(data->buffer,offset+2,packet_size, streamFile);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse setup header */
offset += 2+packet_size;
/* data starts after triad */
*data_start_offset = offset;
}
data->op.b_o_s = 0; /* end of fake headers */
/* init vorbis global and block state */
if (vorbis_synthesis_init(&data->vd,&data->vi) != 0) goto fail;
if (vorbis_block_init(&data->vd,&data->vb) != 0) goto fail;
return data;
fail:
free_ogl_vorbis(data);
return NULL;
}
/**
* Decodes raw OGL vorbis
*/
void decode_ogl_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
vorbis_codec_data * data = vgmstream->codec_data;
size_t stream_size = get_streamfile_size(stream->streamfile);
//data->op.packet = data->buffer;/* implicit from init */
int samples_done = 0;
while (samples_done < samples_to_do) {
/* extra EOF check for edge cases */
if (stream->offset > stream_size) {
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample));
break;
}
if (data->samples_full) { /* read more samples */
int samples_to_get;
float **pcm;
/* get PCM samples from libvorbis buffers */
samples_to_get = vorbis_synthesis_pcmout(&data->vd, &pcm);
if (!samples_to_get) {
data->samples_full = 0; /* request more if empty*/
continue;
}
if (data->samples_to_discard) {
/* discard samples for looping */
if (samples_to_get > data->samples_to_discard)
samples_to_get = data->samples_to_discard;
data->samples_to_discard -= samples_to_get;
}
else {
/* get max samples and convert from Vorbis float pcm to 16bit pcm */
if (samples_to_get > samples_to_do - samples_done)
samples_to_get = samples_to_do - samples_done;
pcm_convert_float_to_16(data, outbuf + samples_done * channels, samples_to_get, pcm);
samples_done += samples_to_get;
}
/* mark consumed samples from the buffer
* (non-consumed samples are returned in next vorbis_synthesis_pcmout calls) */
vorbis_synthesis_read(&data->vd, samples_to_get);
}
else { /* read more data */
int rc;
/* this is not actually needed, but feels nicer */
data->op.granulepos += samples_to_do;
data->op.packetno++;
/* get next packet size from the OGL 16b header */
data->op.bytes = (uint16_t)read_16bitLE(stream->offset, stream->streamfile) >> 2;
stream->offset += 2;
if (data->op.bytes == 0 || data->op.bytes == 0xFFFF) {
goto decode_fail; /* eof or end padding */
}
/* read raw block */
if (read_streamfile(data->buffer,stream->offset, data->op.bytes,stream->streamfile) != data->op.bytes) {
goto decode_fail; /* wrong packet? */
}
stream->offset += data->op.bytes;
/* parse the fake ogg packet into a logical vorbis block */
rc = vorbis_synthesis(&data->vb,&data->op);
if (rc == OV_ENOTAUDIO) {
VGM_LOG("vorbis_synthesis: not audio packet @ %lx\n",stream->offset); getchar();
continue; /* not tested */
} else if (rc != 0) {
goto decode_fail;
}
/* finally decode the logical block into samples */
rc = vorbis_synthesis_blockin(&data->vd,&data->vb);
if (rc != 0) {
goto decode_fail; /* ? */
}
data->samples_full = 1;
}
}
return;
decode_fail:
/* on error just put some 0 samples */
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample));
}
static void pcm_convert_float_to_16(vorbis_codec_data * data, sample * outbuf, int samples_to_do, float ** pcm) {
/* mostly from Xiph's decoder_example.c */
int i,j;
/* convert float PCM (multichannel float array, with pcm[0]=ch0, pcm[1]=ch1, pcm[2]=ch0, etc)
* to 16 bit signed PCM ints (host order) and interleave + fix clipping */
for (i = 0; i < data->vi.channels; i++) {
sample *ptr = outbuf + i;
float *mono = pcm[i];
for (j = 0; j < samples_to_do; j++) {
int val = floor(mono[j] * 32767.f + .5f);
if (val > 32767) val = 32767;
if (val < -32768) val = -32768;
*ptr = val;
ptr += data->vi.channels;
}
}
}
/* ********************************************** */
void free_ogl_vorbis(vorbis_codec_data * data) {
if (!data)
return;
/* internal decoder cleanp */
vorbis_info_clear(&data->vi);
vorbis_comment_clear(&data->vc);
vorbis_dsp_clear(&data->vd);
free(data->buffer);
free(data);
}
void reset_ogl_vorbis(VGMSTREAM *vgmstream) {
vorbis_codec_data *data = vgmstream->codec_data;
/* Seeking is provided by the Ogg layer, so with raw vorbis we need seek tables instead.
* To avoid having to parse different formats we'll just discard until the expected sample */
vorbis_synthesis_restart(&data->vd);
data->samples_to_discard = 0;
}
void seek_ogl_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) {
vorbis_codec_data *data = vgmstream->codec_data;
/* Seeking is provided by the Ogg layer, so with raw vorbis we need seek tables instead.
* To avoid having to parse different formats we'll just discard until the expected sample */
vorbis_synthesis_restart(&data->vd);
data->samples_to_discard = num_sample;
if (vgmstream->loop_ch)
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset;
}
#endif

View File

@ -85,3 +85,7 @@ void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int chan
outbuf[sample_count]=read_16bitLE(stream->offset+i*2*channelspacing,stream->streamfile)^stream->key_xor;
}
}
size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample) {
return bytes / channels / (bits_per_sample/8);
}

View File

@ -432,3 +432,8 @@ void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int cha
stream->adpcm_history1_32 = hist1;
stream->adpcm_history2_32 = hist2;
}
size_t ps_bytes_to_samples(size_t bytes, int channels) {
return bytes / channels / 16 * 28;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,305 @@
#include "coding.h"
#include <math.h>
#ifdef VGM_USE_VORBIS
#include <vorbis/codec.h>
#include "wwise_vorbis_utils.h"
#define WWISE_VORBIS_DEFAULT_BUFFER_SIZE 0x8000 /* should be at least the size of the setup header, ~0x2000 */
static void pcm_convert_float_to_16(vorbis_codec_data * data, sample * outbuf, int samples_to_do, float ** pcm);
static int vorbis_make_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_short, int blocksize_long);
static int vorbis_make_header_comment(uint8_t * buf, size_t bufsize);
/**
* Inits a raw Wwise vorbis stream.
*
* Vorbis packets are stored in .ogg, which is divided into ogg pages/packets, and the first packets contain necessary
* vorbis setup. For raw vorbis the setup is stored it elsewhere (i.e.- in the .exe), presumably to shave off some kb
* per stream and codec startup time. We'll read the external setup and raw data and decode it with libvorbis.
*
* Wwise stores a reduced setup, and the raw vorbis packets have mini headers with the block size,
* and vorbis packets themselves may reduced as well. The format evolved over time so there are some variations.
* The Wwise implementation uses Tremor (fixed-point Vorbis) but shouldn't matter.
*
* Format reverse engineered by hcs in ww2ogg (https://github.com/hcs64/ww2ogg).
* Info from the official docs (https://www.xiph.org/vorbis/doc/libvorbis/overview.html).
*/
vorbis_codec_data * init_wwise_vorbis_codec_data(STREAMFILE *streamFile, off_t start_offset, int channels, int sample_rate, int blocksize_0_exp, int blocksize_1_exp,
wwise_setup_type setup_type, wwise_header_type header_type, wwise_packet_type packet_type, int big_endian) {
vorbis_codec_data * data = NULL;
size_t header_size, packet_size;
/* init stuff */
data = calloc(1,sizeof(vorbis_codec_data));
if (!data) goto fail;
data->buffer_size = WWISE_VORBIS_DEFAULT_BUFFER_SIZE;
data->buffer = calloc(sizeof(uint8_t), data->buffer_size);
if (!data->buffer) goto fail;
data->setup_type = setup_type;
data->header_type = header_type;
data->packet_type = packet_type;
/* init vorbis stream state, using 3 fake Ogg setup packets (info, comments, setup/codebooks)
* libvorbis expects parsed Ogg pages, but we'll fake them with our raw data instead */
vorbis_info_init(&data->vi);
vorbis_comment_init(&data->vc);
data->op.packet = data->buffer;
data->op.b_o_s = 1; /* fake headers start */
if (setup_type == HEADER_TRIAD) {
/* read 3 Wwise packets with triad (id/comment/setup), each with a Wwise header */
off_t offset = start_offset;
/* normal identificacion packet */
header_size = wwise_vorbis_get_header(streamFile, offset, data->header_type, (int*)&data->op.granulepos, &packet_size, big_endian);
if (!header_size || packet_size > data->buffer_size) goto fail;
data->op.bytes = read_streamfile(data->buffer,offset+header_size,packet_size, streamFile);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse identification header */
offset += header_size + packet_size;
/* normal comment packet */
header_size = wwise_vorbis_get_header(streamFile, offset, data->header_type, (int*)&data->op.granulepos, &packet_size, big_endian);
if (!header_size || packet_size > data->buffer_size) goto fail;
data->op.bytes = read_streamfile(data->buffer,offset+header_size,packet_size, streamFile);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) !=0 ) goto fail; /* parse comment header */
offset += header_size + packet_size;
/* normal setup packet */
header_size = wwise_vorbis_get_header(streamFile, offset, data->header_type, (int*)&data->op.granulepos, &packet_size, big_endian);
if (!header_size || packet_size > data->buffer_size) goto fail;
data->op.bytes = read_streamfile(data->buffer,offset+header_size,packet_size, streamFile);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse setup header */
offset += header_size + packet_size;
}
else {
/* rebuild headers */
/* new identificacion packet */
data->op.bytes = vorbis_make_header_identification(data->buffer, data->buffer_size, channels, sample_rate, blocksize_0_exp, blocksize_1_exp);
if (!data->op.bytes) goto fail;
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse identification header */
/* new comment packet */
data->op.bytes = vorbis_make_header_comment(data->buffer, data->buffer_size);
if (!data->op.bytes) goto fail;
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) !=0 ) goto fail; /* parse comment header */
/* rebuild setup packet */
data->op.bytes = wwise_vorbis_rebuild_setup(data->buffer, data->buffer_size, streamFile, start_offset, data, big_endian, channels);
if (!data->op.bytes) goto fail;
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse setup header */
}
data->op.b_o_s = 0; /* end of fake headers */
/* init vorbis global and block state */
if (vorbis_synthesis_init(&data->vd,&data->vi) != 0) goto fail;
if (vorbis_block_init(&data->vd,&data->vb) != 0) goto fail;
return data;
fail:
free_wwise_vorbis(data);
return NULL;
}
/**
* Decodes raw Wwise Vorbis
*/
void decode_wwise_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
vorbis_codec_data * data = vgmstream->codec_data;
size_t stream_size = get_streamfile_size(stream->streamfile);
//data->op.packet = data->buffer;/* implicit from init */
int samples_done = 0;
while (samples_done < samples_to_do) {
/* extra EOF check for edge cases */
if (stream->offset > stream_size) {
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample));
break;
}
if (data->samples_full) { /* read more samples */
int samples_to_get;
float **pcm;
/* get PCM samples from libvorbis buffers */
samples_to_get = vorbis_synthesis_pcmout(&data->vd, &pcm);
if (!samples_to_get) {
data->samples_full = 0; /* request more if empty*/
continue;
}
if (data->samples_to_discard) {
/* discard samples for looping */
if (samples_to_get > data->samples_to_discard)
samples_to_get = data->samples_to_discard;
data->samples_to_discard -= samples_to_get;
}
else {
/* get max samples and convert from Vorbis float pcm to 16bit pcm */
if (samples_to_get > samples_to_do - samples_done)
samples_to_get = samples_to_do - samples_done;
pcm_convert_float_to_16(data, outbuf + samples_done * channels, samples_to_get, pcm);
samples_done += samples_to_get;
}
/* mark consumed samples from the buffer
* (non-consumed samples are returned in next vorbis_synthesis_pcmout calls) */
vorbis_synthesis_read(&data->vd, samples_to_get);
}
else { /* read more data */
int rc;
size_t header_size, packet_size;
data->op.packetno++; /* not actually needed, but feels nicer */
/* reconstruct a Wwise packet, if needed; final bytes may be bigger than packet_size so we get the header offsets here */
header_size = wwise_vorbis_get_header(stream->streamfile, stream->offset, data->header_type, (int*)&data->op.granulepos, &packet_size, vgmstream->codec_endian);
if (!header_size || packet_size > data->buffer_size) {
VGM_LOG("Wwise Vorbis: wrong packet (0x%x) @ %lx\n", packet_size, stream->offset);
goto decode_fail;
}
data->op.bytes = wwise_vorbis_rebuild_packet(data->buffer, data->buffer_size, stream->streamfile,stream->offset, data, vgmstream->codec_endian);
stream->offset += header_size + packet_size; /* update first to avoid infinite loops */
if (!data->op.bytes || data->op.bytes >= 0xFFFF) {
VGM_LOG("Wwise Vorbis: wrong bytes (0x%lx) @ %lx\n", data->op.bytes, stream->offset);
goto decode_fail;
}
/* parse the fake ogg packet into a logical vorbis block */
rc = vorbis_synthesis(&data->vb,&data->op);
if (rc == OV_ENOTAUDIO) {
VGM_LOG("Wwise Vorbis: not audio packet @ %lx\n",stream->offset);
continue; /* bad packet parsing */
} else if (rc != 0) {
VGM_LOG("Wwise Vorbis: cannot parse Vorbis block @ %lx\n",stream->offset);
goto decode_fail;
}
/* finally decode the logical block into samples */
rc = vorbis_synthesis_blockin(&data->vd,&data->vb);
if (rc != 0) {
VGM_LOG("Wwise Vorbis: cannot decode Vorbis block @ %lx\n",stream->offset);
goto decode_fail; /* ? */
}
data->samples_full = 1;
}
}
return;
decode_fail:
/* on error just put some 0 samples */
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample));
}
/* *************************************************** */
static void pcm_convert_float_to_16(vorbis_codec_data * data, sample * outbuf, int samples_to_do, float ** pcm) {
/* mostly from Xiph's decoder_example.c */
int i,j;
/* convert float PCM (multichannel float array, with pcm[0]=ch0, pcm[1]=ch1, pcm[2]=ch0, etc)
* to 16 bit signed PCM ints (host order) and interleave + fix clipping */
for (i = 0; i < data->vi.channels; i++) {
sample *ptr = outbuf + i;
float *mono = pcm[i];
for (j = 0; j < samples_to_do; j++) {
int val = floor(mono[j] * 32767.f + .5f);
if (val > 32767) val = 32767;
if (val < -32768) val = -32768;
*ptr = val;
ptr += data->vi.channels;
}
}
}
static int vorbis_make_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_0_exp, int blocksize_1_exp) {
int bytes = 0x1e;
uint8_t blocksizes;
if (bytes > bufsize) return 0;
blocksizes = (blocksize_0_exp << 4) | (blocksize_1_exp);
put_8bit (buf+0x00, 0x01); /* packet_type (id) */
memcpy (buf+0x01, "vorbis", 6); /* id */
put_32bitLE(buf+0x07, 0x00); /* vorbis_version (fixed) */
put_8bit (buf+0x0b, channels); /* audio_channels */
put_32bitLE(buf+0x0c, sample_rate); /* audio_sample_rate */
put_32bitLE(buf+0x10, 0x00); /* bitrate_maximum (optional hint) */
put_32bitLE(buf+0x14, 0x00); /* bitrate_nominal (optional hint) */
put_32bitLE(buf+0x18, 0x00); /* bitrate_minimum (optional hint) */
put_8bit (buf+0x1c, blocksizes); /* blocksize_0 + blocksize_1 nibbles */
put_8bit (buf+0x1d, 0x01); /* framing_flag (fixed) */
return bytes;
}
static int vorbis_make_header_comment(uint8_t * buf, size_t bufsize) {
int bytes = 0x19;
if (bytes > bufsize) return 0;
put_8bit (buf+0x00, 0x03); /* packet_type (comments) */
memcpy (buf+0x01, "vorbis", 6); /* id */
put_32bitLE(buf+0x07, 0x09); /* vendor_length */
memcpy (buf+0x0b, "vgmstream", 9); /* vendor_string */
put_32bitLE(buf+0x14, 0x00); /* user_comment_list_length */
put_8bit (buf+0x18, 0x01); /* framing_flag (fixed) */
return bytes;
}
/* *************************************** */
void free_wwise_vorbis(vorbis_codec_data * data) {
if (!data)
return;
/* internal decoder cleanp */
vorbis_info_clear(&data->vi);
vorbis_comment_clear(&data->vc);
vorbis_dsp_clear(&data->vd);
free(data->buffer);
free(data);
}
void reset_wwise_vorbis(VGMSTREAM *vgmstream) {
vorbis_codec_data *data = vgmstream->codec_data;
/* Seeking is provided by the Ogg layer, so with raw vorbis we need seek tables instead.
* To avoid having to parse different formats we'll just discard until the expected sample */
vorbis_synthesis_restart(&data->vd);
data->samples_to_discard = 0;
}
void seek_wwise_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) {
vorbis_codec_data *data = vgmstream->codec_data;
/* Seeking is provided by the Ogg layer, so with raw vorbis we need seek tables instead.
* To avoid having to parse different formats we'll just discard until the expected sample */
vorbis_synthesis_restart(&data->vd);
data->samples_to_discard = num_sample;
if (vgmstream->loop_ch) /* this func is only using for looping though */
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
#ifndef _WWISE_VORBIS_UTILS_H_
#define _WWISE_VORBIS_UTILS_H_
#include "coding.h"
int wwise_vorbis_get_header(STREAMFILE *streamFile, off_t offset, wwise_header_type header_type, int * granulepos, size_t * packet_size, int big_endian);
int wwise_vorbis_rebuild_packet(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_codec_data * data, int big_endian);
int wwise_vorbis_rebuild_setup(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_codec_data * data, int big_endian, int channels);
#endif/*_WWISE_VORBIS_UTILS_H_ */

View File

@ -180,6 +180,7 @@ static const char* extension_list[] = {
"nwa",
//"ogg", //common
"ogl",
"oma", //FFmpeg, not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
"omu",
"otm",
@ -197,6 +198,7 @@ static const char* extension_list[] = {
"psnd",
"psw",
"rak",
"ras",
"raw",
"rkv",
@ -261,6 +263,8 @@ static const char* extension_list[] = {
"swag",
"swav",
"swd",
"sxd",
"sxd2",
"tec",
"thp",
@ -419,6 +423,7 @@ static const coding_info coding_info_list[] = {
{coding_SNDS_IMA, "Heavy Iron .snds 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_WWISE_IMA, "Audiokinetic Wwise 4-bit IMA ADPCM"},
{coding_WS, "Westwood Studios ADPCM"},
{coding_ACM, "InterPlay ACM"},
{coding_NWA0, "NWA DPCM Level 0"},
@ -437,6 +442,8 @@ static const coding_info coding_info_list[] = {
#ifdef VGM_USE_VORBIS
{coding_ogg_vorbis, "Ogg Vorbis"},
{coding_fsb_vorbis, "FSB Vorbis"},
{coding_wwise_vorbis, "Wwise Vorbis"},
{coding_ogl_vorbis, "OGL Vorbis"},
#endif
#ifdef VGM_USE_MPEG
{coding_fake_MPEG2_L2, "MPEG-2 Layer II Audio"},
@ -817,7 +824,7 @@ static const meta_info meta_info_list[] = {
{meta_PS3_IVAG, "PS3 'IVAG' Header"},
{meta_PS2_2PFS, "Konami 2PFS header"},
{meta_RSD6OOGV, "RSD6/OOGV Header"},
{meta_UBI_CKD, "CKD 'RIFF' Header"},
{meta_UBI_CKD, "Ubisoft CKD RIFF header"},
{meta_PS2_VBK, "PS2 VBK Header"},
{meta_OTM, "Otomedius OTM Header"},
{meta_CSTM, "Nintendo 3DS CSTM Header"},
@ -837,6 +844,9 @@ static const meta_info meta_info_list[] = {
{meta_XMA_RIFF, "Microsoft XMA RIFF header"},
{meta_X360_AST, "Capcom AST header"},
{meta_WWISE_RIFF, "Audiokinetic Wwise RIFF header"},
{meta_UBI_RAKI, "Ubisoft RAKI header"},
{meta_SXD, "Sony SXD header"},
{meta_OGL, "Shin'en OGL header"},
#ifdef VGM_USE_VORBIS
{meta_OGG_VORBIS, "Ogg Vorbis"},

View File

@ -203,8 +203,11 @@ VGMSTREAM * init_vgmstream_Cstr(STREAMFILE *streamFile) {
if (!(double_loop_end &&
read_32bitBE(0x30,streamFile) +
read_32bitBE(0x0c,streamFile) + 8 ==
read_32bitBE(0x10,streamFile)*2))
goto fail;
read_32bitBE(0x10,streamFile)*2)) {
/* for Mr.Driller Drill Land, no idea about the above but seems to play and loop ok */
VGM_LOG("Cstr: bad loop check ignored\n");
//goto fail;
}
#ifdef DEBUG
fprintf(stderr,"loop points agree\n");

View File

@ -1,259 +1,264 @@
noinst_LTLIBRARIES = libmeta.la
AM_CFLAGS = -Wall @CFLAGS@ -DVAR_ARRAYS -I$(top_builddir) -I$(top_srcdir)
AM_MAKEFLAGS=-f Makefile.unix
libmeta_la_LDFLAGS =
libmeta_la_SOURCES =
libmeta_la_SOURCES += Cstr.c
libmeta_la_SOURCES += adx_header.c
libmeta_la_SOURCES += afc_header.c
libmeta_la_SOURCES += agsc.c
libmeta_la_SOURCES += ast.c
libmeta_la_SOURCES += brstm.c
libmeta_la_SOURCES += ea_header.c
libmeta_la_SOURCES += gcsw.c halpst.c
libmeta_la_SOURCES += nds_strm.c
libmeta_la_SOURCES += ngc_adpdtk.c
libmeta_la_SOURCES += ngc_caf.c
libmeta_la_SOURCES += ngc_dsp_std.c
libmeta_la_SOURCES += ps2_ads.c
libmeta_la_SOURCES += ps2_exst.c
libmeta_la_SOURCES += ps2_ild.c
libmeta_la_SOURCES += ps2_int.c
libmeta_la_SOURCES += ps2_mib.c
libmeta_la_SOURCES += ps2_mic.c
libmeta_la_SOURCES += ps2_npsf.c
libmeta_la_SOURCES += ps2_pnb.c
libmeta_la_SOURCES += ps2_rxw.c
libmeta_la_SOURCES += ps2_str.c
libmeta_la_SOURCES += ps2_svag.c
libmeta_la_SOURCES += ps2_vag.c
libmeta_la_SOURCES += ps2_vpk.c
libmeta_la_SOURCES += psx_cdxa.c
libmeta_la_SOURCES += raw.c
libmeta_la_SOURCES += rs03.c
libmeta_la_SOURCES += rsf.c
libmeta_la_SOURCES += rwsd.c
libmeta_la_SOURCES += psx_gms.c
libmeta_la_SOURCES += xbox_xwav.c
libmeta_la_SOURCES += xbox_wavm.c
libmeta_la_SOURCES += genh.c
libmeta_la_SOURCES += ogg_vorbis_file.c
libmeta_la_SOURCES += ps2_bmdx.c
libmeta_la_SOURCES += aifc.c
libmeta_la_SOURCES += str_snds.c
libmeta_la_SOURCES += ws_aud.c
libmeta_la_SOURCES += ahx.c
libmeta_la_SOURCES += ivb.c
libmeta_la_SOURCES += svs.c
libmeta_la_SOURCES += riff.c
libmeta_la_SOURCES += pos.c
libmeta_la_SOURCES += nwa.c
libmeta_la_SOURCES += ps2_rws.c
libmeta_la_SOURCES += ps2_hgc1.c
libmeta_la_SOURCES += xss.c
libmeta_la_SOURCES += ps2_sl3.c
libmeta_la_SOURCES += ps2_aus.c
libmeta_la_SOURCES += fsb.c
libmeta_la_SOURCES += fsb5.c
libmeta_la_SOURCES += rsd.c
libmeta_la_SOURCES += rwx.c
libmeta_la_SOURCES += xwb.c
libmeta_la_SOURCES += ea_old.c
libmeta_la_SOURCES += ps2_xa30.c
libmeta_la_SOURCES += musc.c
libmeta_la_SOURCES += ps2_leg.c
libmeta_la_SOURCES += ps2_filp.c
libmeta_la_SOURCES += ps2_ikm.c
libmeta_la_SOURCES += musx.c
libmeta_la_SOURCES += ps2_sfs.c
libmeta_la_SOURCES += sat_dvi.c
libmeta_la_SOURCES += ps2_bg00.c
libmeta_la_SOURCES += dc_kcey.c
libmeta_la_SOURCES += ps2_rstm.c
libmeta_la_SOURCES += acm.c
libmeta_la_SOURCES += ps2_kces.c
libmeta_la_SOURCES += ps2_dxh.c
libmeta_la_SOURCES += ps2_psh.c
libmeta_la_SOURCES += mus_acm.c
libmeta_la_SOURCES += sli.c
libmeta_la_SOURCES += sfl.c
libmeta_la_SOURCES += pcm.c
libmeta_la_SOURCES += ps2_psw.c
libmeta_la_SOURCES += rkv.c
libmeta_la_SOURCES += ps2_vas.c
libmeta_la_SOURCES += ps2_tec.c
libmeta_la_SOURCES += ps2_enth.c
libmeta_la_SOURCES += sdt.c
libmeta_la_SOURCES += aix.c
libmeta_la_SOURCES += ngc_tydsp.c
libmeta_la_SOURCES += wvs.c
libmeta_la_SOURCES += xbox_stma.c
libmeta_la_SOURCES += xbox_ims.c
libmeta_la_SOURCES += de2.c
libmeta_la_SOURCES += dc_str.c
libmeta_la_SOURCES += xbox_xmu.c
libmeta_la_SOURCES += ngc_bh2pcm.c
libmeta_la_SOURCES += sat_sap.c
libmeta_la_SOURCES += dc_idvi.c
libmeta_la_SOURCES += ps2_rnd.c
libmeta_la_SOURCES += xbox_xvas.c
libmeta_la_SOURCES += kraw.c
libmeta_la_SOURCES += ps2_xa2.c
libmeta_la_SOURCES += idsp.c
libmeta_la_SOURCES += ngc_ymf.c
libmeta_la_SOURCES += nds_sad.c
libmeta_la_SOURCES += ps2_ccc.c
libmeta_la_SOURCES += psx_fag.c
libmeta_la_SOURCES += ps2_mihb.c
libmeta_la_SOURCES += ngc_pdt.c
libmeta_la_SOURCES += wii_mus.c
libmeta_la_SOURCES += dc_asd.c
libmeta_la_SOURCES += naomi_spsd.c
libmeta_la_SOURCES += bgw.c
libmeta_la_SOURCES += ps2_ass.c
libmeta_la_SOURCES += ngc_waa_wac_wad_wam.c
libmeta_la_SOURCES += seg.c
libmeta_la_SOURCES += str_asr.c
libmeta_la_SOURCES += zwdsp.c
libmeta_la_SOURCES += gca.c
libmeta_la_SOURCES += ish_isd.c
libmeta_la_SOURCES += spt_spd.c
libmeta_la_SOURCES += ydsp.c
libmeta_la_SOURCES += gsp_gsb.c
libmeta_la_SOURCES += ngc_ssm.c
libmeta_la_SOURCES += msvp.c
libmeta_la_SOURCES += ps2_joe.c
libmeta_la_SOURCES += vs.c
libmeta_la_SOURCES += vgs.c
libmeta_la_SOURCES += dc_dcsw_dcs.c
libmeta_la_SOURCES += wii_smp.c
libmeta_la_SOURCES += ss_stream.c
libmeta_la_SOURCES += emff.c
libmeta_la_SOURCES += thp.c
libmeta_la_SOURCES += wii_sts.c
libmeta_la_SOURCES += capdsp.c
libmeta_la_SOURCES += wii_sng.c
libmeta_la_SOURCES += aax.c
libmeta_la_SOURCES += ps2_p2bt.c
libmeta_la_SOURCES += ps2_gbts.c
libmeta_la_SOURCES += ngc_ffcc_str.c
libmeta_la_SOURCES += sat_baka.c
libmeta_la_SOURCES += nds_swav.c
libmeta_la_SOURCES += vsf.c
libmeta_la_SOURCES += nds_rrds.c
libmeta_la_SOURCES += ps2_tk5.c
libmeta_la_SOURCES += ads.c
libmeta_la_SOURCES += wii_str.c
libmeta_la_SOURCES += zsd.c
libmeta_la_SOURCES += ps2_mcg.c
libmeta_la_SOURCES += redspark.c
libmeta_la_SOURCES += ivaud.c
libmeta_la_SOURCES += ps2_vgs.c
libmeta_la_SOURCES += ps2_sps.c
libmeta_la_SOURCES += nds_hwas.c
libmeta_la_SOURCES += ngc_lps.c
libmeta_la_SOURCES += ps2_snd.c
libmeta_la_SOURCES += naomi_adpcm.c
libmeta_la_SOURCES += sd9.c
libmeta_la_SOURCES += 2dx9.c
libmeta_la_SOURCES += ngc_dsp_ygo.c
libmeta_la_SOURCES += ps2_vgv.c
libmeta_la_SOURCES += ngc_gcub.c
libmeta_la_SOURCES += maxis_xa.c
libmeta_la_SOURCES += ngc_sck_dsp.c
libmeta_la_SOURCES += apple_caff.c
libmeta_la_SOURCES += pc_mxst.c
libmeta_la_SOURCES += pc_sob.c
libmeta_la_SOURCES += exakt_sc.c
libmeta_la_SOURCES += wii_bns.c
libmeta_la_SOURCES += pona.c
libmeta_la_SOURCES += xbox_hlwav.c
libmeta_la_SOURCES += stx.c
libmeta_la_SOURCES += ps2_stm.c
libmeta_la_SOURCES += myspd.c
libmeta_la_SOURCES += his.c
libmeta_la_SOURCES += ps2_ast.c
libmeta_la_SOURCES += dmsg_segh.c
libmeta_la_SOURCES += ngc_dsp_konami.c
libmeta_la_SOURCES += ps2_ster.c
libmeta_la_SOURCES += bnsf.c
libmeta_la_SOURCES += ps2_wb.c
libmeta_la_SOURCES += s14_sss.c
libmeta_la_SOURCES += ps2_gcm.c
libmeta_la_SOURCES += ps2_smpl.c
libmeta_la_SOURCES += ps2_msa.c
libmeta_la_SOURCES += pc_smp.c
libmeta_la_SOURCES += p3d.c
libmeta_la_SOURCES += ps2_adsc.c
libmeta_la_SOURCES += psx_str_mgav.c
libmeta_la_SOURCES += ngc_bo2.c
libmeta_la_SOURCES += ngc_dsp_mpds.c
libmeta_la_SOURCES += ps2_khv.c
libmeta_la_SOURCES += ps2_voi.c
libmeta_la_SOURCES += dsp_sth_str.c
libmeta_la_SOURCES += ps2_b1s.c
libmeta_la_SOURCES += ps2_wad.c
libmeta_la_SOURCES += ps2_lpcm.c
libmeta_la_SOURCES += ps2_adm.c
libmeta_la_SOURCES += dsp_bdsp.c
libmeta_la_SOURCES += ps2_vms.c
libmeta_la_SOURCES += ps2_xau.c
libmeta_la_SOURCES += gh3_bar.c
libmeta_la_SOURCES += ffw.c
libmeta_la_SOURCES += ps2_jstm.c
libmeta_la_SOURCES += ps3_xvag.c
libmeta_la_SOURCES += ps3_cps.c
libmeta_la_SOURCES += sqex_scd.c
libmeta_la_SOURCES += ngc_nst_dsp.c
libmeta_la_SOURCES += baf.c
libmeta_la_SOURCES += ps3_msf.c
libmeta_la_SOURCES += nub_vag.c
libmeta_la_SOURCES += ps3_past.c
libmeta_la_SOURCES += sgxd.c
libmeta_la_SOURCES += ngca.c
libmeta_la_SOURCES += wii_ras.c
libmeta_la_SOURCES += ps2_spm.c
libmeta_la_SOURCES += x360_tra.c
libmeta_la_SOURCES += ps2_iab.c
libmeta_la_SOURCES += ps2_strlr.c
libmeta_la_SOURCES += lsf.c
libmeta_la_SOURCES += vawx.c
libmeta_la_SOURCES += pc_snds.c
libmeta_la_SOURCES += ps2_wmus.c
libmeta_la_SOURCES += mattel_hyperscan.c
libmeta_la_SOURCES += ios_psnd.c
libmeta_la_SOURCES += pc_adp.c
libmeta_la_SOURCES += excitebots.c
libmeta_la_SOURCES += ps2_mtaf.c
libmeta_la_SOURCES += ps3_klbs.c
libmeta_la_SOURCES += tun.c
libmeta_la_SOURCES += wpd.c
libmeta_la_SOURCES += mn_str.c
libmeta_la_SOURCES += ps2_mss.c
libmeta_la_SOURCES += ps2_hsf.c
libmeta_la_SOURCES += ps3_ivag.c
libmeta_la_SOURCES += ps2_2pfs.c
libmeta_la_SOURCES += ubi_ckd.c
libmeta_la_SOURCES += otm.c
libmeta_la_SOURCES += bcstm.c
libmeta_la_SOURCES += bfwav.c
libmeta_la_SOURCES += bfstm.c
libmeta_la_SOURCES += g1l.c
libmeta_la_SOURCES += ps2_vbk.c
libmeta_la_SOURCES += mca.c
libmeta_la_SOURCES += btsnd.c
libmeta_la_SOURCES += hca.c
libmeta_la_SOURCES += ps2_svag_snk.c
libmeta_la_SOURCES += mp4.c
libmeta_la_SOURCES += xma.c
libmeta_la_SOURCES += ps2_vds_vdm.c
libmeta_la_SOURCES += x360_cxs.c
libmeta_la_SOURCES += dsp_adx.c
libmeta_la_SOURCES += bik.c
libmeta_la_SOURCES += akb.c
libmeta_la_SOURCES += x360_ast.c
libmeta_la_SOURCES += wwise.c
EXTRA_DIST = meta.h
noinst_LTLIBRARIES = libmeta.la
AM_CFLAGS = -Wall @CFLAGS@ -DVAR_ARRAYS -I$(top_builddir) -I$(top_srcdir)
AM_MAKEFLAGS=-f Makefile.unix
libmeta_la_LDFLAGS =
libmeta_la_SOURCES =
libmeta_la_SOURCES += Cstr.c
libmeta_la_SOURCES += adx.c
libmeta_la_SOURCES += afc_header.c
libmeta_la_SOURCES += agsc.c
libmeta_la_SOURCES += ast.c
libmeta_la_SOURCES += brstm.c
libmeta_la_SOURCES += ea_header.c
libmeta_la_SOURCES += gcsw.c halpst.c
libmeta_la_SOURCES += nds_strm.c
libmeta_la_SOURCES += ngc_adpdtk.c
libmeta_la_SOURCES += ngc_caf.c
libmeta_la_SOURCES += ngc_dsp_std.c
libmeta_la_SOURCES += ps2_ads.c
libmeta_la_SOURCES += ps2_exst.c
libmeta_la_SOURCES += ps2_ild.c
libmeta_la_SOURCES += ps2_int.c
libmeta_la_SOURCES += ps2_mib.c
libmeta_la_SOURCES += ps2_mic.c
libmeta_la_SOURCES += ps2_npsf.c
libmeta_la_SOURCES += ps2_pnb.c
libmeta_la_SOURCES += ps2_rxw.c
libmeta_la_SOURCES += ps2_str.c
libmeta_la_SOURCES += ps2_svag.c
libmeta_la_SOURCES += ps2_vag.c
libmeta_la_SOURCES += ps2_vpk.c
libmeta_la_SOURCES += psx_cdxa.c
libmeta_la_SOURCES += raw.c
libmeta_la_SOURCES += rs03.c
libmeta_la_SOURCES += rsf.c
libmeta_la_SOURCES += rwsd.c
libmeta_la_SOURCES += psx_gms.c
libmeta_la_SOURCES += xbox_xwav.c
libmeta_la_SOURCES += xbox_wavm.c
libmeta_la_SOURCES += genh.c
libmeta_la_SOURCES += ogg_vorbis_file.c
libmeta_la_SOURCES += ps2_bmdx.c
libmeta_la_SOURCES += aifc.c
libmeta_la_SOURCES += str_snds.c
libmeta_la_SOURCES += ws_aud.c
libmeta_la_SOURCES += ahx.c
libmeta_la_SOURCES += ivb.c
libmeta_la_SOURCES += svs.c
libmeta_la_SOURCES += riff.c
libmeta_la_SOURCES += pos.c
libmeta_la_SOURCES += nwa.c
libmeta_la_SOURCES += ps2_rws.c
libmeta_la_SOURCES += ps2_hgc1.c
libmeta_la_SOURCES += xss.c
libmeta_la_SOURCES += ps2_sl3.c
libmeta_la_SOURCES += ps2_aus.c
libmeta_la_SOURCES += fsb.c
libmeta_la_SOURCES += fsb5.c
libmeta_la_SOURCES += rsd.c
libmeta_la_SOURCES += rwx.c
libmeta_la_SOURCES += xwb.c
libmeta_la_SOURCES += ea_old.c
libmeta_la_SOURCES += ps2_xa30.c
libmeta_la_SOURCES += musc.c
libmeta_la_SOURCES += ps2_leg.c
libmeta_la_SOURCES += ps2_filp.c
libmeta_la_SOURCES += ps2_ikm.c
libmeta_la_SOURCES += musx.c
libmeta_la_SOURCES += ps2_sfs.c
libmeta_la_SOURCES += sat_dvi.c
libmeta_la_SOURCES += ps2_bg00.c
libmeta_la_SOURCES += dc_kcey.c
libmeta_la_SOURCES += ps2_rstm.c
libmeta_la_SOURCES += acm.c
libmeta_la_SOURCES += ps2_kces.c
libmeta_la_SOURCES += ps2_dxh.c
libmeta_la_SOURCES += ps2_psh.c
libmeta_la_SOURCES += mus_acm.c
libmeta_la_SOURCES += sli.c
libmeta_la_SOURCES += sfl.c
libmeta_la_SOURCES += pcm.c
libmeta_la_SOURCES += ps2_psw.c
libmeta_la_SOURCES += rkv.c
libmeta_la_SOURCES += ps2_vas.c
libmeta_la_SOURCES += ps2_tec.c
libmeta_la_SOURCES += ps2_enth.c
libmeta_la_SOURCES += sdt.c
libmeta_la_SOURCES += aix.c
libmeta_la_SOURCES += ngc_tydsp.c
libmeta_la_SOURCES += wvs.c
libmeta_la_SOURCES += xbox_stma.c
libmeta_la_SOURCES += xbox_ims.c
libmeta_la_SOURCES += de2.c
libmeta_la_SOURCES += dc_str.c
libmeta_la_SOURCES += xbox_xmu.c
libmeta_la_SOURCES += ngc_bh2pcm.c
libmeta_la_SOURCES += sat_sap.c
libmeta_la_SOURCES += dc_idvi.c
libmeta_la_SOURCES += ps2_rnd.c
libmeta_la_SOURCES += xbox_xvas.c
libmeta_la_SOURCES += kraw.c
libmeta_la_SOURCES += ps2_xa2.c
libmeta_la_SOURCES += idsp.c
libmeta_la_SOURCES += ngc_ymf.c
libmeta_la_SOURCES += nds_sad.c
libmeta_la_SOURCES += ps2_ccc.c
libmeta_la_SOURCES += psx_fag.c
libmeta_la_SOURCES += ps2_mihb.c
libmeta_la_SOURCES += ngc_pdt.c
libmeta_la_SOURCES += wii_mus.c
libmeta_la_SOURCES += dc_asd.c
libmeta_la_SOURCES += naomi_spsd.c
libmeta_la_SOURCES += bgw.c
libmeta_la_SOURCES += ps2_ass.c
libmeta_la_SOURCES += ngc_waa_wac_wad_wam.c
libmeta_la_SOURCES += seg.c
libmeta_la_SOURCES += str_asr.c
libmeta_la_SOURCES += zwdsp.c
libmeta_la_SOURCES += gca.c
libmeta_la_SOURCES += ish_isd.c
libmeta_la_SOURCES += spt_spd.c
libmeta_la_SOURCES += ydsp.c
libmeta_la_SOURCES += gsp_gsb.c
libmeta_la_SOURCES += ngc_ssm.c
libmeta_la_SOURCES += msvp.c
libmeta_la_SOURCES += ps2_joe.c
libmeta_la_SOURCES += vs.c
libmeta_la_SOURCES += vgs.c
libmeta_la_SOURCES += dc_dcsw_dcs.c
libmeta_la_SOURCES += wii_smp.c
libmeta_la_SOURCES += ss_stream.c
libmeta_la_SOURCES += emff.c
libmeta_la_SOURCES += thp.c
libmeta_la_SOURCES += wii_sts.c
libmeta_la_SOURCES += capdsp.c
libmeta_la_SOURCES += wii_sng.c
libmeta_la_SOURCES += aax.c
libmeta_la_SOURCES += ps2_p2bt.c
libmeta_la_SOURCES += ps2_gbts.c
libmeta_la_SOURCES += ngc_ffcc_str.c
libmeta_la_SOURCES += sat_baka.c
libmeta_la_SOURCES += nds_swav.c
libmeta_la_SOURCES += vsf.c
libmeta_la_SOURCES += nds_rrds.c
libmeta_la_SOURCES += ps2_tk5.c
libmeta_la_SOURCES += ads.c
libmeta_la_SOURCES += wii_str.c
libmeta_la_SOURCES += zsd.c
libmeta_la_SOURCES += ps2_mcg.c
libmeta_la_SOURCES += redspark.c
libmeta_la_SOURCES += ivaud.c
libmeta_la_SOURCES += ps2_vgs.c
libmeta_la_SOURCES += ps2_sps.c
libmeta_la_SOURCES += nds_hwas.c
libmeta_la_SOURCES += ngc_lps.c
libmeta_la_SOURCES += ps2_snd.c
libmeta_la_SOURCES += naomi_adpcm.c
libmeta_la_SOURCES += sd9.c
libmeta_la_SOURCES += 2dx9.c
libmeta_la_SOURCES += ngc_dsp_ygo.c
libmeta_la_SOURCES += ps2_vgv.c
libmeta_la_SOURCES += ngc_gcub.c
libmeta_la_SOURCES += maxis_xa.c
libmeta_la_SOURCES += ngc_sck_dsp.c
libmeta_la_SOURCES += apple_caff.c
libmeta_la_SOURCES += pc_mxst.c
libmeta_la_SOURCES += pc_sob.c
libmeta_la_SOURCES += exakt_sc.c
libmeta_la_SOURCES += wii_bns.c
libmeta_la_SOURCES += pona.c
libmeta_la_SOURCES += xbox_hlwav.c
libmeta_la_SOURCES += stx.c
libmeta_la_SOURCES += ps2_stm.c
libmeta_la_SOURCES += myspd.c
libmeta_la_SOURCES += his.c
libmeta_la_SOURCES += ps2_ast.c
libmeta_la_SOURCES += dmsg_segh.c
libmeta_la_SOURCES += ngc_dsp_konami.c
libmeta_la_SOURCES += ps2_ster.c
libmeta_la_SOURCES += bnsf.c
libmeta_la_SOURCES += ps2_wb.c
libmeta_la_SOURCES += s14_sss.c
libmeta_la_SOURCES += ps2_gcm.c
libmeta_la_SOURCES += ps2_smpl.c
libmeta_la_SOURCES += ps2_msa.c
libmeta_la_SOURCES += pc_smp.c
libmeta_la_SOURCES += p3d.c
libmeta_la_SOURCES += ps2_adsc.c
libmeta_la_SOURCES += psx_str_mgav.c
libmeta_la_SOURCES += ngc_bo2.c
libmeta_la_SOURCES += ngc_dsp_mpds.c
libmeta_la_SOURCES += ps2_khv.c
libmeta_la_SOURCES += ps2_voi.c
libmeta_la_SOURCES += dsp_sth_str.c
libmeta_la_SOURCES += ps2_b1s.c
libmeta_la_SOURCES += ps2_wad.c
libmeta_la_SOURCES += ps2_lpcm.c
libmeta_la_SOURCES += ps2_adm.c
libmeta_la_SOURCES += dsp_bdsp.c
libmeta_la_SOURCES += ps2_vms.c
libmeta_la_SOURCES += ps2_xau.c
libmeta_la_SOURCES += gh3_bar.c
libmeta_la_SOURCES += ffw.c
libmeta_la_SOURCES += ps2_jstm.c
libmeta_la_SOURCES += ps3_xvag.c
libmeta_la_SOURCES += ps3_cps.c
libmeta_la_SOURCES += sqex_scd.c
libmeta_la_SOURCES += ngc_nst_dsp.c
libmeta_la_SOURCES += baf.c
libmeta_la_SOURCES += ps3_msf.c
libmeta_la_SOURCES += nub_vag.c
libmeta_la_SOURCES += ps3_past.c
libmeta_la_SOURCES += sgxd.c
libmeta_la_SOURCES += ngca.c
libmeta_la_SOURCES += wii_ras.c
libmeta_la_SOURCES += ps2_spm.c
libmeta_la_SOURCES += x360_tra.c
libmeta_la_SOURCES += ps2_iab.c
libmeta_la_SOURCES += ps2_strlr.c
libmeta_la_SOURCES += lsf.c
libmeta_la_SOURCES += vawx.c
libmeta_la_SOURCES += pc_snds.c
libmeta_la_SOURCES += ps2_wmus.c
libmeta_la_SOURCES += mattel_hyperscan.c
libmeta_la_SOURCES += ios_psnd.c
libmeta_la_SOURCES += pc_adp.c
libmeta_la_SOURCES += excitebots.c
libmeta_la_SOURCES += ps2_mtaf.c
libmeta_la_SOURCES += ps3_klbs.c
libmeta_la_SOURCES += tun.c
libmeta_la_SOURCES += wpd.c
libmeta_la_SOURCES += mn_str.c
libmeta_la_SOURCES += ps2_mss.c
libmeta_la_SOURCES += ps2_hsf.c
libmeta_la_SOURCES += ps3_ivag.c
libmeta_la_SOURCES += ps2_2pfs.c
libmeta_la_SOURCES += ubi_ckd.c
libmeta_la_SOURCES += otm.c
libmeta_la_SOURCES += bcstm.c
libmeta_la_SOURCES += bfwav.c
libmeta_la_SOURCES += bfstm.c
libmeta_la_SOURCES += g1l.c
libmeta_la_SOURCES += ps2_vbk.c
libmeta_la_SOURCES += mca.c
libmeta_la_SOURCES += btsnd.c
libmeta_la_SOURCES += hca.c
libmeta_la_SOURCES += ps2_svag_snk.c
libmeta_la_SOURCES += mp4.c
libmeta_la_SOURCES += xma.c
libmeta_la_SOURCES += ps2_vds_vdm.c
libmeta_la_SOURCES += x360_cxs.c
libmeta_la_SOURCES += dsp_adx.c
libmeta_la_SOURCES += bik.c
libmeta_la_SOURCES += akb.c
libmeta_la_SOURCES += x360_ast.c
libmeta_la_SOURCES += wwise.c
libmeta_la_SOURCES += ubi_raki.c
libmeta_la_SOURCES += x360_pasx.c
libmeta_la_SOURCES += x360_nub.c
libmeta_la_SOURCES += sxd.c
libmeta_la_SOURCES += ogl.c
EXTRA_DIST = meta.h

View File

@ -11,138 +11,146 @@
static int find_key(STREAMFILE *file, uint8_t type, uint16_t *xor_start, uint16_t *xor_mult, uint16_t *xor_add);
/* ADX - CRI Middleware format */
VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t stream_offset;
off_t start_offset, hist_offset = 0;
int loop_flag = 0, channel_count;
int32_t loop_start_sample = 0, loop_end_sample = 0;
uint16_t version_signature;
int loop_flag=0;
int channel_count;
int32_t loop_start_sample=0;
int32_t loop_end_sample=0;
meta_t header_type;
coding_t coding_type = coding_CRI_ADX;
int16_t coef1, coef2;
uint16_t cutoff;
char filename[PATH_LIMIT];
int coding_type = coding_CRI_ADX;
uint16_t xor_start=0,xor_mult=0,xor_add=0;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("adx",filename_extension(filename))) goto fail;
if (!check_extensions(streamFile,"adx")) goto fail;
/* check first 2 bytes */
if ((uint16_t)read_16bitBE(0,streamFile)!=0x8000) goto fail;
if ((uint16_t)read_16bitBE(0x00,streamFile)!=0x8000) goto fail;
/* get stream offset, check for CRI signature just before */
stream_offset = (uint16_t)read_16bitBE(2,streamFile) + 4;
if ((uint16_t)read_16bitBE(stream_offset-6,streamFile)!=0x2863 ||/* "(c" */
(uint32_t)read_32bitBE(stream_offset-4,streamFile)!=0x29435249 /* ")CRI" */
start_offset = (uint16_t)read_16bitBE(0x02,streamFile) + 4;
if ((uint16_t)read_16bitBE(start_offset-6,streamFile)!=0x2863 || /* "(c" */
(uint32_t)read_32bitBE(start_offset-4,streamFile)!=0x29435249 /* ")CRI" */
) goto fail;
/* check for encoding type */
/* 2 is for some unknown fixed filter, 3 is standard ADX, 4 is
* ADX with exponential scale, 0x11 is AHX */
if (read_8bit(4,streamFile) != 3) goto fail;
/* 0x02 is for some unknown fixed filter, 0x03 is standard ADX, 0x04 is
* ADX with exponential scale, 0x10 is AHX for DC, 0x11 is AHX */
if (read_8bit(0x04,streamFile) != 3) goto fail;
/* check for frame size (only 18 is supported at the moment) */
if (read_8bit(5,streamFile) != 18) goto fail;
if (read_8bit(0x05,streamFile) != 18) goto fail;
/* check for bits per sample? (only 4 makes sense for ADX) */
if (read_8bit(6,streamFile) != 4) goto fail;
if (read_8bit(0x06,streamFile) != 4) goto fail;
/* older ADX (adxencd) up to 2ch, newer ADX (criatomencd) up to 8 */
channel_count = read_8bit(0x07,streamFile);
/* check version signature, read loop info */
version_signature = read_16bitBE(0x12,streamFile);
/* encryption */
if (version_signature == 0x0408) {
if (find_key(streamFile, 8, &xor_start, &xor_mult, &xor_add))
{
if (find_key(streamFile, 8, &xor_start, &xor_mult, &xor_add)) {
coding_type = coding_CRI_ADX_enc_8;
version_signature = 0x0400;
}
}
else if (version_signature == 0x0409) {
if (find_key(streamFile, 9, &xor_start, &xor_mult, &xor_add))
{
if (find_key(streamFile, 9, &xor_start, &xor_mult, &xor_add)) {
coding_type = coding_CRI_ADX_enc_9;
version_signature = 0x0400;
}
}
if (version_signature == 0x0300) { /* type 03 */
/* version + extra data */
if (version_signature == 0x0300) { /* early ADX (~2004?) */
size_t base_size = 0x14, loops_size = 0x18;
header_type = meta_ADX_03;
if (stream_offset-6 >= 0x2c) { /* enough space for loop info? */
loop_flag = (read_32bitBE(0x18,streamFile) != 0);
loop_start_sample = read_32bitBE(0x1c,streamFile);
//loop_start_offset = read_32bitBE(0x20,streamFile);
loop_end_sample = read_32bitBE(0x24,streamFile);
//loop_end_offset = read_32bitBE(0x28,streamFile);
/* no sample history */
if (start_offset - 6 >= base_size + loops_size) { /* enough space for loop info? */
off_t loops_offset = base_size;
/* off+0x00 (2): initial loop padding (the encoder adds a few blank samples so loop start is block-aligned; max 31)
* ex. loop_start=12: enc_start=32, padding=20 (32-20=12); loop_start=35: enc_start=64, padding=29 (64-29=35)
* off+0x02 (2): loop sample(?) flag (always 1) */
loop_flag = read_32bitBE(loops_offset+0x04,streamFile) != 0; /* loop offset(?) flag (always 1) */
loop_start_sample = read_32bitBE(loops_offset+0x08,streamFile);
//loop_start_offset = read_32bitBE(loops_offset+0x0c,streamFile);
loop_end_sample = read_32bitBE(loops_offset+0x10,streamFile);
//loop_end_offset = read_32bitBE(loops_offset+0x14,streamFile);
}
} else if (version_signature == 0x0400) {
off_t ainf_info_length=0;
if((uint32_t)read_32bitBE(0x24,streamFile)==0x41494E46) /* AINF Header */
ainf_info_length = (off_t)read_32bitBE(0x28,streamFile);
}
else if (version_signature == 0x0400) { /* common */
size_t base_size = 0x18, hist_size, ainf_size = 0, loops_size = 0x18;
off_t ainf_offset;
header_type = meta_ADX_04;
if (stream_offset-ainf_info_length-6 >= 0x38) { /* enough space for loop info? */
if (read_32bitBE(0x24,streamFile) == 0xFFFEFFFE)
loop_flag = 0;
else
loop_flag = (read_32bitBE(0x24,streamFile) != 0);
loop_start_sample = read_32bitBE(0x28,streamFile);
//loop_start_offset = read_32bitBE(0x2c,streamFile);
loop_end_sample = read_32bitBE(0x30,streamFile);
//loop_end_offset = read_32bitBE(0x34,streamFile);
hist_offset = base_size; /* always present but often blank */
hist_size = (channel_count > 1 ? 4*channel_count : 4+4); /* min is 8, even in 1ch files */
ainf_offset = base_size + hist_size + 0x4; /* not seen with >2ch though */
if ((uint32_t)read_32bitBE(ainf_offset+0x00,streamFile) == 0x41494E46) /* "AINF" */
ainf_size = read_32bitBE(ainf_offset+0x04,streamFile);
if (start_offset - ainf_size - 6 >= hist_offset + hist_size + loops_size) { /* enough space for loop info? */
off_t loops_offset = base_size + hist_size;
/* off+0x00 (2): initial loop padding (the encoder adds a few blank samples so loop start is block-aligned; max 31)
* ex. loop_start=12: enc_start=32, padding=20 (32-20=12); loop_start=35: enc_start=64, padding=29 (64-29=35)
* off+0x02 (2): loop sample(?) flag (always 1) */
loop_flag = read_32bitBE(loops_offset+0x04,streamFile) != 0; /* loop offset(?) flag (always 1) */
loop_start_sample = read_32bitBE(loops_offset+0x08,streamFile);
//loop_start_offset = read_32bitBE(loops_offset+0x0c,streamFile);
loop_end_sample = read_32bitBE(loops_offset+0x10,streamFile);
//loop_end_offset = read_32bitBE(loops_offset+0x14,streamFile);
}
/* AINF header can also start after the loop points
* (may be inserted by CRI's tools but is rarely used) */
/* ainf_magic = read_32bitBE(0x38,streamFile); */ /* 0x41494E46 */
/* ainf_length = read_32bitBE(0x3c,streamFile); */
/* ainf_str_id = read_string(0x40,streamFile); */ /* max size 0x10 */
/* ainf_volume = read_16bitBE(0x50,streamFile); */ /* 0=base/max?, negative=reduce */
/* ainf_pan_l = read_16bitBE(0x54,streamFile); */ /* 0=base, max +-128 */
/* ainf_pan_r = read_16bitBE(0x56,streamFile); */
} else if (version_signature == 0x0500) { /* found in some SFD : Buggy Heat, appears to have no loop */
/* AINF header info (may be inserted by CRI's tools but is rarely used)
* Can also start right after the loop points (base_size + hist_size + loops_size)
* 0x00 (4): "AINF"; 0x04 (4): size; 0x08 (10): str_id
* 0x18 (2): volume (0=base/max?, negative=reduce)
* 0x1c (2): pan l; 0x1e (2): pan r (0=base, max +-128) */
}
else if (version_signature == 0x0500) { /* found in some SFD: Buggy Heat, appears to have no loop */
header_type = meta_ADX_05;
} else goto fail; /* not a known/supported version signature */
/* At this point we almost certainly have an ADX file,
* so let's build the VGMSTREAM. */
/* high-pass cutoff frequency, always 500 that I've seen */
cutoff = (uint16_t)read_16bitBE(0x10,streamFile);
if (loop_start_sample == 0 && loop_end_sample == 0) {
loop_flag = 0;
}
else { /* not a known/supported version signature */
goto fail;
}
channel_count = read_8bit(7,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->num_samples = read_32bitBE(0xc,streamFile);
vgmstream->sample_rate = read_32bitBE(8,streamFile);
/* channels and loop flag are set by allocate_vgmstream */
vgmstream->sample_rate = read_32bitBE(0x8,streamFile);
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->coding_type = coding_type;
if (channel_count==1)
vgmstream->layout_type = layout_none;
else
vgmstream->layout_type = layout_interleave;
vgmstream->layout_type = channel_count==1 ? layout_none : layout_interleave;
vgmstream->interleave_block_size = 18;
vgmstream->meta_type = header_type;
vgmstream->interleave_block_size=18;
/* calculate filter coefficients */
{
double x,y,z,a,b,c;
/* high-pass cutoff frequency, always 500 that I've seen */
uint16_t cutoff = (uint16_t)read_16bitBE(0x10,streamFile);
x = cutoff;
y = vgmstream->sample_rate;
@ -156,27 +164,22 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
coef2 = floor(c*c*-4096);
}
/* init decoder */
{
int i;
STREAMFILE * chstreamfile;
/* ADX is so tightly interleaved that having two buffers is silly */
chstreamfile = streamFile->open(streamFile,filename,18*0x400);
if (!chstreamfile) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = chstreamfile;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=
stream_offset+18*i;
vgmstream->ch[i].adpcm_coef[0] = coef1;
vgmstream->ch[i].adpcm_coef[1] = coef2;
if (coding_type == coding_CRI_ADX_enc_8 ||
coding_type == coding_CRI_ADX_enc_9)
{
/* 2 hist shorts per ch, corresponding to the very first original sample repeated (verified with CRI's encoders).
* Not vital as their effect is small, after a few samples they don't matter, and most songs start in silence. */
if (hist_offset) {
vgmstream->ch[i].adpcm_history1_32 = read_16bitBE(hist_offset + i*4 + 0x00,streamFile);
vgmstream->ch[i].adpcm_history2_32 = read_16bitBE(hist_offset + i*4 + 0x02,streamFile);
}
if (coding_type == coding_CRI_ADX_enc_8 || coding_type == coding_CRI_ADX_enc_9) {
int j;
vgmstream->ch[i].adx_channels = channel_count;
vgmstream->ch[i].adx_xor = xor_start;
@ -189,11 +192,13 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
}
}
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
goto fail;
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}
@ -426,7 +431,7 @@ static struct {
};
/* type 9 keys */
/* type 9 keys (may not be autodetected correctly) */
static struct {
uint16_t start,mult,add;
} keys_9[] = {
@ -442,6 +447,10 @@ static struct {
* guessed with degod */
{0x0005,0x0bcd,0x1add},
/* Raramagi [Android]
* found in 2ch */
{0x0000,0x0b99,0x1e33},
};
static const int keys_8_count = sizeof(keys_8)/sizeof(keys_8[0]);

View File

@ -138,6 +138,7 @@ VGMSTREAM * init_vgmstream_akb2_multi(STREAMFILE *streamFile) {
off_t start_offset, header_offset;
size_t datasize;
int loop_flag = 0, channel_count, codec;
int akb_header_size, sound_index = 0, sound_offset_data, sound, sound_header_size, material_offset_data, material_index = 0, material, extradata, encryption_flag;
/* check extensions */
if ( !check_extensions(streamFile, "akb") )
@ -147,10 +148,17 @@ VGMSTREAM * init_vgmstream_akb2_multi(STREAMFILE *streamFile) {
if (read_32bitBE(0x00,streamFile) != 0x414B4232) /* "AKB2" */
goto fail;
/* this is weird (BE?) but seems to work */
start_offset = (uint16_t)read_16bitBE(0x21,streamFile);
header_offset = start_offset - 0x50;
if (header_offset < 0x30) goto fail;
akb_header_size = read_16bitLE(0x06, streamFile);
sound_offset_data = akb_header_size + sound_index * 0x10;
sound = read_32bitLE(sound_offset_data + 0x04, streamFile);
sound_header_size = read_16bitLE(sound + 0x02, streamFile);
material_offset_data = sound + sound_header_size + material_index * 0x10;
material = sound + read_32bitLE(material_offset_data + 0x04, streamFile);
encryption_flag = read_8bit(material + 0x03, streamFile) & 0x08;
extradata = material + read_16bitLE(material + 0x04, streamFile);
start_offset = material + read_16bitLE(material + 0x04, streamFile) + read_32bitLE(material + 0x18, streamFile);
header_offset = material;
channel_count = read_8bit(header_offset+0x02,streamFile);
loop_flag = read_32bitLE(header_offset+0x14,streamFile) > 0;
@ -172,6 +180,15 @@ VGMSTREAM * init_vgmstream_akb2_multi(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_AKB;
switch (codec) {
case 0x02: { /* msadpcm [The Irregular at Magic High School Lost Zero (Android)] */
if (encryption_flag) goto fail;
vgmstream->num_samples = read_32bitLE(extradata + 0x04, streamFile);
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = read_16bitLE(extradata + 0x02, streamFile);
break;
}
#ifdef VGM_USE_FFMPEG
case 0x05: { /* ogg vorbis [The World Ends with You (iPhone / latest update)] */
ffmpeg_codec_data *ffmpeg_data;

View File

@ -82,9 +82,9 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
uint8_t buf[100];
int32_t bytes, block_size, encoder_delay, joint_stereo, max_samples;
block_size = 0x98 * vgmstream->channels;
joint_stereo = 0;
max_samples = (datasize / block_size) * 1024;
block_size = 0x98 * vgmstream->channels;
joint_stereo = 0;
max_samples = atrac3_bytes_to_samples(datasize, block_size);;
encoder_delay = max_samples - vgmstream->num_samples; /* todo guessed */
vgmstream->num_samples += encoder_delay;
@ -113,7 +113,7 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
if (!find_chunk_be(streamFileGSP, 0x584D4558,first_offset,1, &chunk_offset,NULL)) goto fail; /*"XMEX"*/
/* 0x00: fmt0x166 header (BE), 0x34: seek table */
bytes = ffmpeg_make_riff_xma_from_fmt(buf,200, chunk_offset,0x34, datasize, streamFileGSP, 1);
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, chunk_offset,0x34, datasize, streamFileGSP, 1);
if (bytes <= 0) goto fail;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,datasize);

View File

@ -656,9 +656,9 @@ VGMSTREAM * init_vgmstream_btsnd(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_svag_snk(STREAMFILE* streamFile);
#ifdef VGM_USE_FFMPEG
VGMSTREAM * init_vgmstream_xma(STREAMFILE* streamFile);
#ifdef VGM_USE_FFMPEG
VGMSTREAM * init_vgmstream_bik(STREAMFILE* streamFile);
#endif
@ -676,4 +676,14 @@ VGMSTREAM * init_vgmstream_x360_ast(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_x360_nub(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_x360_pasx(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ogl(STREAMFILE *streamFile);
#endif /*_META_H*/

View File

@ -0,0 +1,68 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
/* OGL - Shin'en custom Vorbis [Jett Rocket (Wii), FAST Racing NEO (WiiU)] */
VGMSTREAM * init_vgmstream_ogl(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
size_t partial_file_size;
int loop_flag, channel_count, sample_rate;
uint32_t num_samples, loop_start_sample, loop_end_sample;
/* check extension, case insensitive */
if (!check_extensions(streamFile,"ogl"))
goto fail;
/* OGL headers are very basic with no ID but libvorbis should reject garbage data anyway */
loop_flag = read_32bitLE(0x00,streamFile) > 0; /* absolute loop offset */
loop_start_sample = read_32bitLE(0x04,streamFile);
//loop_start_block = read_32bitLE(0x08,streamFile);
num_samples = read_32bitLE(0x0c,streamFile);
partial_file_size = read_32bitLE(0x10,streamFile); /* header + data not counting end padding */
if (partial_file_size > get_streamfile_size(streamFile)) goto fail;
loop_end_sample = num_samples; /* there is no data after num_samples (ie.- it's really num_samples) */
/* this is actually peeking into the Vorbis id packet */
channel_count = read_8bit (0x21,streamFile);
sample_rate = read_32bitLE(0x22,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->meta_type = meta_OGL;
#ifdef VGM_USE_VORBIS
{
vgmstream->codec_data = init_ogl_vorbis_codec_data(streamFile, 0x14, &start_offset);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_ogl_vorbis;
vgmstream->layout_type = layout_none;
}
#else
goto fail;
#endif
/* non-looping files do this */
if (!num_samples) {
uint32_t avg_bitrate = read_32bitLE(0x2a,streamFile); /* inside id packet */
/* approximate as we don't know the sizes of all packet headers */ //todo this is wrong... but somehow works?
vgmstream->num_samples = (partial_file_size - start_offset) * ((sample_rate*10/avg_bitrate)+1);
}
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -104,12 +104,12 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
case 0x6: { /* ATRAC3 high (132 kbps, frame size 192) */
ffmpeg_codec_data *ffmpeg_data = NULL;
uint8_t buf[100];
int32_t bytes, samples_size = 1024, block_size, encoder_delay, joint_stereo, max_samples;
int32_t bytes, block_size, encoder_delay, joint_stereo, max_samples;
block_size = (codec_id==4 ? 0x60 : (codec_id==5 ? 0x98 : 0xC0)) * vgmstream->channels;
block_size = (codec_id==4 ? 0x60 : (codec_id==5 ? 0x98 : 0xC0)) * vgmstream->channels;
encoder_delay = 0x0; //todo MSF encoder delay (around 440-450*2)
max_samples = (data_size / block_size) * samples_size;
joint_stereo = codec_id==4; /* interleaved joint stereo (ch must be even) */
max_samples = atrac3_bytes_to_samples(data_size, block_size);
joint_stereo = codec_id==4; /* interleaved joint stereo (ch must be even) */
if (vgmstream->sample_rate==0xFFFFFFFF) /* some MSFv1 (Digi World SP) */
vgmstream->sample_rate = 44100;//voice tracks seems to use 44khz, not sure about other tracks
@ -126,8 +126,8 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
vgmstream->num_samples = max_samples;
if (loop_flag) {
vgmstream->loop_start_sample = (loop_start / block_size) * samples_size;
vgmstream->loop_end_sample = (loop_end / block_size) * samples_size;
vgmstream->loop_start_sample = atrac3_bytes_to_samples(loop_start, block_size);
vgmstream->loop_end_sample = atrac3_bytes_to_samples(loop_end, block_size);
}
break;

View File

@ -227,8 +227,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
uint32_t riff_size;
uint32_t data_size = 0;
int FormatChunkFound = 0;
int DataChunkFound = 0;
int FormatChunkFound = 0, DataChunkFound = 0, JunkFound = 0;
/* Level-5 mwv */
int mwv = 0;
@ -361,6 +360,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
fact_sample_skip = read_32bitLE(current_chunk+0x10, streamFile);
}
break;
case 0x4A554E4B: /* JUNK */
JunkFound = 1;
break;
default:
/* ignorance is bliss */
@ -373,6 +375,12 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
if (!FormatChunkFound || !DataChunkFound) goto fail;
/* JUNK is an optional Wwise chunk, and Wwise hijacks the MSADPCM/MS_IMA/XBOX IMA ids (how nice).
* To ensure their stuff is parsed in wwise.c we reject their JUNK, which they put almost always.
* As JUNK is legal (if unusual) we only reject those codecs.
* (ex. Cave PC games have PCM16LE + JUNK + smpl created by "Samplitude software") */
if (JunkFound && (fmt.coding_type==coding_MSADPCM || fmt.coding_type==coding_MS_IMA)) goto fail;
switch (fmt.coding_type) {
case coding_PCM16LE:
sample_count = data_size/2/fmt.channel_count;
@ -611,8 +619,7 @@ VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
uint32_t riff_size;
uint32_t data_size = 0;
int FormatChunkFound = 0;
int DataChunkFound = 0;
int FormatChunkFound = 0, DataChunkFound = 0, JunkFound = 0;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
@ -687,6 +694,8 @@ VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
if (chunk_size != 4) break;
//fact_sample_count = read_32bitBE(current_chunk+8, streamFile);
break;
case 0x4A554E4B: /* JUNK */
JunkFound = 1;
default:
/* ignorance is bliss */
break;
@ -698,6 +707,12 @@ VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
if (!FormatChunkFound || !DataChunkFound) goto fail;
/* JUNK is an optional Wwise chunk, and Wwise hijacks the MSADPCM/MS_IMA/XBOX IMA ids (how nice).
* To ensure their stuff is parsed in wwise.c we reject their JUNK, which they put almost always.
* As JUNK is legal (if unusual) we only reject those codecs.
* (ex. Cave PC games have PCM16LE + JUNK + smpl created by "Samplitude software") */
if (JunkFound && (fmt.coding_type==coding_MSADPCM || fmt.coding_type==coding_MS_IMA)) goto fail;
switch (fmt.coding_type) {
case coding_PCM16BE:
sample_count = data_size/2/fmt.channel_count;

View File

@ -358,7 +358,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
/* post_meta_offset+0x00: fmt0x166 header (BE), post_meta_offset+0x34: seek table */
bytes = ffmpeg_make_riff_xma_from_fmt(buf,200, post_meta_offset,0x34, stream_size, streamFile, 1);
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, post_meta_offset,0x34, stream_size, streamFile, 1);
if (bytes <= 0) goto fail;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,stream_size);

View File

@ -0,0 +1,128 @@
#include "meta.h"
#include "../util.h"
/* SXD - Sony's SDK format? (cousin of SGXD) [Gravity Rush, Freedom Wars, Soul Sacrifice PSV] */
VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * streamHeader = NULL;
off_t start_offset, chunk_offset, first_offset = 0x60;
int is_separate;
int loop_flag, channels, type;
int sample_rate, num_samples, loop_start_sample, loop_end_sample;
int target_stream = 0, total_streams;
/* check extension, case insensitive */
/* .sxd: header+data (SXDF), .sxd1: header (SXDF) + .sxd2 = data (SXDS) */
if (!check_extensions(streamFile,"sxd,sxd2")) goto fail;
is_separate = !check_extensions(streamFile,"sxd");
/* sxd1+sxd2: use sxd1 as header; otherwise use the current file as header */
if (is_separate) {
if (read_32bitBE(0x00,streamFile) != 0x53584453) /* "SXDS" */
goto fail;
streamHeader = open_stream_ext(streamFile, "sxd1");
if (!streamHeader) goto fail;
} else {
streamHeader = streamFile;
}
if (read_32bitBE(0x00,streamHeader) != 0x53584446) /* "SXDF" */
goto fail;
/* typical chunks: NAME, WAVE and many control chunks (SXDs don't need to contain any sound data) */
/* WAVE chunk (0 + streams + 4*streams table + streams * variable? + optional padding) */
if (!find_chunk_le(streamHeader, 0x57415645,first_offset,0, &chunk_offset,NULL)) goto fail; /* "WAVE" */
/* check multi-streams (usually only in SFX containers) */
total_streams = read_32bitLE(chunk_offset+0x04,streamHeader);
if (target_stream == 0) target_stream = 1;
if (target_stream < 0 || target_stream > total_streams || total_streams < 1) goto fail;
/* read stream header */
{
off_t table_offset, header_offset, stream_offset, data_offset;
int i;
/* get target offset using table of relative offsets within WAVE */
table_offset = chunk_offset + 0x08 + 4*(target_stream-1);
header_offset = table_offset + read_32bitLE(table_offset,streamHeader);
type = read_32bitLE(header_offset+0x00,streamHeader);
/* 0x04 (1): unk (HEVAG: 21, ATRAC9: 42 */
channels = read_8bit (header_offset+0x05,streamHeader);
sample_rate = read_32bitLE(header_offset+0x08,streamHeader);
/* 0x0c (4): unk size? */
/* 0x10 (4): ? + volume? + pan? (can be 0 for music) */
num_samples = read_32bitLE(header_offset+0x14,streamHeader);
loop_start_sample = read_32bitLE(header_offset+0x18,streamHeader);
loop_end_sample = read_32bitLE(header_offset+0x1c,streamHeader);
/* 0x20 (4): data size */
/* 0x24 (-): extra data, variable size and format dependant
(ATRAC9 can contain truncated part of the data, for preloading I guess) */
loop_flag = loop_start_sample != -1 && loop_end_sample != -1;
/* calc stream offset by reading stream sizes */
stream_offset = 0;
for (i = 0; i < total_streams; i++) {
off_t subtable_offset, subheader_offset;
if (i == target_stream-1) break;
subtable_offset = chunk_offset + 0x08 + 4*(i);
subheader_offset = subtable_offset + read_32bitLE(subtable_offset,streamHeader);
stream_offset += read_32bitLE(subheader_offset+0x20,streamHeader); /* data size */
}
if (is_separate) {
data_offset = first_offset;
} else {
if (!find_chunk_le(streamHeader, 0x44415441,first_offset,0, &data_offset,NULL)) goto fail; /* "DATA" */
data_offset += 0x08;
}
start_offset = data_offset + stream_offset;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->num_streams = total_streams;
vgmstream->meta_type = meta_SXD;
switch (type) {
case 0x01: /* HEVAG */
vgmstream->coding_type = coding_HEVAG;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
break;
case 0x03: /* ATRAC9 */
goto fail;
default:
VGM_LOG("SXD: unknown codec %i", type);
goto fail;
}
/* open the file for reading */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
if (is_separate && streamHeader) close_streamfile(streamHeader);
return vgmstream;
fail:
if (is_separate && streamHeader) close_streamfile(streamHeader);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,20 +1,17 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
#include "../util.h"
/* Ubisoft CKD (Rayman Origins - Wii) */
/* CKD RIFF - Ubisoft audio [Rayman Origins (Wii)] */
VGMSTREAM * init_vgmstream_ubi_ckd(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
off_t start_offset, first_offset = 0xc, chunk_offset;
size_t chunk_size, data_size;
int loop_flag, channel_count, interleave;
int loop_flag;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("ckd",filename_extension(filename))) goto fail;
if (!check_extensions(streamFile,"ckd")) goto fail;
/* check header */
if (read_32bitBE(0x0,streamFile) != 0x52494646) /* RIFF */
@ -25,61 +22,43 @@ VGMSTREAM * init_vgmstream_ubi_ckd(STREAMFILE *streamFile) {
loop_flag = 0;
channel_count = read_16bitBE(0x16,streamFile);
/* build the VGMSTREAM */
/* find data chunk, in 3 variants */
if (find_chunk_be(streamFile, 0x64617453,first_offset,0, &chunk_offset,&chunk_size)) { /*"datS"*/
/* normal interleave */
start_offset = chunk_offset;
data_size = chunk_size;
interleave = 8;
} else if (find_chunk_be(streamFile, 0x6461744C,first_offset,0, &chunk_offset,&chunk_size)) { /*"datL"*/
/* mono or full interleave (with a "datR" after the "datL", no check as we can just pretend it exists) */
start_offset = chunk_offset;
data_size = chunk_size * channel_count;
interleave = (4+4) + chunk_size; /* don't forget to skip the "datR"+size chunk */
} else {
goto fail;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
if (read_16bitBE(0x16,streamFile) == 1) {
start_offset = 0x96;
vgmstream->num_samples = (read_32bitBE(0x92,streamFile))*28/16/channel_count;
}
else {
start_offset = 0xFE;
vgmstream->num_samples = (read_32bitBE(0xFA,streamFile))*28/16/channel_count;
}
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x18,streamFile);
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->num_samples = (read_32bitBE(0xFA,streamFile))*28/16/channel_count;
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 8;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = channel_count==1 ? layout_none : layout_interleave;
vgmstream->interleave_block_size = interleave;
vgmstream->meta_type = meta_UBI_CKD;
if (vgmstream->coding_type == coding_NGC_DSP) {
int i;
for (i=0;i<16;i++) {
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x4A+i*2,streamFile);
}
if (vgmstream->channels) {
for (i=0;i<16;i++) {
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0xB2+i*2,streamFile);
}
}
}
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
dsp_read_coefs_be(vgmstream,streamFile, 0x4A, (4+4)+0x60);
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
/* clean up anything we may have opened */
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -0,0 +1,172 @@
#include "meta.h"
#include "../coding/coding.h"
/* RAKI - Ubisoft audio format [Rayman Legends, Just Dance 2017 (multi)] */
VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, off, fmt_offset;
size_t header_size, data_size;
int little_endian;
int loop_flag, channel_count, block_align, bits_per_sample;
uint32_t platform, type;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
/* basic checks */
/* .rak: Just Dance 2017; .ckd: Rayman Legends (technically .wav.ckd/rak) */
if (!check_extensions(streamFile,"rak,ckd")) goto fail;
/* some games (ex. Rayman Legends PS3) have a 32b file type before the RAKI data. However
* offsets are absolute and expect the type exists, so it's part of the file and not an extraction defect. */
if ((read_32bitBE(0x00,streamFile) == 0x52414B49)) /* "RAKI" */
off = 0x0;
else if ((read_32bitBE(0x04,streamFile) == 0x52414B49)) /* type varies between platforms (0x09, 0x0b) so ignore */
off = 0x4;
else
goto fail;
/* endianness is given with the platform field, but this is more versatile */
little_endian = read_32bitBE(off+0x10,streamFile) > 0x00ffffff;
if (little_endian) {
read_32bit = read_32bitLE;
read_16bit = read_16bitLE;
} else {
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
}
/* 0x04: version? (0x00, 0x07, 0x0a, etc); */
platform = read_32bitBE(off+0x08,streamFile); /* string */
type = read_32bitBE(off+0x0c,streamFile); /* string */
header_size = read_32bit(off+0x10,streamFile);
start_offset = read_32bit(off+0x14,streamFile);
/* 0x18: number of chunks */
/* 0x1c: unk */
/* The first chunk is always "fmt" and points to a RIFF "fmt" chunk (even for WiiU or PS3) */
if (read_32bitBE(off+0x20,streamFile) != 0x666D7420) goto fail; /*"fmt "*/
fmt_offset = read_32bit(off+0x24,streamFile);
//fmt_size = read_32bit(off+0x28,streamFile);
loop_flag = 0; /* not seen */
channel_count = read_16bit(fmt_offset+0x2,streamFile);
block_align = read_16bit(fmt_offset+0xc,streamFile);
bits_per_sample = read_16bit(fmt_offset+0xe,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bit(fmt_offset+0x4,streamFile);
vgmstream->meta_type = meta_UBI_RAKI;
/* codecs have a "data" or equivalent chunk with the size/start_offset, but always agree with this */
data_size = get_streamfile_size(streamFile) - start_offset;
/* parse compound codec to simplify */
switch(((uint64_t)platform << 32) | type) {
case 0x57696E2070636D20: /* "Win pcm " */
/* chunks: "data" */
vgmstream->coding_type = little_endian ? coding_PCM16LE : coding_PCM16BE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = block_align;
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, bits_per_sample);
break;
case 0x57696E2061647063: /* "Win adpc" */
/* chunks: "data" */
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = block_align;
vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, vgmstream->interleave_block_size, channel_count);
break;
case 0x5769692061647063: /* "Wii adpc" */
case 0x4361666561647063: /* "Cafeadpc" (WiiU) */
/* chunks: "datS" (stereo), "datL" (mono or full interleave), "datR" (full interleave), "data" equivalents */
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = channel_count==1 ? layout_none : layout_interleave;
vgmstream->interleave_block_size = 8;
/* we need to know if the file uses "datL" and is full-interleave */
if (channel_count > 1) {
off_t chunk_off = off+ 0x20 + 0xc; /* after "fmt" */
while (chunk_off < header_size) {
if (read_32bitBE(chunk_off,streamFile) == 0x6461744C) { /*"datL" found */
size_t chunk_size = read_32bit(chunk_off+0x8,streamFile);
data_size = chunk_size * channel_count; /* to avoid counting the "datR" chunk */
vgmstream->interleave_block_size = (4+4) + chunk_size; /* don't forget to skip the "datR"+size chunk */
break;
}
chunk_off += 0xc;
}
/* not found? probably "datS" (regular stereo interleave) */
}
{
/* get coef offsets; could check "dspL" and "dspR" chunks after "fmt " better but whatevs (only "dspL" if mono) */
off_t dsp_coefs = read_32bitBE(off+0x30,streamFile); /* after "dspL"; spacing is consistent but could vary */
dsp_read_coefs(vgmstream,streamFile, dsp_coefs+0x1c, 0x60, !little_endian);
/* dsp_coefs + 0x00-0x1c: ? (special coefs or adpcm history?) */
}
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
break;
#ifdef VGM_USE_MPEG
case 0x505333206D703320: { /* "PS3 mp3 " */
/* chunks: "MARK" optional seek table), "STRG" (optional description), "Msf " ("data" equivalent) */
vgmstream->codec_data = init_mpeg_codec_data(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_mpeg;
vgmstream->num_samples = mpeg_bytes_to_samples(data_size, vgmstream->codec_data);
break;
}
#endif
#ifdef VGM_USE_FFMPEG
case 0x58333630786D6132: { /* "X360xma2" */
/* chunks: "seek" (XMA2 seek table), "data" */
uint8_t buf[100];
int bytes, block_count;
block_count = data_size / block_align + (data_size % block_align ? 1 : 0);
bytes = ffmpeg_make_riff_xma2(buf, 100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_align);
if (bytes <= 0) goto fail;
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
if ( !vgmstream->codec_data ) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = read_32bit(fmt_offset+0x18,streamFile);
break;
}
#endif
case 0x5649544161743920: /*"VITAat9 "*/
/* chunks: "fact" (equivalent to a RIFF "fact", num_samples + skip_samples), "data" */
goto fail;
default:
VGM_LOG("RAKI: unknown platform %x and type %x\n", platform, type);
goto fail;
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -75,33 +75,30 @@ VGMSTREAM * init_vgmstream_vawx(STREAMFILE *streamFile) {
}
case 7: { /* ATRAC3 */
ffmpeg_codec_data *ffmpeg_data = NULL;
uint8_t buf[FAKE_RIFF_BUFFER_SIZE];
int32_t bytes, block_size, encoder_delay, joint_stereo, max_samples;
datasize = read_32bitBE(0x54,streamFile);
block_size = 0x98 * vgmstream->channels;
joint_stereo = 0;
max_samples = (datasize / block_size) * 1024;
encoder_delay = 0x0; /* not used by FFmpeg */
if (vgmstream->num_samples > max_samples) {
vgmstream->num_samples = max_samples;
/*encoder_delay = ?; */ /* todo some tracks need it to skip garbage but not sure how to calculate it */
}
max_samples = atrac3_bytes_to_samples(datasize, block_size);
encoder_delay = 0x0; //max_samples - vgmstream->num_samples; /* todo not correct */
vgmstream->num_samples = max_samples; /* use calc samples since loop points are too, breaks looping in some files otherwise */
/* make a fake riff so FFmpeg can parse the ATRAC3 */
bytes = ffmpeg_make_riff_atrac3(buf, FAKE_RIFF_BUFFER_SIZE, vgmstream->num_samples, datasize, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay);
if (bytes <= 0)
goto fail;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,datasize);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,datasize);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->loop_start_sample = (read_32bitBE(0x44,streamFile) / ffmpeg_data->blockAlign) * ffmpeg_data->frameSize;
vgmstream->loop_end_sample = (read_32bitBE(0x48,streamFile) / ffmpeg_data->blockAlign) * ffmpeg_data->frameSize;
vgmstream->loop_start_sample = atrac3_bytes_to_samples(read_32bitBE(0x44,streamFile), block_size);
vgmstream->loop_end_sample = atrac3_bytes_to_samples(read_32bitBE(0x48,streamFile), block_size);
//vgmstream->loop_start_sample -= encoder_delay;
//vgmstream->loop_end_sample -= encoder_delay;
break;
}

View File

@ -12,6 +12,7 @@ typedef enum { PCM, IMA, VORBIS, DSP, XMA2, XWMA, AAC, HEVAG, ATRAC9 } wwise_cod
typedef struct {
int big_endian;
size_t file_size;
int truncated;
/* chunks references */
off_t fmt_offset;
@ -25,13 +26,14 @@ typedef struct {
int channels;
int sample_rate;
int block_align;
int bit_per_sample;
int average_bps;
int bits_per_sample;
size_t extra_size;
int32_t num_samples;
int loop_flag;
uint32_t num_samples;
uint32_t loop_start_sample;
uint32_t loop_end_sample;
int32_t loop_start_sample;
int32_t loop_end_sample;
} wwise_header;
@ -45,13 +47,14 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
/* basic checks */
/* .wem (Wwise Encoded Media) is "newer Wwise", used after the 2011.2 SDK (~july)
* .wav (ex. Shadowrun X360) and .ogg (ex. KOF XII X360) are used only in older Wwise */
if (!check_extensions(streamFile,"wem,wav,lwav,ogg,logg")) goto fail; /* .xma may be possible? */
* .wav (ex. Shadowrun X360) and .ogg (ex. KOF XII X360), .xma (ex. Tron Evolution X360) are used in older Wwise */
if (!check_extensions(streamFile,"wem,wav,lwav,ogg,logg,xma")) goto fail;
if ((read_32bitBE(0x00,streamFile) != 0x52494646) && /* "RIFF" (LE) */
(read_32bitBE(0x00,streamFile) != 0x52494658)) /* "RIFX" (BE) */
goto fail;
if ((read_32bitBE(0x08,streamFile) != 0x57415645)) /* "WAVE" */
if ((read_32bitBE(0x08,streamFile) != 0x57415645) && /* "WAVE" */
(read_32bitBE(0x08,streamFile) != 0x58574D41)) /* "XWMA" */
goto fail;
memset(&ww,0,sizeof(wwise_header));
@ -68,7 +71,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
ww.file_size = streamFile->get_size(streamFile);
#if 0
/* sometimes uses a RIFF size that doesn't count chunk/sizes, or just wrong...? */
/* sometimes uses a RIFF size that doesn't count chunks/sizes, has LE size in RIFX, or is just wrong...? */
if (4+4+read_32bit(0x04,streamFile) != ww.file_size) {
VGM_LOG("WWISE: bad riff size (real=0x%x vs riff=0x%x)\n", 4+4+read_32bit(0x04,streamFile), ww.file_size);
goto fail;
@ -76,7 +79,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
#endif
/* parse WAVEFORMATEX (roughly spec-compliant but some massaging is needed) */
/* parse format (roughly spec-compliant but some massaging is needed) */
{
off_t loop_offset;
size_t loop_size;
@ -85,29 +88,32 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
if (!find_chunk(streamFile, 0x666d7420,first_offset,0, &ww.fmt_offset,&ww.fmt_size, ww.big_endian, 0)) goto fail; /*"fmt "*/
if (!find_chunk(streamFile, 0x64617461,first_offset,0, &ww.data_offset,&ww.data_size, ww.big_endian, 0)) goto fail; /*"data"*/
if (ww.data_size > ww.file_size) {
VGM_LOG("WWISE: bad data size (real=0x%x > riff=0x%x)\n", ww.data_size, ww.file_size);
goto fail;
}
/* base fmt */
if (ww.fmt_size < 0x12) goto fail;
ww.format = (uint16_t)read_16bit(ww.fmt_offset+0x00,streamFile);
ww.channels = read_16bit(ww.fmt_offset+0x02,streamFile);
ww.sample_rate = read_32bit(ww.fmt_offset+0x04,streamFile);
/* 0x08: average samples per second */
ww.block_align = (uint16_t)read_16bit(ww.fmt_offset+0x0c,streamFile);
ww.bit_per_sample = (uint16_t)read_16bit(ww.fmt_offset+0x0e,streamFile);
if (ww.fmt_size > 0x10 && ww.format != 0x0165 && ww.format != 0x0166) /* ignore XMAWAVEFORMAT */
ww.extra_size = (uint16_t)read_16bit(ww.fmt_offset+0x10,streamFile);
#if 0
/* channel bitmask, see AkSpeakerConfig.h (ex. 1ch uses FRONT_CENTER 0x4, 2ch FRONT_LEFT 0x1 | FRONT_RIGHT 0x2) */
if (ww.extra_size >= 6)
ww.channel_config = read_32bit(ww.fmt_offset+0x14,streamFile);
#endif
/* find loop info (both used in early and late Wwise and seem to follow the spec) */
if (find_chunk(streamFile, 0x736D706C,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"smpl"*/
if (ww.format == 0x0165) { /* XMA2WAVEFORMAT (always "fmt"+"XMA2", unlike .xma that may only have "XMA2") */
off_t xma2_offset;
if (!find_chunk(streamFile, 0x584D4132,first_offset,0, &xma2_offset,NULL, ww.big_endian, 0)) goto fail;
xma2_parse_xma2_chunk(streamFile, xma2_offset,&ww.channels,&ww.sample_rate, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample);
} else { /* WAVEFORMATEX */
ww.channels = read_16bit(ww.fmt_offset+0x02,streamFile);
ww.sample_rate = read_32bit(ww.fmt_offset+0x04,streamFile);
ww.average_bps = read_32bit(ww.fmt_offset+0x08,streamFile);/* bytes per sec */
ww.block_align = (uint16_t)read_16bit(ww.fmt_offset+0x0c,streamFile);
ww.bits_per_sample = (uint16_t)read_16bit(ww.fmt_offset+0x0e,streamFile);
if (ww.fmt_size > 0x10 && ww.format != 0x0165 && ww.format != 0x0166) /* ignore XMAWAVEFORMAT */
ww.extra_size = (uint16_t)read_16bit(ww.fmt_offset+0x10,streamFile);
/* channel bitmask, see AkSpeakerConfig.h (ex. 1ch uses FRONT_CENTER 0x4, 2ch FRONT_LEFT 0x1 | FRONT_RIGHT 0x2, etc) */
//if (ww.extra_size >= 6)
// ww.channel_config = read_32bit(ww.fmt_offset+0x14,streamFile);
}
/* find loop info */
if (ww.format == 0x0166) { /* XMA2WAVEFORMATEX */
xma2_parse_fmt_chunk_extra(streamFile, ww.fmt_offset, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample, ww.big_endian);
}
else if (find_chunk(streamFile, 0x736D706C,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"smpl". common */
if (loop_size >= 0x34
&& read_32bit(loop_offset+0x1c, streamFile)==1 /*loop count*/
&& read_32bit(loop_offset+0x24+4, streamFile)==0) {
@ -116,28 +122,31 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
ww.loop_end_sample = read_32bit(loop_offset+0x24+0xc,streamFile);
//todo fix repeat looping
}
} else if (find_chunk(streamFile, 0x4C495354,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"LIST"*/
}
else if (find_chunk(streamFile, 0x4C495354,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"LIST", common */
//todo parse "adtl" (does it ever contain loop info in Wwise?)
}
/* other Wwise specific: */
//"JUNK": optional padding so that raw data starts in an offset multiple of 0x10 (0-size JUNK exists)
//"JUNK": optional padding so that raw data starts in an offset multiple of 0x10 (0-size JUNK exists too)
//"akd ": unknown (IMA/PCM; "audiokinetic data"?)
}
/* format to codec */
switch(ww.format) {
case 0x0001: ww.codec = PCM; break; /* older Wwise */
case 0x0002: ww.codec = IMA; break; /* newer Wwise (conflicts with MSADPCM) */
case 0x0011: ww.codec = IMA; break; /* older Wwise */
case 0x0069: ww.codec = IMA; break; /* older Wwise */
case 0x0165: ww.codec = XMA2; break;
case 0x0002: ww.codec = IMA; break; /* newer Wwise (conflicts with MSADPCM, probably means "platform's ADPCM") */
//case 0x0011: ww.codec = IMA; break; /* older Wwise (used?) */
case 0x0069: ww.codec = IMA; break; /* older Wwise (Spiderman Web of Shadows X360, LotR Conquest PC) */
case 0x0161: ww.codec = XWMA; break;
case 0x0162: ww.codec = XWMA; break;
case 0x0165: ww.codec = XMA2; break; /* always with the "XMA2" chunk, Wwise doesn't use XMA1 */
case 0x0166: ww.codec = XMA2; break;
case 0xAAC0: ww.codec = AAC; break;
case 0xFFF0: ww.codec = DSP; break;
case 0xFFFB: ww.codec = HEVAG; break;
case 0xFFFC: ww.codec = ATRAC9; break;
case 0xFFFE: ww.codec = PCM; break; /* newer Wwise ("PCM for Wwise Authoring") (conflicts with WAVEFORMATEXTENSIBLE) */
case 0xFFFE: ww.codec = PCM; break; /* "PCM for Wwise Authoring" */
case 0xFFFF: ww.codec = VORBIS; break;
default:
VGM_LOG("WWISE: unknown codec 0x%x \n", ww.format);
@ -148,13 +157,23 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
ww.codec = DSP;
}
/* Some Wwise files (ex. Oddworld PSV, Bayonetta 2 WiiU sfx) are truncated mirrors of another file.
* They come in RAM banks, probably to play the beginning while the rest of the real stream loads.
* We'll add basic support to avoid complaints of this or that .wem not playing */
if (ww.data_size > ww.file_size) {
//VGM_LOG("WWISE: truncated data size (prefetch): (real=0x%x > riff=0x%x)\n", ww.data_size, ww.file_size);
if (ww.codec == IMA || ww.codec == VORBIS) /* only seen those, probably others exist */
ww.truncated = 1;
else
goto fail;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(ww.channels,ww.loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = ww.sample_rate;
vgmstream->num_samples = ww.num_samples;
vgmstream->loop_start_sample = ww.loop_start_sample;
vgmstream->loop_end_sample = ww.loop_end_sample;
vgmstream->meta_type = meta_WWISE_RIFF;
@ -164,93 +183,172 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
switch(ww.codec) {
case PCM: /* common */
/* normally riff.c has priority but it's needed when .wem is used */
if (ww.bit_per_sample != 16) goto fail;
if (ww.bits_per_sample != 16) goto fail;
vgmstream->coding_type = (ww.big_endian ? coding_PCM16BE : coding_PCM16LE);
vgmstream->layout_type = ww.channels > 1 ? layout_interleave : layout_none;
vgmstream->interleave_block_size = 0x02;
vgmstream->num_samples = ww.data_size / ww.channels / (ww.bit_per_sample/8);
vgmstream->num_samples = pcm_bytes_to_samples(ww.data_size, ww.channels, ww.bits_per_sample);
break;
case IMA: /* common */
/* slightly modified MS-IMA.
* Original research by hcs in ima_rejigger (https://github.com/hcs64/vgm_ripping/tree/master/demux/ima_rejigger5) */
#if 0
if (ww.bit_per_sample != 4) goto fail;
/* slightly modified MS IMA with interleaved sub-blocks and LE/BE header */
/* Wwise uses common codecs (ex. 0x0002 MSADPCM) so this parser should go AFTER riff.c avoid misdetection */
if (ww.bits_per_sample != 4) goto fail;
vgmstream->coding_type = coding_WWISE_IMA;
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = ww.block_align;
vgmstream->codec_endian = ww.big_endian;
vgmstream->num_samples = (ww.data_size / ww.block_align) * (ww.block_align - 4 * vgmstream->channels) * 2 /vgmstream->channels;
if (ww.truncated) /* enough to get real samples */
ww.data_size = ww.file_size - ww.data_offset;
vgmstream->num_samples = ms_ima_bytes_to_samples(ww.data_size, ww.block_align, ww.channels);
break;
#endif
VGM_LOG("WWISE: IMA found (unsupported)\n");
goto fail;
#ifdef VGM_USE_VORBIS
case VORBIS: { /* common */
/* Wwise uses custom Vorbis, which changed over time (config must be detected to pass to the decoder).
* Original research by hcs in ww2ogg (https://github.com/hcs64/ww2ogg) */
#if 0
off_t vorb_offset;
size_t vorb_size;
/* Wwise uses custom Vorbis, which changed over time (config must be detected to pass to the decoder). */
off_t vorb_offset, data_offsets, block_offsets;
size_t vorb_size, setup_offset, audio_offset;
int packet_header_type = 0; /* 1 = size 8 (4-granule + 4-size), 2 = size 6 (4-granule + 2-size) or 3 = size 2 (2-size) */
int packet_type = 0; /* 1 = standard, 2 = modified vorbis packets */
int setup_type = 0; /* 1: triad, 2 = inline codebooks, 3 = external codebooks, 4 = external aoTuV codebooks */
int blocksize_0_pow = 0, blocksize_1_pow = 0;
wwise_setup_type setup_type;
wwise_header_type header_type;
wwise_packet_type packet_type;
int blocksize_0_exp = 0, blocksize_1_exp = 0;
if (ww.block_align != 0 || ww.bit_per_sample != 0) goto fail;
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail; /* always 0 for Worbis */
/* autodetect format */
/* autodetect format (field are mostly common, see the end of the file) */
if (find_chunk(streamFile, 0x766F7262,first_offset,0, &vorb_offset,&vorb_size, ww.big_endian, 0)) { /*"vorb"*/
/* older Wwise (~2011) */
switch (vorb_size) {
case 0x28:
case 0x2A:
case 0x2C:
case 0x32:
case 0x34:
default: goto fail;
/* older Wwise (~<2012) */
switch(vorb_size) {
//case 0x2C: /* early (~2009), some EVE Online Apocrypha files? */
case 0x28: /* early (~2009), ex. The Lord of the Rings: Conquest PC */
data_offsets = 0x18;
block_offsets = 0; /* no need, full headers are present */
header_type = TYPE_8;
packet_type = STANDARD;
setup_type = HEADER_TRIAD;
break;
//case 0x32: /* ? */
case 0x34: /* common (2010~2011) */
data_offsets = 0x18;
block_offsets = 0x30;
header_type = TYPE_6;
packet_type = STANDARD;
setup_type = EXTERNAL_CODEBOOKS; /* setup_type will be corrected later */
break;
case 0x2a: /* uncommon (mid 2011), ex. infamous 2 PS3 */
data_offsets = 0x10;
block_offsets = 0x28;
header_type = TYPE_2;
packet_type = MODIFIED;
setup_type = EXTERNAL_CODEBOOKS;
break;
default:
VGM_LOG("WWISE: unknown vorb size 0x%x\n", vorb_size);
goto fail;
}
vgmstream->num_samples = read_32bit(vorb_offset + 0x00, streamFile);
setup_offset = read_32bit(vorb_offset + data_offsets + 0x00, streamFile); /* within data (0 = no seek table) */
audio_offset = read_32bit(vorb_offset + data_offsets + 0x04, streamFile); /* within data */
if (block_offsets) {
blocksize_1_exp = read_8bit(vorb_offset + block_offsets + 0x00, streamFile); /* small */
blocksize_0_exp = read_8bit(vorb_offset + block_offsets + 0x01, streamFile); /* big */
}
/* detect setup type:
* - full inline: ~2009, ex. The King of Fighters XII X360, The Saboteur PC
* - trimmed inline: ~2010, ex. Army of Two: 40 days X360 (some multiplayer files)
* - external: ~2010, ex. Assassin's Creed Brotherhood X360, Dead Nation X360 */
if (vorb_size == 0x34) {
size_t setup_size = (uint16_t)read_16bit(start_offset + setup_offset, streamFile);
uint32_t id = (uint32_t)read_32bitBE(start_offset + setup_offset + 0x06, streamFile);
/* if the setup after header starts with "(data)BCV" it's an inline codebook) */
if ((id & 0x00FFFFFF) == 0x00424356) { /* 0"BCV" */
setup_type = FULL_SETUP;
}
/* 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 */
setup_type = INLINE_CODEBOOKS;
}
}
vgmstream->codec_data = init_wwise_vorbis_codec_data(streamFile, start_offset + setup_offset, ww.channels, ww.sample_rate, blocksize_0_exp,blocksize_1_exp,
setup_type,header_type,packet_type, ww.big_endian);
if (!vgmstream->codec_data) goto fail;
}
else {
/* newer Wwise (~2012+) */
if (ww.extra_size != 0x30) goto fail; //todo some 0x2a exist
/* newer Wwise (>2012) */
off_t extra_offset = ww.fmt_offset + 0x18; /* after flag + channels */
int is_wem = check_extensions(streamFile,"wem");
packet_header_type = 3; /* size 2 */
packet_type = 1; //todo mod packets false on certain configs
setup_type = 4; /* aoTuV */
switch(ww.extra_size) {
case 0x30:
data_offsets = 0x10;
block_offsets = 0x28;
header_type = TYPE_2;
packet_type = MODIFIED;
/* 0x12 (2): unk (00,10,18) not related to seek table*/
/* 0x14 (4): channel config */
vgmstream->num_samples = read_32bit(ww.fmt_offset + 0x18, streamFile);
/* 0x20 (4): config, 0xcb/0xd9/etc */
/* 0x24 (4): ? samples? */
/* 0x28 (4): seek table size (setup packet offset within data) */
/* 0x2c (4): setup size (first audio packet offset within data) */
/* 0x30 (2): ? */
/* 0x32 (2): ? */
/* 0x34 (4): ? */
/* 0x38 (4): ? */
/* 0x3c (4): uid */ //todo same as external crc32?
blocksize_0_pow = read_8bit(ww.fmt_offset + 0x40, streamFile);
blocksize_1_pow = read_8bit(ww.fmt_offset + 0x41, streamFile);
/* 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)
* - aoTuV603: later (>2012), ex. Sonic & All-Stars Racing Transformed PC (2012/11), .wem */
setup_type = is_wem ? AOTUV603_CODEBOOKS : EXTERNAL_CODEBOOKS; /* aoTuV came along .wem */
break;
goto fail;
//case 0x2a: /* Rocksmith 2011 X360? */
//non mod packets? TYPE_06? (possibly detectable by checking setup's granule, should be 0)
default:
VGM_LOG("WWISE: unknown extra size 0x%x\n", vorb_size);
goto fail;
}
vgmstream->num_samples = read_32bit(extra_offset + 0x00, streamFile);
setup_offset = read_32bit(extra_offset + data_offsets + 0x00, streamFile); /* within data*/
audio_offset = read_32bit(extra_offset + data_offsets + 0x04, streamFile); /* within data */
blocksize_1_exp = read_8bit(extra_offset + block_offsets + 0x00, streamFile); /* small */
blocksize_0_exp = read_8bit(extra_offset + block_offsets + 0x01, streamFile); /* big */
/* Normal packets are used rarely (ex. Oddworld New 'n' Tasty! PSV). They are hard to detect (decoding
* will mostly work with garbage results) but we'll try. Setup size and "fmt" bitrate fields may matter too. */
if (ww.extra_size == 0x30) {
/* all blocksizes I've seen are 0x08+0x0B except Oddworld PSV, that uses 0x09+0x09
* (maybe lower spec machines = needs simpler packets) */
if (blocksize_0_exp == blocksize_1_exp)
packet_type = STANDARD;
}
/* try with the selected codebooks */
vgmstream->codec_data = init_wwise_vorbis_codec_data(streamFile, start_offset + setup_offset, ww.channels, ww.sample_rate, blocksize_0_exp,blocksize_1_exp,
setup_type,header_type,packet_type, ww.big_endian);
if (!vgmstream->codec_data) {
/* codebooks failed: try again with the other type */
setup_type = is_wem ? EXTERNAL_CODEBOOKS : AOTUV603_CODEBOOKS;
vgmstream->codec_data = init_wwise_vorbis_codec_data(streamFile, start_offset + setup_offset, ww.channels, ww.sample_rate, blocksize_0_exp,blocksize_1_exp,
setup_type,header_type,packet_type, ww.big_endian);
if (!vgmstream->codec_data) goto fail;
}
}
vgmstream->codec_data = init_wwise_vorbis_codec_data(streamFile, start_offset, vgmstream->channels, vgmstream->sample_rate);//pass endianness too
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_wwise_vorbis;
vgmstream->layout_type = layout_none;
vgmstream->codec_endian = ww.big_endian;
start_offset = start_offset + audio_offset;
/* Vorbis is VBR so this is very approximate, meh */
if (ww.truncated)
vgmstream->num_samples = vgmstream->num_samples * (ww.file_size - start_offset) / ww.data_size;
break;
#endif
VGM_LOG("WWISE: VORBIS found (unsupported)\n");
goto fail;
}
#endif
@ -259,7 +357,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
size_t wiih_size;
int i;
if (ww.bit_per_sample != 4) goto fail;
if (ww.bits_per_sample != 4) goto fail;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
@ -267,7 +365,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
/* find coef position */
if (find_chunk(streamFile, 0x57696948,first_offset,0, &wiih_offset,&wiih_size, ww.big_endian, 0)) { /*"WiiH"*/ /* older Wwise */
vgmstream->num_samples = ww.data_size / ww.channels / 8 * 14;
vgmstream->num_samples = dsp_bytes_to_samples(ww.data_size, ww.channels);
if (wiih_size != 0x2e * ww.channels) goto fail;
}
else if (ww.extra_size == 0x0c + ww.channels * 0x2e) { /* newer Wwise */
@ -291,21 +389,74 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
#ifdef VGM_USE_FFMPEG
case XMA2: { /* X360/XBone */
//chunks:
//"XMA2", "seek": same as the official ones
//"XMAc": Wwise extension, XMA2 physical loop regions (loop_start_b, loop_end_b, loop_subframe_data)
uint8_t buf[0x100];
int bytes;
off_t xma2_offset;
size_t xma2_size;
VGM_LOG("WWISE: XMA2 found (unsupported)\n");
goto fail;
if (!ww.big_endian) goto fail; /* must be Wwise (real XMA are LE and parsed elsewhere) */
if (find_chunk(streamFile, 0x584D4132,first_offset,0, &xma2_offset,&xma2_size, ww.big_endian, 0)) { /*"XMA2"*/ /* older Wwise */
bytes = ffmpeg_make_riff_xma2_from_xma2_chunk(buf,0x100, xma2_offset, xma2_size, ww.data_size, streamFile);
} else { /* newer Wwise */
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, ww.fmt_offset, ww.fmt_size, ww.data_size, streamFile, ww.big_endian);
}
if (bytes <= 0) goto fail;
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, ww.data_offset,ww.data_size);
if ( !vgmstream->codec_data ) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = ww.num_samples; /* set while parsing XMAWAVEFORMATs */
/* "XMAc": rare Wwise extension, XMA2 physical loop regions (loop_start_b, loop_end_b, loop_subframe_data)
* Can appear even in the file doesn't loop, maybe it's meant to be the playable physical region */
//VGM_ASSERT(find_chunk(streamFile, 0x584D4163,first_offset,0, NULL,NULL, ww.big_endian, 0), "WWISE: XMAc chunk found\n");
/* other chunks: "seek", regular XMA2 seek table */
break;
}
case XWMA: /* X360 */
VGM_LOG("WWISE: XWMA found (unsupported)\n");
goto fail;
case XWMA: { /* X360 */
ffmpeg_codec_data *ffmpeg_data = NULL;
uint8_t buf[0x100];
int bytes;
if (!ww.big_endian) goto fail; /* must be from Wwise X360 (PC LE XWMA is parsed elsewhere) */
bytes = ffmpeg_make_riff_xwma(buf,0x100, ww.format, ww.data_size, vgmstream->channels, vgmstream->sample_rate, ww.average_bps, ww.block_align);
if (bytes <= 0) goto fail;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, ww.data_offset,ww.data_size);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
/* manually find total samples, why don't they put this in the header is beyond me */
{
ms_sample_data msd;
memset(&msd,0,sizeof(ms_sample_data));
msd.channels = ww.channels;
msd.data_offset = ww.data_offset;
msd.data_size = ww.data_size;
if (ww.format == 0x0162)
wmapro_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x0000);
else
wma_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x0000);
vgmstream->num_samples = ffmpeg_data->totalSamples; /* ffmpeg_data->totalSamples is approximate from avg-br */
}
break;
}
case AAC: { /* iOS/Mac */
ffmpeg_codec_data * ffmpeg_data = NULL;
if (ww.block_align != 0 || ww.bit_per_sample != 0) goto fail;
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail;
/* extra: size 0x12, unknown values */
@ -322,18 +473,18 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
case HEVAG: /* PSV */
/* changed values, another bizarre Wwise quirk */
//ww.block_align /* unknown (1ch=2, 2ch=4) */
//ww.bit_per_sample; /* probably interleave (0x10) */
//if (ww.bit_per_sample != 4) goto fail;
//ww.bits_per_sample; /* probably interleave (0x10) */
//if (ww.bits_per_sample != 4) goto fail;
if (ww.big_endian) goto fail;
/* extra_data: size 0x06, @0x00: samples per block (28), @0x04: channel config */
/* extra_data: size 0x06, @0x00: samples per block (0x1c), @0x04: channel config */
vgmstream->coding_type = coding_HEVAG;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
vgmstream->num_samples = ww.data_size * 28 / 16 / ww.channels;
vgmstream->num_samples = ps_bytes_to_samples(ww.data_size, ww.channels);
break;
case ATRAC9: /* PSV/PS4 */
@ -353,3 +504,68 @@ fail:
close_vgmstream(vgmstream);
return NULL;
}
/* VORBIS FORMAT RESEARCH */
/*
- old format
"fmt" size 0x28, extra size 0x16 / size 0x18, extra size 0x06
0x12 (2): flag? (00,10,18): not related to seek table, codebook type, chunk count, looping
0x14 (4): channel config
0x18-24 (16): ? (fixed: 0x01000000 00001000 800000AA 00389B71) [removed when extra size is 0x06]
"vorb" size 0x34
0x00 (4): num_samples
0x04 (4): skip samples?
0x08 (4): ? (small if loop, 0 otherwise)
0x0c (4): loop offset after seek table+setup (offset after setup if file doesn't loop)
0x10 (4): ? (small, 0..~0x400)
0x14 (4): approximate data size without seek table? (almost setup+packets)
0x18 (4): setup_offset within data (0 = no seek table)
0x1c (4): audio_offset within data
0x20 (4): biggest packet size (not including header)?
0x24 (4): ? (mid, 0~0x5000)
0x28 (4): ? (mid, 0~0x5000)
0x2c (4): parent bank/event id? (shared by several .wem a game, but not all need to share it)
0x30 (1): blocksize_1_exp (small)
0x31 (1): blocksize_0_exp (large)
0x32 (2): empty
"vorb" size 0x28 / 0x2a
0x00 (4): num_samples
0x04 (4): loop offset after seek table+setup (offset after setup if file doesn't loop)
0x08 (4): data size without seek table (setup+packets)
0x0c (2): ? (small, 0..~0x400)
0x10 (4): setup_offset within data (0 = no seek table)
0x14 (4): audio_offset within data
0x18 (2): ? (small, 0..~0x400)
0x1a (2): ? (small, N..~0x100)
0x1c (4): ? (mid, 0~0x5000)
0x20 (4): ? (mid, 0~0x5000)
0x24 (4): parent bank/event id? (shared by several .wem a game, but not all need to share it)
0x28 (1): blocksize_1_exp (small) [removed when size is 0x28]
0x29 (1): blocksize_0_exp (large) [removed when size is 0x28]
- new format:
"fmt" size 0x42, extra size 0x30
0x12 (2): flag? (00,10,18): not related to seek table, codebook type, chunk count, looping, etc
0x14 (4): channel config
0x18 (4): num_samples
0x1c (4): loop offset after seek table+setup (offset after setup if file doesn't loop)
0x20 (4): data size without seek table (setup+packets)
0x24 (2): ?1 (small, 0..~0x400)
0x26 (2): ?2 (small, N..~0x100): not related to seek table, codebook type, chunk count, looping, packet size, samples, etc
0x28 (4): setup offset within data (0 = no seek table)
0x2c (4): audio offset within data
0x30 (2): biggest packet size (not including header)
0x32 (2): ?4 (small, 0..~0x100): may be same than ?2 (something related to the avg bitrate?)
0x34 (4): bitrate config? (mid, 0~0x5000)
0x38 (4): bitrate config? (mid, 0~0x5000) (2 byte with max/min?)
0x40 (1): blocksize_1_exp (small)
0x41 (1): blocksize_0_exp (large)
Wwise encoder options, unknown fields above may be reflect these:
https://www.audiokinetic.com/library/edge/?source=Help&id=vorbis_encoder_parameters
*/

View File

@ -37,29 +37,29 @@ VGMSTREAM * init_vgmstream_x360_ast(STREAMFILE *streamFile) {
vgmstream->sample_rate = read_32bitBE(0x40,streamFile);
vgmstream->meta_type = meta_X360_AST;
#ifdef VGM_USE_FFMPEG
{
/* manually find sample offsets (XMA1 nonsense again) */
xma_sample_data xma_sd;
memset(&xma_sd,0,sizeof(xma_sample_data));
ms_sample_data msd;
memset(&msd,0,sizeof(ms_sample_data));
xma_sd.xma_version = 1;
xma_sd.channels = channel_count;
xma_sd.data_offset = start_offset;
xma_sd.data_size = data_size;
xma_sd.loop_flag = loop_flag;
xma_sd.loop_start_b = read_32bitBE(0x44,streamFile);
xma_sd.loop_end_b = read_32bitBE(0x48,streamFile);
xma_sd.loop_start_subframe = read_8bit(0x4c,streamFile) & 0xF; /* lower 4b: subframe where the loop starts, 0..4 */
xma_sd.loop_end_subframe = read_8bit(0x4c,streamFile) >> 4; /* upper 4b: subframe where the loop ends, 0..3 */
msd.xma_version = 1;
msd.channels = channel_count;
msd.data_offset = start_offset;
msd.data_size = data_size;
msd.loop_flag = loop_flag;
msd.loop_start_b = read_32bitBE(0x44,streamFile);
msd.loop_end_b = read_32bitBE(0x48,streamFile);
msd.loop_start_subframe = read_8bit(0x4c,streamFile) & 0xF; /* lower 4b: subframe where the loop starts, 0..4 */
msd.loop_end_subframe = read_8bit(0x4c,streamFile) >> 4; /* upper 4b: subframe where the loop ends, 0..3 */
xma_get_samples(&xma_sd, streamFile);
vgmstream->num_samples = xma_sd.num_samples;
vgmstream->loop_start_sample = xma_sd.loop_start_sample;
vgmstream->loop_end_sample = xma_sd.loop_end_sample;
//skip_samples = xma_sd.skip_samples; //todo add skip samples
xma_get_samples(&msd, streamFile);
vgmstream->num_samples = msd.num_samples;
vgmstream->loop_start_sample = msd.loop_start_sample;
vgmstream->loop_end_sample = msd.loop_end_sample;
//skip_samples = msd.skip_samples; //todo add skip samples
}
#ifdef VGM_USE_FFMPEG
{
uint8_t buf[100];
size_t bytes;
@ -68,7 +68,7 @@ VGMSTREAM * init_vgmstream_x360_ast(STREAMFILE *streamFile) {
size_t fmt_size = 0x0c + xma_streams * 0x14;
/* XMA1 "fmt" chunk @ 0x20 (BE, unlike the usual LE) */
bytes = ffmpeg_make_riff_xma_from_fmt(buf,100, fmt_offset,fmt_size, data_size, streamFile, 1);
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,100, fmt_offset,fmt_size, data_size, streamFile, 1);
if (bytes <= 0) goto fail;
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);

View File

@ -0,0 +1,78 @@
#include "meta.h"
#include "../coding/coding.h"
/* Namco NUB xma - from Tekken 6, Galaga Legions DX */
VGMSTREAM * init_vgmstream_x360_nub(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, chunk_offset;
size_t data_size, chunk_size;
int loop_flag, channel_count, sample_rate, chunk_type;
int num_samples, loop_start_sample, loop_end_sample;
/* check extension, case insensitive */
if ( !check_extensions(streamFile,"xma")) /* (probably meant to be .nub) */
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x786D6100) /* "xma\0" */
goto fail;
/* custom header with a "XMA2" or "fmt " chunk inside; most other values are unknown */
chunk_type = read_32bitBE(0xC,streamFile);
start_offset = 0x100;
data_size = read_32bitBE(0x14,streamFile);
chunk_offset = 0xBC;
chunk_size = read_32bitBE(0x24,streamFile);
if (chunk_type == 0x4) { /* "XMA2" */
xma2_parse_xma2_chunk(streamFile, chunk_offset, &channel_count,&sample_rate, &loop_flag, &num_samples, &loop_start_sample, &loop_end_sample);
} else if (chunk_type == 0x8) { /* "fmt " */
channel_count = read_16bitBE(chunk_offset+0x02,streamFile);
sample_rate = read_32bitBE(chunk_offset+0x04,streamFile);
xma2_parse_fmt_chunk_extra(streamFile, chunk_offset, &loop_flag, &num_samples, &loop_start_sample, &loop_end_sample, 1);
} else {
goto fail;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->meta_type = meta_NUB_XMA;
#ifdef VGM_USE_FFMPEG
{
uint8_t buf[0x100];
size_t bytes;
if (chunk_type == 0x4) { /* "XMA2" */
bytes = ffmpeg_make_riff_xma2_from_xma2_chunk(buf,0x100, chunk_offset,chunk_size, data_size, streamFile);
} else { /* "fmt " */
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, chunk_offset,chunk_size, data_size, streamFile, 1);
}
if (bytes <= 0) goto fail;
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);;
if ( !vgmstream->codec_data ) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
}
#else
goto fail;
#endif
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -0,0 +1,68 @@
#include "meta.h"
#include "../coding/coding.h"
/* PASX - from SoulCalibur II HD (X360) */
VGMSTREAM * init_vgmstream_x360_pasx(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, chunk_offset;
size_t data_size, chunk_size;
int loop_flag, channel_count, sample_rate;
int num_samples, loop_start_sample, loop_end_sample;
/* check extension, case insensitive */
if ( !check_extensions(streamFile,"past"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x50415358) /* "PASX" */
goto fail;
/* custom header with a "fmt " data chunk inside */
chunk_size = read_32bitBE(0x08,streamFile);
data_size = read_32bitBE(0x0c,streamFile);
chunk_offset = read_32bitBE(0x10,streamFile); /* 0x14: fmt offset end */
start_offset = read_32bitBE(0x18,streamFile);
channel_count = read_16bitBE(chunk_offset+0x02,streamFile);
sample_rate = read_32bitBE(chunk_offset+0x04,streamFile);
xma2_parse_fmt_chunk_extra(streamFile, chunk_offset, &loop_flag, &num_samples, &loop_start_sample, &loop_end_sample, 1);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->meta_type = meta_X360_PASX;
#ifdef VGM_USE_FFMPEG
{
uint8_t buf[0x100];
size_t bytes;
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, chunk_offset,chunk_size, data_size, streamFile, 1);
if (bytes <= 0) goto fail;
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
if ( !vgmstream->codec_data ) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
}
#else
goto fail;
#endif
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,103 +1,117 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
#ifdef VGM_USE_FFMPEG
#define FAKE_RIFF_BUFFER_SIZE 100
/* parsing helper */
typedef struct {
size_t file_size;
/* file traversing */
int big_endian;
off_t chunk_offset; /* main header chunk offset, after "(id)" and size */
size_t chunk_size;
off_t data_offset;
size_t data_size;
int32_t fmt_codec;
uint8_t xma2_version;
int needs_header;
int force_little_endian; /* FFmpeg can't parse big endian "fmt" chunks */
int skip_samples;
/* info */
int channels;
int loop_flag;
int32_t num_samples;
int32_t loop_start_sample;
int32_t loop_end_sample;
int32_t loop_start_b;
int32_t loop_end_b;
int32_t loop_subframe;
meta_t meta;
} xma_header_data;
static int parse_header(xma_header_data * xma, STREAMFILE *streamFile);
static void fix_samples(xma_header_data * xma, STREAMFILE *streamFile);
static int create_riff_header(uint8_t * buf, size_t buf_size, xma_header_data * xma, STREAMFILE *streamFile);
/**
* XMA 1/2 (Microsoft)
*
* Usually in RIFF headers and minor variations.
*/
/* XMA - Microsoft format derived from WMAPRO, found in X360/XBone games */
VGMSTREAM * init_vgmstream_xma(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
ffmpeg_codec_data *data = NULL;
xma_header_data xma;
uint8_t fake_riff[FAKE_RIFF_BUFFER_SIZE];
int fake_riff_size = 0;
off_t start_offset, chunk_offset, first_offset = 0xc;
size_t data_size, chunk_size;
int loop_flag, channel_count, sample_rate, is_xma2_old = 0, is_xma1 = 0;
int num_samples, loop_start_sample, loop_end_sample, loop_start_b = 0, loop_end_b = 0, loop_subframe = 0;
/* check extension, case insensitive */
/* .xma2: Skullgirls, .nps: Beautiful Katamari, .past: SoulCalibur II HD */
if ( !check_extensions(streamFile, "xma,xma2,nps,past") )
/* .xma2: Skullgirls, .nps: Beautiful Katamari (renamed .xma) */
if ( !check_extensions(streamFile, "xma,xma2,nps") )
goto fail;
/* check header */
if ( !parse_header(&xma, streamFile) )
goto fail;
/* init ffmpeg (create a fake RIFF that FFmpeg can read if needed) */
if (xma.needs_header) { /* fake header + partial size */
fake_riff_size = create_riff_header(fake_riff, FAKE_RIFF_BUFFER_SIZE, &xma, streamFile);
if (fake_riff_size <= 0) goto fail;
data = init_ffmpeg_header_offset(streamFile, fake_riff, (uint64_t)fake_riff_size, xma.data_offset, xma.data_size);
if (!data) goto fail;
}
else { /* no change */
data = init_ffmpeg_offset(streamFile, 0, xma.file_size);
if (!data) goto fail;
{
size_t file_size = streamFile->get_size(streamFile);
size_t riff_size = read_32bitLE(0x04,streamFile);
/* +8 for some Beautiful Katamari files, unsure if bad rip */
if (riff_size != file_size && riff_size+8 > file_size)
goto fail;
}
/* build VGMSTREAM */
vgmstream = allocate_vgmstream(data->channels, xma.loop_flag);
/* parse LE RIFF header, with "XMA2" (XMA2WAVEFORMAT) or "fmt " (XMAWAVEFORMAT/XMA2WAVEFORMAT) main chunks
* Often comes with an optional "seek" chunk too */
/* parse sample data */
if ( find_chunk_le(streamFile, 0x584D4132,first_offset,0, &chunk_offset,&chunk_size) ) { /* old XMA2 */
is_xma2_old = 1;
xma2_parse_xma2_chunk(streamFile, chunk_offset, &channel_count,&sample_rate, &loop_flag, &num_samples, &loop_start_sample, &loop_end_sample);
}
else if ( find_chunk_le(streamFile, 0x666d7420,first_offset,0, &chunk_offset,&chunk_size)) {
int format = read_16bitLE(chunk_offset,streamFile);
if (format == 0x165) { /* XMA1 */
is_xma1 = 1;
xma1_parse_fmt_chunk(streamFile, chunk_offset, &channel_count,&sample_rate, &loop_flag, &loop_start_b, &loop_end_b, &loop_subframe, 0);
} else if (format == 0x166) { /* new XMA2 */
channel_count = read_16bitLE(chunk_offset+0x02,streamFile);
sample_rate = read_32bitLE(chunk_offset+0x04,streamFile);
xma2_parse_fmt_chunk_extra(streamFile, chunk_offset, &loop_flag, &num_samples, &loop_start_sample, &loop_end_sample, 0);
} else {
goto fail;
}
}
else {
goto fail;
}
/* "data" chunk */
if (!find_chunk_le(streamFile, 0x64617461,first_offset,0, &start_offset,&data_size)) /*"data"*/
goto fail;
/* fix samples; for now only XMA1 is fixed, but xmaencode.exe doesn't seem to use XMA2
* num_samples in the headers, and the values don't look exact */
if (is_xma1) {
ms_sample_data msd;
memset(&msd,0,sizeof(ms_sample_data));
msd.xma_version = 1;
msd.channels = channel_count;
msd.data_offset = start_offset;
msd.data_size = data_size;
msd.loop_flag = loop_flag;
msd.loop_start_b= loop_start_b;
msd.loop_end_b = loop_end_b;
msd.loop_start_subframe = loop_subframe & 0xF; /* lower 4b: subframe where the loop starts, 0..4 */
msd.loop_end_subframe = loop_subframe >> 4; /* upper 4b: subframe where the loop ends, 0..3 */
xma_get_samples(&msd, streamFile);
num_samples = msd.num_samples;
//skip_samples = msd.skip_samples;
loop_start_sample = msd.loop_start_sample;
loop_end_sample = msd.loop_end_sample;
/* XMA2 loop/num_samples don't seem to skip_samples */
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->codec_data = data;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = xma.meta;
vgmstream->sample_rate = data->sampleRate;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->meta_type = meta_XMA_RIFF;
/* fix samples for some formats (data->totalSamples: XMA1 = not set; XMA2 = not reliable) */
xma.channels = data->channels;
fix_samples(&xma, streamFile);
vgmstream->num_samples = xma.num_samples;
if (vgmstream->loop_flag) {
vgmstream->loop_start_sample = xma.loop_start_sample;
vgmstream->loop_end_sample = xma.loop_end_sample;
#ifdef VGM_USE_FFMPEG
{
uint8_t buf[0x100];
size_t bytes;
if (is_xma2_old) {
bytes = ffmpeg_make_riff_xma2_from_xma2_chunk(buf,0x100, chunk_offset,chunk_size, data_size, streamFile);
} else {
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, chunk_offset,chunk_size, data_size, streamFile, 0);
}
if (bytes <= 0) goto fail;
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
if ( !vgmstream->codec_data ) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
}
#else
goto fail;
#endif
#if 0
//not active due to a FFmpeg bug that misses some of the last packet samples and decodes
// garbage if asked for more samples (always happens but more apparent with skip_samples active)
@ -106,313 +120,17 @@ VGMSTREAM * init_vgmstream_xma(STREAMFILE *streamFile) {
ffmpeg_set_skip_samples(data, xma.skip_samples);
#endif
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
/* clean up */
if (data) {
free_ffmpeg(data);
}
if (vgmstream) {
vgmstream->codec_data = NULL;
close_vgmstream(vgmstream);
}
close_vgmstream(vgmstream);
return NULL;
}
/**
* Finds stuff needed for XMA with FFmpeg
*
* returns 1 if ok, 0 on error
*/
static int parse_header(xma_header_data * xma, STREAMFILE *streamFile) {
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
uint32_t id;
int big_endian = 0;
enum {
id_RIFF = UINT32_C(0x52494646), /* "RIFF" */
id_RIFX = UINT32_C(0x52494658), /* "RIFX" */
id_NXMA = UINT32_C(0x786D6100), /* "xma\0" */
id_PASX = UINT32_C(0x50415358), /* "PASX" */
};
/* check header */
id = read_32bitBE(0x00,streamFile);
switch (id) {
case id_RIFF:
break;
case id_RIFX:
case id_NXMA:
case id_PASX:
big_endian = 1;
break;
default:
goto fail;
}
memset(xma,0,sizeof(xma_header_data));
xma->big_endian = big_endian;
if (xma->big_endian) {
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
} else {
read_32bit = read_32bitLE;
read_16bit = read_16bitLE;
}
xma->file_size = streamFile->get_size(streamFile);
/* find offsets */
if (id == id_RIFF || id == id_RIFX) { /* regular RIFF header / RIFX (BE, wwsize?) */
off_t current_chunk = 0xc;
off_t fmt_offset = 0, xma2_offset = 0;
size_t riff_size = 0, fmt_size = 0, xma2_size = 0;
xma->meta = meta_XMA_RIFF;
riff_size = read_32bit(4,streamFile);
if (riff_size != xma->file_size && /* some Beautiful Katamari, unsure if bad rip */
riff_size+8 > xma->file_size) goto fail;
while (current_chunk < xma->file_size && current_chunk < riff_size+8) {
uint32_t chunk_type = read_32bitBE(current_chunk,streamFile);
off_t chunk_size = read_32bit(current_chunk+4,streamFile);
if (current_chunk+4+4+chunk_size > xma->file_size)
goto fail;
switch(chunk_type) {
case 0x666d7420: /* "fmt " */
if (fmt_offset) goto fail;
fmt_offset = current_chunk + 4 + 4;
fmt_size = chunk_size;
break;
case 0x64617461: /* "data" */
if (xma->data_offset) goto fail;
xma->data_offset = current_chunk + 4 + 4;
xma->data_size = chunk_size;
break;
case 0x584D4132: /* "XMA2" */
if (xma2_offset) goto fail;
xma2_offset = current_chunk + 4 + 4;
xma2_size = chunk_size;
break;
default:
break;
}
current_chunk += 8+chunk_size;
}
/* give priority to "XMA2" since it can go together with "fmt " */
if (xma2_offset) {
xma->chunk_offset = xma2_offset;
xma->chunk_size = xma2_size;
xma->xma2_version = read_8bit(xma->chunk_offset,streamFile);
xma->needs_header = 1; /* FFmpeg can only parse pure XMA1 or pure XMA2 */
} else if (fmt_offset) {
xma->chunk_offset = fmt_offset;
xma->chunk_size = fmt_size;
xma->fmt_codec = read_16bit(xma->chunk_offset,streamFile);
xma->force_little_endian = xma->big_endian;
} else {
goto fail;
}
}
else if (id == id_NXMA) { /* Namco NUB xma (Tekken 6, Galaga Legions DX) */
/* Custom header with a "XMA2" or "fmt " data chunk inside; most other values are unknown
* It's here rather than its own meta to reuse the chunk parsing (probably intended to be .nub) */
uint32_t chunk_type = read_32bit(0xC,streamFile);
xma->meta = meta_NUB_XMA;
xma->data_offset = 0x100;
xma->data_size = read_32bit(0x14,streamFile);
xma->chunk_offset = 0xBC;
xma->chunk_size = read_32bit(0x24,streamFile);
if (chunk_type == 0x4) { /* "XMA2" */
xma->xma2_version = read_8bit(xma->chunk_offset,streamFile);
} else if (chunk_type == 0x8) { /* "fmt " */
xma->fmt_codec = read_16bit(xma->chunk_offset,streamFile);
xma->force_little_endian = 1;
} else {
goto fail;
}
xma->needs_header = 1;
if (xma->data_size + xma->data_offset > xma->file_size) goto fail;
}
else if (id == id_PASX) { /* SoulCalibur II HD */
/* Custom header with a "fmt " data chunk inside
* It's here rather than its own meta to reuse the chunk parsing */
xma->meta = meta_X360_PASX;
xma->chunk_size = read_32bit(0x08,streamFile);
xma->data_size = read_32bit(0x0c,streamFile);
xma->chunk_offset = read_32bit(0x10,streamFile);
/* 0x14: chunk offset end */
xma->data_offset = read_32bit(0x18,streamFile);
xma->fmt_codec = read_16bit(xma->chunk_offset,streamFile);
xma->needs_header = 1;
xma->force_little_endian = 1;
}
else {
goto fail;
}
/* find sample data */
if (xma->xma2_version) { /* old XMA2 (internally always BE) */
xma->loop_start_sample = read_32bitBE(xma->chunk_offset+0x4,streamFile);
xma->loop_end_sample = read_32bitBE(xma->chunk_offset+0x8,streamFile);
xma->loop_flag = (uint8_t)read_8bit(xma->chunk_offset+0x3,streamFile) > 0 /* rarely not set, encoder default */
|| xma->loop_end_sample;
if (xma->xma2_version == 3) {
xma->num_samples = read_32bitBE(xma->chunk_offset+0x14,streamFile);
/*xma->pcm_samples = read_32bitBE(xma->chunk_offset+0x18,streamFile)*/
} else {
xma->num_samples = read_32bitBE(xma->chunk_offset+0x1C,streamFile);
/*xma->pcm_samples = read_32bitBE(xma->chunk_offset+0x20,streamFile)*/
}
/* num_samples is the max samples in the file (apparently not including encoder delay) */
/* pcm_samples are original WAV's; not current since samples and sample rate may be adjusted for looping purposes */
}
else if (xma->fmt_codec == 0x166) { /* pure XMA2 */
xma->num_samples = read_32bit(xma->chunk_offset+0x18,streamFile);
xma->loop_start_sample = read_32bit(xma->chunk_offset+0x28,streamFile);
xma->loop_end_sample = xma->loop_start_sample + read_32bit(xma->chunk_offset+0x2C,streamFile);
xma->loop_flag = (uint8_t)read_8bit(xma->chunk_offset+0x30,streamFile) > 0 /* never set in practice */
|| xma->loop_end_sample;
/* play_begin+end = probably pcm_samples (for original sample rate), don't seem to affect anything */
/* int32_t play_begin_sample = read_32bit(xma->chunk_offset+0x20,streamFile); */
/* int32_t play_end_sample = play_begin_sample + read_32bit(xma->chunk_offset+0x24,streamFile); */
}
else if (xma->fmt_codec == 0x165) { /* pure XMA1 */
xma->loop_flag = (uint8_t)read_8bit(xma->chunk_offset+0xA,streamFile) > 0;
xma->loop_start_b = read_32bit(xma->chunk_offset+0x14,streamFile);
xma->loop_end_b = read_32bit(xma->chunk_offset+0x18,streamFile);
xma->loop_subframe = (uint8_t)read_8bit(xma->chunk_offset+0x1C,streamFile);
/* num_samples are parsed later */
}
else { /* unknown chunk */
goto fail;
}
return 1;
fail:
return 0;
}
static void fix_samples(xma_header_data * xma, STREAMFILE *streamFile) {
xma_sample_data xma_sd;
/* for now only XMA1 is fixed, but xmaencode.exe doesn't seem to use
* XMA2 sample values in the headers, and the exact number of samples may not be exact.
* Also loop values don't seem to need skip_samples. */
if (xma->fmt_codec != 0x165) {
return;
}
memset(&xma_sd,0,sizeof(xma_sample_data));
/* call xma parser (copy to its own struct, a bit clunky but oh well...) */
xma_sd.xma_version = xma->fmt_codec==0x165 ? 1 : 2;
xma_sd.channels = xma->channels;
xma_sd.data_offset = xma->data_offset;
xma_sd.data_size = xma->data_size;
xma_sd.loop_flag = xma->loop_flag;
xma_sd.loop_start_b = xma->loop_start_b;
xma_sd.loop_end_b = xma->loop_end_b;
xma_sd.loop_start_subframe = xma->loop_subframe & 0xF; /* lower 4b: subframe where the loop starts, 0..4 */
xma_sd.loop_end_subframe = xma->loop_subframe >> 4; /* upper 4b: subframe where the loop ends, 0..3 */
xma_get_samples(&xma_sd, streamFile);
/* and recieve results */
xma->num_samples = xma_sd.num_samples;
xma->skip_samples = xma_sd.skip_samples;
xma->loop_start_sample = xma_sd.loop_start_sample;
xma->loop_end_sample = xma_sd.loop_end_sample;
/* XMA2 loop/num_samples don't seem to skip_samples */
}
/**
* Recreates a RIFF header that FFmpeg can read since it lacks support for some variations.
*
* returns bytes written (up until "data" chunk + size), -1 on failure
*/
static int create_riff_header(uint8_t * buf, size_t buf_size, xma_header_data * xma, STREAMFILE *streamFile) {
void (*put_32bit)(uint8_t *, int32_t) = NULL;
uint8_t chunk[FAKE_RIFF_BUFFER_SIZE];
uint8_t internal[FAKE_RIFF_BUFFER_SIZE];
size_t head_size, file_size, internal_size;
int use_be = xma->big_endian && !xma->force_little_endian;
if (use_be) {
put_32bit = put_32bitBE;
} else {
put_32bit = put_32bitLE;
}
memset(buf,0, sizeof(uint8_t) * buf_size);
if (read_streamfile(chunk,xma->chunk_offset,xma->chunk_size, streamFile) != xma->chunk_size)
goto fail;
/* create internal chunks */
if (xma->xma2_version == 3) { /* old XMA2 v3: change to v4 (extra 8 bytes in the middle) */
internal_size = 4+4+xma->chunk_size + 8;
memcpy(internal + 0x0, "XMA2", 4); /* "XMA2" chunk (internal data is BE) */
put_32bit(internal + 0x4, xma->chunk_size + 8); /* v3 > v4 size*/
put_8bit(internal + 0x8, 4); /* v4 */
memcpy(internal + 0x9, chunk+1, 15); /* first v3 part (fixed) */
put_32bitBE(internal + 0x18, 0); /* extra v4 BE: "EncodeOptions" (not used by FFmpeg) */
put_32bitBE(internal + 0x1c, 0); /* extra v4 BE: "PsuedoBytesPerSec" (not used by FFmpeg) */
memcpy(internal + 0x20, chunk+16, xma->chunk_size - 16); /* second v3 part (variable) */
}
else { /* direct copy (old XMA2 v4 ignoring "fmt", pure XMA1/2) */
internal_size = 4+4+xma->chunk_size;
if (xma->force_little_endian ) {
if ( !ffmpeg_fmt_chunk_swap_endian(chunk, xma->chunk_size, xma->fmt_codec) )
goto fail;
}
memcpy(internal + 0x0, xma->xma2_version ? "XMA2" : "fmt ", 4);
put_32bit(internal + 0x4, xma->chunk_size);
memcpy(internal + 0x8, chunk, xma->chunk_size);
}
/* create main RIFF */
head_size = 4+4 + 4 + internal_size + 4+4;
file_size = head_size-4-4 + xma->data_size;
if (head_size > buf_size) goto fail;
memcpy(buf + 0x0, use_be ? "RIFX" : "RIFF", 4);
put_32bit(buf + 0x4, file_size);
memcpy(buf + 0x8, "WAVE", 4);
memcpy(buf + 0xc, internal, internal_size);
memcpy(buf + head_size-4-4, "data", 4);
put_32bit(buf + head_size-4, xma->data_size);
return head_size;
fail:
return -1;
}
#if 0
/**
* Get real XMA sample rate (from Microsoft docs).
@ -428,5 +146,3 @@ static int32_t get_xma_sample_rate(int32_t general_rate) {
return xma_rate;
}
#endif
#endif

View File

@ -5,12 +5,21 @@
/* most info from XWBtool, xactwb.h, xact2wb.h and xact3wb.h */
#define WAVEBANK_FLAGS_COMPACT 0x00020000 // Bank uses compact format
#define WAVEBANKENTRY_FLAGS_IGNORELOOP 0x00000008 // Used internally when the loop region can't be used
#define WAVEBANKENTRY_FLAGS_IGNORELOOP 0x00000008 // Used internally when the loop region can't be used (no idea...)
static const int32_t wma_avg_bps_index[] = { /*7*/
/* 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_1_MAX 3 /* 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_1_MAX 38 /* Prey (v38) */ // v39 too?
#define XACT2_2_MAX 41 /* Blue Dragon (v40) */
#define XACT3_0_MAX 46 /* Ninja Blade (t43 v42), Persona 4 Ultimax NESSICA (t45 v43) */
#define XACT_TECHLAND 0x10000 /* Sniper Ghost Warrior, Nail'd (PS3/X360) */
static const int wma_avg_bps_index[7] = {
12000, 24000, 4000, 6000, 8000, 20000, 2500
};
static const int32_t wma_block_align_index[] = { /*17*/
static const int wma_block_align_index[17] = {
929, 1487, 1280, 2230, 8917, 8192, 4459, 5945, 2304, 1536, 1485, 1008, 2731, 4096, 6827, 5462, 1280
};
@ -18,8 +27,6 @@ static const int32_t wma_block_align_index[] = { /*17*/
typedef enum { PCM, XBOX_ADPCM, MS_ADPCM, XMA1, XMA2, WMA, XWMA, ATRAC3 } xact_codec;
typedef struct {
int little_endian;
int xact; /* rough XACT version (1/2/3) */
int version;
/* segments */
@ -83,43 +90,47 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* read main header (WAVEBANKHEADER) */
xwb.version = read_32bit(0x04, streamFile);
if (xwb.version <= 3) {
xwb.xact = 1; /* XACT1: XBOX [The King of Fighters 2003] */
} else if (xwb.version < 42) {
xwb.xact = 2; /* XACT2: early XBOX360 [Kameo, Table Tennis, Blue Dragon], Windows */
} else { /* highest seen: tool=v46, header=v44 */
xwb.xact = 3; /* XACT3: late XBOX360, Windows */
}
xwb.version = read_32bit(0x04, streamFile); /* XACT3: 0x04=tool version, 0x08=header version */
/* read segment offsets (SEGIDX) */
off = xwb.xact <= 2 ? 0x08 : 0x0c; /* XACT3: 0x04=tool version, 0x08=header version */
xwb.base_offset = read_32bit(off+0x00, streamFile);//BANKDATA
xwb.base_size = read_32bit(off+0x04, streamFile);
xwb.entry_offset= read_32bit(off+0x08, streamFile);//ENTRYMETADATA
xwb.entry_size = read_32bit(off+0x0c, streamFile);
/* go to last segment (XACT2/3 have 5 segments, XACT1 4) */
//0x10: XACT1/2: ENTRYNAMES, XACT3: SEEKTABLES
//0x14: XACT1: none (ENTRYWAVEDATA), XACT2: EXTRA, XACT3: ENTRYNAMES
suboff = xwb.xact >= 2 ? 0x08+0x08 : 0x08;
xwb.data_offset = read_32bit(off+0x10+suboff, streamFile);//ENTRYWAVEDATA
xwb.data_size = read_32bit(off+0x14+suboff, streamFile);
if (xwb.version <= XACT1_0_MAX) {
xwb.streams = read_32bit(0x0c, streamFile);
/* 0x10: bank name */
xwb.entry_elem_size = 0x14;
xwb.entry_offset= 0x50;
xwb.entry_size = xwb.entry_elem_size * xwb.streams;
xwb.data_offset = xwb.entry_offset + xwb.entry_size;
xwb.data_size = get_streamfile_size(streamFile) - xwb.data_offset;
}
else {
off = xwb.version <= XACT2_2_MAX ? 0x08 : 0x0c;
xwb.base_offset = read_32bit(off+0x00, streamFile);//BANKDATA
xwb.base_size = read_32bit(off+0x04, streamFile);
xwb.entry_offset= read_32bit(off+0x08, streamFile);//ENTRYMETADATA
xwb.entry_size = read_32bit(off+0x0c, streamFile);
/* go to last segment (XACT2/3 have 5 segments, XACT1 4) */
//0x10: XACT1/2: ENTRYNAMES, XACT3: SEEKTABLES
//0x14: XACT1: none (ENTRYWAVEDATA), XACT2: EXTRA, XACT3: ENTRYNAMES
suboff = xwb.version <= XACT1_1_MAX ? 0x08 : 0x08+0x08;
xwb.data_offset = read_32bit(off+0x10+suboff, streamFile);//ENTRYWAVEDATA
xwb.data_size = read_32bit(off+0x14+suboff, streamFile);
/* for Silent Hill 4 Xbox fake XWB and Techland's XWB with no data */
if (xwb.base_offset == 0) goto fail;
if (xwb.data_offset + xwb.data_size != get_streamfile_size(streamFile)) goto fail;
/* for Techland's XWB with no data */
if (xwb.base_offset == 0) goto fail;
if (xwb.data_offset + xwb.data_size != get_streamfile_size(streamFile)) goto fail;
/* read base entry (WAVEBANKDATA) */
off = xwb.base_offset;
xwb.base_flags = (uint32_t)read_32bit(off+0x00, streamFile);
xwb.streams = read_32bit(off+0x04, streamFile);
/* 0x08 bank_name */
suboff = 0x08 + (xwb.xact == 1 ? 0x10 : 0x40);
xwb.entry_elem_size = read_32bit(off+suboff+0x00, streamFile);
/* suboff+0x04: meta name entry size */
xwb.entry_alignment = read_32bit(off+suboff+0x08, streamFile); /* usually 1 dvd sector */
xwb.format = read_32bit(off+suboff+0x0c, streamFile); /* compact mode only */
/* suboff+0x10: build time 64b (XACT2/3) */
/* read base entry (WAVEBANKDATA) */
off = xwb.base_offset;
xwb.base_flags = (uint32_t)read_32bit(off+0x00, streamFile);
xwb.streams = read_32bit(off+0x04, streamFile);
/* 0x08 bank_name */
suboff = 0x08 + (xwb.version <= XACT1_1_MAX ? 0x10 : 0x40);
xwb.entry_elem_size = read_32bit(off+suboff+0x00, streamFile);
/* suboff+0x04: meta name entry size */
xwb.entry_alignment = read_32bit(off+suboff+0x08, streamFile); /* usually 1 dvd sector */
xwb.format = read_32bit(off+suboff+0x0c, streamFile); /* compact mode only */
/* suboff+0x10: build time 64b (XACT2/3) */
}
if (target_stream == 0) target_stream = 1; /* auto: default to 1 */
if (target_stream < 0 || target_stream > xwb.streams || xwb.streams < 1) goto fail;
@ -142,27 +153,34 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
xwb.stream_size = xwb.data_size;
}
}
else if (xwb.version <= XACT1_0_MAX) {
xwb.format = (uint32_t)read_32bit(off+0x00, streamFile);
xwb.stream_offset = xwb.data_offset + (uint32_t)read_32bit(off+0x04, streamFile);
xwb.stream_size = (uint32_t)read_32bit(off+0x08, streamFile);
xwb.loop_start = (uint32_t)read_32bit(off+0x0c, streamFile);
xwb.loop_end = (uint32_t)read_32bit(off+0x10, streamFile);//length
xwb.loop_flag = (xwb.loop_end > 0 || xwb.loop_end_sample > xwb.loop_start);
}
else {
uint32_t entry_info = (uint32_t)read_32bit(off+0x00, streamFile);
if (xwb.xact == 1) {
if (xwb.version <= XACT1_1_MAX) {
xwb.entry_flags = entry_info;
} else {
xwb.entry_flags = (entry_info) & 0xF; /*4*/
xwb.num_samples = (entry_info >> 4) & 0x0FFFFFFF; /*28*/
xwb.entry_flags = (entry_info) & 0xF; /*4b*/
xwb.num_samples = (entry_info >> 4) & 0x0FFFFFFF; /*28b*/
}
xwb.format = (uint32_t)read_32bit(off+0x04, streamFile);
xwb.stream_offset = xwb.data_offset + (uint32_t)read_32bit(off+0x08, streamFile);
xwb.stream_size = (uint32_t)read_32bit(off+0x0c, streamFile);
if (xwb.xact == 1) { //LoopRegion (bytes within data)
if (xwb.version <= XACT2_1_MAX) { /* LoopRegion (bytes) */
xwb.loop_start = (uint32_t)read_32bit(off+0x10, streamFile);
xwb.loop_end = (uint32_t)read_32bit(off+0x14, streamFile);//length
} else if (xwb.xact == 2 && xwb.version <= 38) {//LoopRegion (bytes within data) or XMALoopRegion (bits within data)
xwb.loop_start = (uint32_t)read_32bit(off+0x10, streamFile);
xwb.loop_end = (uint32_t)read_32bit(off+0x14, streamFile);//length (LoopRegion) or offset (XMALoopRegion)
} else {//LoopRegion (samples)
xwb.loop_end = (uint32_t)read_32bit(off+0x14, streamFile);//length (LoopRegion) or offset (XMALoopRegion in late XACT2)
} else { /* LoopRegion (samples) */
xwb.loop_start_sample = (uint32_t)read_32bit(off+0x10, streamFile);
xwb.loop_end_sample = xwb.loop_start_sample + (uint32_t)read_32bit(off+0x14, streamFile);
xwb.loop_end_sample = (uint32_t)read_32bit(off+0x14, streamFile) + xwb.loop_start_sample;
}
xwb.loop_flag = (xwb.loop_end > 0 || xwb.loop_end_sample > xwb.loop_start)
@ -171,40 +189,52 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* parse format */
if (xwb.xact == 1) {
xwb.bits_per_sample = (xwb.format >> 31) & 0x1; /*1*/
xwb.sample_rate = (xwb.format >> 5) & 0x3FFFFFF; /*26*/
xwb.channels = (xwb.format >> 2) & 0x7; /*3*/
xwb.tag = (xwb.format) & 0x3; /*2*/
if (xwb.version <= XACT1_0_MAX) {
xwb.bits_per_sample = (xwb.format >> 31) & 0x1; /*1b*/
xwb.sample_rate = (xwb.format >> 4) & 0x7FFFFFF; /*27b*/
xwb.channels = (xwb.format >> 1) & 0x7; /*3b*/
xwb.tag = (xwb.format) & 0x1; /*1b*/
}
else if (xwb.version <= 34) { /* early XACT2, not sure if includes v35/36 */
xwb.bits_per_sample = (xwb.format >> 31) & 0x1; /*1*/
xwb.block_align = (xwb.format >> 24) & 0xFF; /*8*/
xwb.sample_rate = (xwb.format >> 4) & 0x7FFFF; /*19*/
xwb.channels = (xwb.format >> 1) & 0x7; /*3*/
xwb.tag = (xwb.format) & 0x1; /*1*/
else if (xwb.version <= XACT1_1_MAX) {
xwb.bits_per_sample = (xwb.format >> 31) & 0x1; /*1b*/
xwb.sample_rate = (xwb.format >> 5) & 0x3FFFFFF; /*26b*/
xwb.channels = (xwb.format >> 2) & 0x7; /*3b*/
xwb.tag = (xwb.format) & 0x3; /*2b*/
}
else if (xwb.version <= XACT2_0_MAX) {
xwb.bits_per_sample = (xwb.format >> 31) & 0x1; /*1b*/
xwb.block_align = (xwb.format >> 24) & 0xFF; /*8b*/
xwb.sample_rate = (xwb.format >> 4) & 0x7FFFF; /*19b*/
xwb.channels = (xwb.format >> 1) & 0x7; /*3b*/
xwb.tag = (xwb.format) & 0x1; /*1b*/
}
else {
xwb.bits_per_sample = (xwb.format >> 31) & 0x1; /*1*/
xwb.block_align = (xwb.format >> 23) & 0xFF; /*8*/
xwb.sample_rate = (xwb.format >> 5) & 0x3FFFF; /*18*/
xwb.channels = (xwb.format >> 2) & 0x7; /*3*/
xwb.tag = (xwb.format) & 0x3; /*2*/
xwb.bits_per_sample = (xwb.format >> 31) & 0x1; /*1b*/
xwb.block_align = (xwb.format >> 23) & 0xFF; /*8b*/
xwb.sample_rate = (xwb.format >> 5) & 0x3FFFF; /*18b*/
xwb.channels = (xwb.format >> 2) & 0x7; /*3b*/
xwb.tag = (xwb.format) & 0x3; /*2b*/
}
/* standardize tag to codec */
if (xwb.xact == 1) {
if (xwb.version <= XACT1_0_MAX) {
switch(xwb.tag){
case 0: xwb.codec = PCM; break;
case 1: xwb.codec = XBOX_ADPCM; break;
default: goto fail;
}
} else if (xwb.version <= XACT1_1_MAX) {
switch(xwb.tag){
case 0: xwb.codec = PCM; break;
case 1: xwb.codec = XBOX_ADPCM; break;
case 2: xwb.codec = WMA; break;
default: goto fail;
}
} else if (xwb.xact == 2) {
} else if (xwb.version <= XACT2_2_MAX) {
switch(xwb.tag) {
case 0: xwb.codec = PCM; break;
/* Table Tennis (v34): XMA1, Prey (v38): XMA2, v35/36/37: ? */
case 1: xwb.codec = xwb.version <= 34 ? XMA1 : XMA2; break;
case 1: xwb.codec = xwb.version <= XACT2_0_MAX ? XMA1 : XMA2; break;
case 2: xwb.codec = MS_ADPCM; break;
default: goto fail;
}
@ -220,60 +250,59 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* Techland's bizarre format hijack (Nail'd, Sniper: Ghost Warrior PS3).
* Somehow they used XWB + ATRAC3 in their PS3 games, very creative */
if (xwb.version == 0x10000 && xwb.codec == XMA2 /* v 0x10000 is used in their X360 games too */
if (xwb.version == XACT_TECHLAND && xwb.codec == XMA2 /* XACT_TECHLAND used in their X360 games too */
&& (xwb.block_align == 0x60 || xwb.block_align == 0x98 || xwb.block_align == 0xc0) ) {
xwb.codec = ATRAC3; /* standard ATRAC3 blocks sizes; no other way to identify (other than reading data) */
/* num samples uses a modified entry_info format (maybe skip samples + samples? sfx use the standard format)
* ignore for now and just calc max samples */ //todo
xwb.num_samples = xwb.stream_size / (xwb.block_align * xwb.channels) * 1024;
* ignore for now and just calc max samples */
xwb.num_samples = atrac3_bytes_to_samples(xwb.stream_size, xwb.block_align * xwb.channels);
}
/* fix samples */
if ((xwb.xact == 1 || xwb.xact == 2) && xwb.codec == PCM) {
xwb.num_samples = xwb.stream_size / 2 / xwb.channels;
if (xwb.version <= XACT2_2_MAX && xwb.codec == PCM) {
int bits_per_sample = xwb.bits_per_sample == 0 ? 8 : 16;
xwb.num_samples = pcm_bytes_to_samples(xwb.stream_size, xwb.channels, bits_per_sample);
if (xwb.loop_flag) {
xwb.loop_start_sample = (xwb.loop_start) / 2 / xwb.channels;
xwb.loop_end_sample = (xwb.loop_start + xwb.loop_end) / 2 / xwb.channels;
xwb.loop_start_sample = pcm_bytes_to_samples(xwb.loop_start, xwb.channels, bits_per_sample);
xwb.loop_end_sample = pcm_bytes_to_samples(xwb.loop_start + xwb.loop_end, xwb.channels, bits_per_sample);
}
}
else if (xwb.xact == 1 && xwb.codec == XBOX_ADPCM) {
xwb.num_samples = xwb.stream_size / 36 / xwb.channels*64;
else if (xwb.version <= XACT1_1_MAX && xwb.codec == XBOX_ADPCM) {
xwb.block_align = 0x24 * xwb.channels;
xwb.num_samples = ms_ima_bytes_to_samples(xwb.stream_size, xwb.block_align, xwb.channels);
if (xwb.loop_flag) {
xwb.loop_start_sample = xwb.loop_start / 36 / xwb.channels*64;
xwb.loop_end_sample = (xwb.loop_start + xwb.loop_end) / 36 / xwb.channels*64;
xwb.loop_start_sample = ms_ima_bytes_to_samples(xwb.loop_start, xwb.block_align, xwb.channels);
xwb.loop_end_sample = ms_ima_bytes_to_samples(xwb.loop_start + xwb.loop_end, xwb.block_align, xwb.channels);
}
}
else if (xwb.xact == 2 && xwb.codec == MS_ADPCM && xwb.loop_flag) {
int block_size, samples_per_frame;
block_size = (xwb.block_align + 22) * xwb.channels; /*22=CONVERSION_OFFSET (?)*/
samples_per_frame = (block_size-(7-1) * xwb.channels) * 2 / xwb.channels;
else if (xwb.version <= XACT2_2_MAX && xwb.codec == MS_ADPCM && xwb.loop_flag) {
int block_size = (xwb.block_align + 22) * xwb.channels; /*22=CONVERSION_OFFSET (?)*/
xwb.loop_start_sample = (xwb.loop_start) / block_size / samples_per_frame;
xwb.loop_end_sample = (xwb.loop_start + xwb.loop_end) / block_size / samples_per_frame;
xwb.loop_start_sample = msadpcm_bytes_to_samples(xwb.loop_start, block_size, xwb.channels);
xwb.loop_end_sample = msadpcm_bytes_to_samples(xwb.loop_start + xwb.loop_end, block_size, xwb.channels);
}
else if (xwb.xact == 2 && xwb.version <= 38 /* v38: byte offset, v40+: sample offset, v39: ? */
&& (xwb.codec == XMA1 || xwb.codec == XMA2) && xwb.loop_flag) {
#ifdef VGM_USE_FFMPEG
else if (xwb.version <= XACT2_1_MAX && (xwb.codec == XMA1 || xwb.codec == XMA2) && xwb.loop_flag) {
/* v38: byte offset, v40+: sample offset, v39: ? */
/* need to manually find sample offsets, thanks to Microsoft dumb headers */
xma_sample_data xma_sd;
memset(&xma_sd,0,sizeof(xma_sample_data));
ms_sample_data msd;
memset(&msd,0,sizeof(ms_sample_data));
xma_sd.xma_version = xwb.codec == XMA1 ? 1 : 2;
xma_sd.channels = xwb.channels;
xma_sd.data_offset = xwb.stream_offset;
xma_sd.data_size = xwb.stream_size;
xma_sd.loop_flag = xwb.loop_flag;
xma_sd.loop_start_b = xwb.loop_start; /* bit offset in the stream */
xma_sd.loop_end_b = (xwb.loop_end >> 4); /*28b */
msd.xma_version = xwb.codec == XMA1 ? 1 : 2;
msd.channels = xwb.channels;
msd.data_offset = xwb.stream_offset;
msd.data_size = xwb.stream_size;
msd.loop_flag = xwb.loop_flag;
msd.loop_start_b = xwb.loop_start; /* bit offset in the stream */
msd.loop_end_b = (xwb.loop_end >> 4); /*28b */
/* XACT adds +1 to the subframe, but this means 0 can't be used? */
xma_sd.loop_end_subframe = ((xwb.loop_end >> 2) & 0x3) + 1; /* 2b */
xma_sd.loop_start_subframe = ((xwb.loop_end >> 0) & 0x3) + 1; /* 2b */
msd.loop_end_subframe = ((xwb.loop_end >> 2) & 0x3) + 1; /* 2b */
msd.loop_start_subframe = ((xwb.loop_end >> 0) & 0x3) + 1; /* 2b */
xma_get_samples(&xma_sd, streamFile);
xwb.loop_start_sample = xma_sd.loop_start_sample;
xwb.loop_end_sample = xma_sd.loop_end_sample;
xma_get_samples(&msd, streamFile);
xwb.loop_start_sample = msd.loop_start_sample;
xwb.loop_end_sample = msd.loop_end_sample;
// todo fix properly (XWB loop_start/end seem to count padding samples while XMA1 RIFF doesn't)
//this doesn't seem ok because can fall within 0 to 512 (ie.- first frame)
@ -283,9 +312,6 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
//add padding back until it's fixed (affects looping)
// (in rare cases this causes a glitch in FFmpeg since it has a bug where it's missing some samples)
xwb.num_samples += 64 + 512;
#else
goto fail;
#endif
}
@ -296,7 +322,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
vgmstream->sample_rate = xwb.sample_rate;
vgmstream->num_samples = xwb.num_samples;
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->meta_type = meta_XWB;
@ -380,7 +406,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
block_align = wma_block_align_index[block_index];
wma_codec = xwb.bits_per_sample ? 0x162 : 0x161; /* 0=WMAudio2, 1=WMAudio3 */
bytes = ffmpeg_make_riff_xwma(buf, 100, wma_codec, vgmstream->num_samples, 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;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, xwb.stream_offset,xwb.stream_size);

View File

@ -3,7 +3,7 @@
#include "streamtypes.h"
int check_sample_rate(int32_t sr) {
return !(sr<1000 || sr>96000);
return !(sr<300 || sr>96000);
}
const char * filename_extension(const char * filename) {

View File

@ -11,6 +11,12 @@
#include "layout/layout.h"
#include "coding/coding.h"
/* See if there is a second file which may be the second channel, given
* already opened mono opened_stream which was opened from filename.
* If a suitable file is found, open it and change opened_stream to a stereo stream. */
static void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFile);
/*
* List of functions that will recognize files. These should correspond pretty
* directly to the metadata types
@ -342,9 +348,14 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_akb2_multi,
init_vgmstream_x360_ast,
init_vgmstream_wwise,
init_vgmstream_ubi_raki,
init_vgmstream_x360_pasx,
init_vgmstream_x360_nub,
init_vgmstream_xma,
init_vgmstream_sxd,
init_vgmstream_ogl,
#ifdef VGM_USE_FFMPEG
init_vgmstream_xma,
init_vgmstream_mp4_aac_ffmpeg,
init_vgmstream_bik,
@ -371,6 +382,7 @@ VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) {
/* fail if there is nothing to play
* (without this check vgmstream can generate empty files) */
if (vgmstream->num_samples <= 0) {
VGM_LOG("VGMSTREAM: wrong num_samples (ns=%i)\n", vgmstream->num_samples);
close_vgmstream(vgmstream);
continue;
}
@ -378,6 +390,7 @@ VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) {
/* everything should have a reasonable sample rate
* (a verification of the metadata) */
if (!check_sample_rate(vgmstream->sample_rate)) {
VGM_LOG("VGMSTREAM: wrong sample rate (sr=%i)\n", vgmstream->sample_rate);
close_vgmstream(vgmstream);
continue;
}
@ -388,7 +401,7 @@ VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) {
|| (vgmstream->loop_end_sample > vgmstream->num_samples)
|| (vgmstream->loop_start_sample < 0) ) {
vgmstream->loop_flag = 0;
VGM_LOG("VGMSTREAM: wrong loops ignored (lss==%i, lse=%i, ns=%i)\n", vgmstream->loop_start_sample, vgmstream->loop_end_sample, vgmstream->num_samples);
VGM_LOG("VGMSTREAM: wrong loops ignored (lss=%i, lse=%i, ns=%i)\n", vgmstream->loop_start_sample, vgmstream->loop_end_sample, vgmstream->num_samples);
}
}
@ -476,6 +489,14 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
if (vgmstream->coding_type==coding_fsb_vorbis) {
reset_fsb_vorbis(vgmstream);
}
if (vgmstream->coding_type==coding_wwise_vorbis) {
reset_wwise_vorbis(vgmstream);
}
if (vgmstream->coding_type==coding_ogl_vorbis) {
reset_ogl_vorbis(vgmstream);
}
#endif
if (vgmstream->coding_type==coding_CRI_HCA) {
hca_codec_data *data = vgmstream->codec_data;
@ -679,6 +700,16 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
free_fsb_vorbis(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
if (vgmstream->coding_type==coding_wwise_vorbis) {
free_wwise_vorbis(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
if (vgmstream->coding_type==coding_ogl_vorbis) {
free_ogl_vorbis(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
#endif
if (vgmstream->coding_type==coding_CRI_HCA) {
@ -1000,6 +1031,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
#ifdef VGM_USE_VORBIS
case coding_ogg_vorbis:
case coding_fsb_vorbis:
case coding_wwise_vorbis:
case coding_ogl_vorbis:
#endif
#ifdef VGM_USE_MPEG
case coding_fake_MPEG2_L2:
@ -1070,6 +1103,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
return 64;
case coding_MS_IMA:
case coding_RAD_IMA:
case coding_WWISE_IMA:
return (vgmstream->interleave_block_size-4*vgmstream->channels)*2/vgmstream->channels;
case coding_RAD_IMA_mono:
return 32;
@ -1159,6 +1193,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_RAD_IMA:
case coding_NDS_IMA:
case coding_DAT4_IMA:
case coding_WWISE_IMA:
return vgmstream->interleave_block_size;
case coding_RAD_IMA_mono:
return 0x14;
@ -1484,6 +1519,18 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
buffer+samples_written*vgmstream->channels,samples_to_do,
vgmstream->channels);
break;
case coding_wwise_vorbis:
decode_wwise_vorbis(vgmstream,
buffer+samples_written*vgmstream->channels,samples_to_do,
vgmstream->channels);
break;
case coding_ogl_vorbis:
decode_ogl_vorbis(vgmstream,
buffer+samples_written*vgmstream->channels,samples_to_do,
vgmstream->channels);
break;
#endif
case coding_CRI_HCA:
decode_hca(vgmstream->codec_data,
@ -1584,6 +1631,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
samples_to_do,chan);
}
break;
case coding_WWISE_IMA:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_wwise_ima(vgmstream,&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do,chan);
}
break;
case coding_WS:
for (chan=0;chan<vgmstream->channels;chan++) {
@ -1798,6 +1852,14 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
if (vgmstream->coding_type==coding_fsb_vorbis) {
seek_fsb_vorbis(vgmstream, vgmstream->loop_start_sample);
}
if (vgmstream->coding_type==coding_wwise_vorbis) {
seek_wwise_vorbis(vgmstream, vgmstream->loop_start_sample);
}
if (vgmstream->coding_type==coding_ogl_vorbis) {
seek_ogl_vorbis(vgmstream, vgmstream->loop_start_sample);
}
#endif
#ifdef VGM_USE_FFMPEG
@ -1994,7 +2056,7 @@ const char * const dfs_pairs[][2] = {
};
#define DFS_PAIR_COUNT (sizeof(dfs_pairs)/sizeof(dfs_pairs[0]))
void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFile) {
static void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFile) {
char filename[PATH_LIMIT];
char filename2[PATH_LIMIT];
char * ext;

View File

@ -130,9 +130,10 @@ typedef enum {
coding_SNDS_IMA, /* Heavy Iron Studios .snds IMA ADPCM */
coding_OTNS_IMA, /* Omikron The Nomad Soul IMA ADPCM */
coding_FSB_IMA, /* FMOD's FSB multichannel IMA ADPCM */
coding_WWISE_IMA, /* Audiokinetic Wwise IMA ADPCM */
coding_WS, /* Westwood Studios VBR ADPCM */
coding_MSADPCM, /* Microsoft ADPCM */
coding_WS, /* Westwood Studios VBR ADPCM */
coding_AICA, /* Yamaha AICA ADPCM */
coding_L5_555, /* Level-5 0x555 ADPCM */
coding_SASSC, /* Activision EXAKT SASSC DPCM */
@ -158,7 +159,9 @@ typedef enum {
#ifdef VGM_USE_VORBIS
coding_ogg_vorbis, /* Xiph Vorbis (MDCT-based) */
coding_fsb_vorbis, /* FMOD's Vorbis without Ogg layer */
coding_fsb_vorbis, /* FMOD Vorbis without Ogg layer */
coding_wwise_vorbis, /* Audiokinetic Vorbis without Ogg layer */
coding_ogl_vorbis, /* Shin'en Vorbis without Ogg layer */
#endif
#ifdef VGM_USE_MPEG
@ -441,7 +444,7 @@ typedef enum {
meta_PS2_XA2_RRP, /* RC Revenge Pro */
meta_PS2_STM, /* Red Dead Revolver .stm, renamed .ps2stm */
meta_NGC_DSP_KONAMI, /* Konami DSP header, found in various games */
meta_UBI_CKD, /* Ubisoft CKD RIFF header from Rayman Origins */
meta_UBI_CKD, /* Ubisoft CKD RIFF header (Rayman Origins Wii) */
meta_XBOX_WAVM, /* XBOX WAVM File */
meta_XBOX_RIFF, /* XBOX RIFF/WAVE File */
@ -608,6 +611,9 @@ typedef enum {
meta_XMA_RIFF, /* Microsoft RIFF XMA */
meta_X360_AST, /* Dead Rising (X360) */
meta_WWISE_RIFF, /* Audiokinetic Wwise RIFF/RIFX */
meta_UBI_RAKI, /* Ubisoft RAKI header (Rayman Legends, Just Dance 2017) */
meta_SXD, /* Sony SXD (Gravity Rush, Freedom Wars PSV) */
meta_OGL, /* Shin'en Wii/WiiU (Jett Rocket (Wii), FAST Racing NEO (WiiU)) */
#ifdef VGM_USE_VORBIS
meta_OGG_VORBIS, /* Ogg Vorbis */
@ -729,6 +735,8 @@ typedef struct {
off_t loop_next_block_offset; /* saved from next_block_offset */
/* decoder specific */
int codec_endian; /* little/big endian marker; name is left vague but usually means big endian */
uint8_t xa_channel; /* XA ADPCM: selected channel */
int32_t xa_sector_length; /* XA ADPCM: XA block */
uint8_t xa_headerless; /* XA ADPCM: headerless XA block */
@ -776,8 +784,13 @@ typedef struct {
ogg_vorbis_streamfile ov_streamfile;
} ogg_vorbis_codec_data;
/* config for Wwise Vorbis */
typedef enum { HEADER_TRIAD, FULL_SETUP, INLINE_CODEBOOKS, EXTERNAL_CODEBOOKS, AOTUV603_CODEBOOKS } wwise_setup_type;
typedef enum { TYPE_8, TYPE_6, TYPE_2 } wwise_header_type;
typedef enum { STANDARD, MODIFIED } wwise_packet_type;
/* any raw Vorbis without Ogg layer */
typedef struct {
typedef struct {
vorbis_info vi; /* stream settings */
vorbis_comment vc; /* stream comments */
vorbis_dsp_state vd; /* decoder global state */
@ -788,6 +801,16 @@ typedef struct {
size_t buffer_size;
size_t samples_to_discard; /* for looping purposes */
int samples_full; /* flag, samples available in vorbis buffers */
/* Wwise Vorbis config */
wwise_setup_type setup_type;
wwise_header_type header_type;
wwise_packet_type packet_type;
/* saved data to reconstruct modified packets */
uint8_t mode_blockflag[64+1]; /* max 6b+1; flags 'n stuff */
int mode_bits; /* bits to store mode_number */
uint8_t prev_blockflag; /* blockflag in the last decoded packet */
} vorbis_codec_data;
#endif
@ -1053,12 +1076,6 @@ int vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMST
* Returns 1 if loop was done. */
int vgmstream_do_loop(VGMSTREAM * vgmstream);
/* See if there is a second file which may be the second channel, given
* already opened mono opened_stream which was opened from filename.
* If a suitable file is found, open it and change opened_stream to a stereo stream. */
void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFile);
/* Open the stream for reading at offset (standarized taking into account layouts, channels and so on).
* returns 0 on failure */
int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t start_offset);