Browse Source

Updated VGMStream to r1050-3043-g295ffac0

master
Christopher Snowhill 3 weeks ago
parent
commit
ebfb7e1207
40 changed files with 4310 additions and 2332 deletions
  1. +35
    -7
      Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj
  2. +1
    -0
      Frameworks/vgmstream/vgmstream/src/coding/coding.h
  3. +2
    -0
      Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c
  4. +18
    -0
      Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c
  5. +11
    -5
      Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c
  6. +10
    -3
      Frameworks/vgmstream/vgmstream/src/formats.c
  7. +6
    -6
      Frameworks/vgmstream/vgmstream/src/layout/blocked_ubi_sce.c
  8. +670
    -641
      Frameworks/vgmstream/vgmstream/src/meta/acb.c
  9. +14
    -12
      Frameworks/vgmstream/vgmstream/src/meta/aix.c
  10. +9
    -2
      Frameworks/vgmstream/vgmstream/src/meta/bnsf_keys.h
  11. +11
    -9
      Frameworks/vgmstream/vgmstream/src/meta/deblock_streamfile.c
  12. +4
    -2
      Frameworks/vgmstream/vgmstream/src/meta/deblock_streamfile.h
  13. +3
    -0
      Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c
  14. +1
    -9
      Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c
  15. +92
    -52
      Frameworks/vgmstream/vgmstream/src/meta/ffmpeg.c
  16. +606
    -600
      Frameworks/vgmstream/vgmstream/src/meta/fsb.c
  17. +65
    -61
      Frameworks/vgmstream/vgmstream/src/meta/fsb5.c
  18. +74
    -54
      Frameworks/vgmstream/vgmstream/src/meta/fsb5_fev.c
  19. +85
    -164
      Frameworks/vgmstream/vgmstream/src/meta/fsb_encrypted.c
  20. +73
    -0
      Frameworks/vgmstream/vgmstream/src/meta/fsb_encrypted_streamfile.h
  21. +3
    -0
      Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h
  22. +82
    -0
      Frameworks/vgmstream/vgmstream/src/meta/kat.c
  23. +566
    -0
      Frameworks/vgmstream/vgmstream/src/meta/ktsr.c
  24. +11
    -1
      Frameworks/vgmstream/vgmstream/src/meta/meta.h
  25. +42
    -0
      Frameworks/vgmstream/vgmstream/src/meta/mups.c
  26. +102
    -0
      Frameworks/vgmstream/vgmstream/src/meta/mups_streamfile.h
  27. +0
    -42
      Frameworks/vgmstream/vgmstream/src/meta/ngc_dsp_std.c
  28. +68
    -0
      Frameworks/vgmstream/vgmstream/src/meta/pcm_success.c
  29. +1
    -3
      Frameworks/vgmstream/vgmstream/src/meta/ps2_joe.c
  30. +18
    -5
      Frameworks/vgmstream/vgmstream/src/meta/riff.c
  31. +51
    -0
      Frameworks/vgmstream/vgmstream/src/meta/sadf.c
  32. +16
    -18
      Frameworks/vgmstream/vgmstream/src/meta/sadl.c
  33. +42
    -27
      Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c
  34. +1434
    -547
      Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c
  35. +51
    -49
      Frameworks/vgmstream/vgmstream/src/meta/xvag.c
  36. +8
    -2
      Frameworks/vgmstream/vgmstream/src/streamfile.c
  37. +8
    -2
      Frameworks/vgmstream/vgmstream/src/util.c
  38. +5
    -7
      Frameworks/vgmstream/vgmstream/src/util.h
  39. +7
    -0
      Frameworks/vgmstream/vgmstream/src/vgmstream.c
  40. +5
    -2
      Frameworks/vgmstream/vgmstream/src/vgmstream.h

+ 35
- 7
Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj View File

@@ -312,7 +312,6 @@
836F6FA318BDC2190095E648 /* naomi_spsd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6718BDC2180095E648 /* naomi_spsd.c */; };
836F6FA418BDC2190095E648 /* nds_hwas.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6818BDC2180095E648 /* nds_hwas.c */; };
836F6FA518BDC2190095E648 /* nds_rrds.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6918BDC2180095E648 /* nds_rrds.c */; };
836F6FA618BDC2190095E648 /* nds_sad.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6A18BDC2180095E648 /* nds_sad.c */; };
836F6FA718BDC2190095E648 /* nds_strm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6B18BDC2180095E648 /* nds_strm.c */; };
836F6FA818BDC2190095E648 /* nds_swav.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6C18BDC2180095E648 /* nds_swav.c */; };
836F6FA918BDC2190095E648 /* ngc_adpdtk.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E6D18BDC2180095E648 /* ngc_adpdtk.c */; };
@@ -579,6 +578,14 @@
83C7282922BC8C1500678B4A /* mixing.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7282522BC8C1400678B4A /* mixing.c */; };
83C7282A22BC8C1500678B4A /* plugins.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C7282622BC8C1400678B4A /* plugins.c */; };
83CD428A1F787879000F77BE /* libswresample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83CD42851F787878000F77BE /* libswresample.a */; };
83D2007A248DDB770048BD24 /* fsb_encrypted_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83D20072248DDB760048BD24 /* fsb_encrypted_streamfile.h */; };
83D2007B248DDB770048BD24 /* mups_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83D20073248DDB760048BD24 /* mups_streamfile.h */; };
83D2007C248DDB770048BD24 /* ktsr.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20074248DDB760048BD24 /* ktsr.c */; };
83D2007D248DDB770048BD24 /* kat.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20075248DDB760048BD24 /* kat.c */; };
83D2007E248DDB770048BD24 /* pcm_success.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20076248DDB770048BD24 /* pcm_success.c */; };
83D2007F248DDB770048BD24 /* mups.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20077248DDB770048BD24 /* mups.c */; };
83D20080248DDB770048BD24 /* sadf.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20078248DDB770048BD24 /* sadf.c */; };
83D20081248DDB770048BD24 /* sadl.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D20079248DDB770048BD24 /* sadl.c */; };
83D2F58E2356B266007646ED /* libopus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D2F58A2356B266007646ED /* libopus.a */; };
83D731891A749D1500CA1366 /* g719.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D7313E1A74968A00CA1366 /* g719.framework */; };
83D7318A1A749D2200CA1366 /* g719.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83D7313E1A74968A00CA1366 /* g719.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -1019,7 +1026,6 @@
836F6E6718BDC2180095E648 /* naomi_spsd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = naomi_spsd.c; sourceTree = "<group>"; };
836F6E6818BDC2180095E648 /* nds_hwas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_hwas.c; sourceTree = "<group>"; };
836F6E6918BDC2180095E648 /* nds_rrds.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_rrds.c; sourceTree = "<group>"; };
836F6E6A18BDC2180095E648 /* nds_sad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_sad.c; sourceTree = "<group>"; };
836F6E6B18BDC2180095E648 /* nds_strm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_strm.c; sourceTree = "<group>"; };
836F6E6C18BDC2180095E648 /* nds_swav.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_swav.c; sourceTree = "<group>"; };
836F6E6D18BDC2180095E648 /* ngc_adpdtk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_adpdtk.c; sourceTree = "<group>"; };
@@ -1285,6 +1291,14 @@
83C7282522BC8C1400678B4A /* mixing.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mixing.c; sourceTree = "<group>"; };
83C7282622BC8C1400678B4A /* plugins.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = plugins.c; sourceTree = "<group>"; };
83CD42851F787878000F77BE /* libswresample.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libswresample.a; path = ../../ThirdParty/ffmpeg/lib/libswresample.a; sourceTree = "<group>"; };
83D20072248DDB760048BD24 /* fsb_encrypted_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fsb_encrypted_streamfile.h; sourceTree = "<group>"; };
83D20073248DDB760048BD24 /* mups_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mups_streamfile.h; sourceTree = "<group>"; };
83D20074248DDB760048BD24 /* ktsr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ktsr.c; sourceTree = "<group>"; };
83D20075248DDB760048BD24 /* kat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kat.c; sourceTree = "<group>"; };
83D20076248DDB770048BD24 /* pcm_success.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pcm_success.c; sourceTree = "<group>"; };
83D20077248DDB770048BD24 /* mups.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mups.c; sourceTree = "<group>"; };
83D20078248DDB770048BD24 /* sadf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sadf.c; sourceTree = "<group>"; };
83D20079248DDB770048BD24 /* sadl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sadl.c; sourceTree = "<group>"; };
83D2F58A2356B266007646ED /* libopus.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libopus.a; path = ../../ThirdParty/ffmpeg/lib/libopus.a; sourceTree = "<group>"; };
83D731381A74968900CA1366 /* g719.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = g719.xcodeproj; path = ../g719/g719.xcodeproj; sourceTree = "<group>"; };
83D7318B1A749EEE00CA1366 /* g719_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = g719_decoder.c; sourceTree = "<group>"; };
@@ -1699,6 +1713,7 @@
838BDB6D1D3B043C0022CA6F /* ffmpeg.c */,
836F6E4B18BDC2180095E648 /* ffw.c */,
8349A8FD1FE6257F00E26435 /* flx.c */,
83D20072248DDB760048BD24 /* fsb_encrypted_streamfile.h */,
83A21F81201D8981000F04B9 /* fsb_encrypted.c */,
834FE0C4215C79E6000A5D3D /* fsb_interleave_streamfile.h */,
83A21F7E201D8980000F04B9 /* fsb_keys.h */,
@@ -1734,9 +1749,11 @@
836F6E5818BDC2180095E648 /* ivb.c */,
837CEAE923487F2B00E62A4A /* jstm_streamfile.h */,
837CEAEF23487F2C00E62A4A /* jstm.c */,
83D20075248DDB760048BD24 /* kat.c */,
834FE0C3215C79E6000A5D3D /* kma9_streamfile.h */,
83A21F83201D8981000F04B9 /* kma9.c */,
836F6E5918BDC2180095E648 /* kraw.c */,
83D20074248DDB760048BD24 /* ktsr.c */,
830EBE122004656E0023AA10 /* ktss.c */,
8373342423F60CDB00DE14DC /* kwb.c */,
8373341F23F60CDB00DE14DC /* lrmd_streamfile.h */,
@@ -1764,6 +1781,8 @@
83C7280322BC893A00678B4A /* mtaf.c */,
83031ED5243C510400C3F3E0 /* mul_streamfile.h */,
832BF81221E05149006F50F1 /* mul.c */,
83D20073248DDB760048BD24 /* mups_streamfile.h */,
83D20077248DDB770048BD24 /* mups.c */,
836F6E6218BDC2180095E648 /* mus_acm.c */,
83C7280622BC893B00678B4A /* mus_vc.c */,
836F6E6318BDC2180095E648 /* musc.c */,
@@ -1776,7 +1795,6 @@
836F6E6718BDC2180095E648 /* naomi_spsd.c */,
836F6E6818BDC2180095E648 /* nds_hwas.c */,
836F6E6918BDC2180095E648 /* nds_rrds.c */,
836F6E6A18BDC2180095E648 /* nds_sad.c */,
830165991F256BD000CA0941 /* nds_strm_ffta2.c */,
836F6E6B18BDC2180095E648 /* nds_strm.c */,
836F6E6C18BDC2180095E648 /* nds_swav.c */,
@@ -1822,6 +1840,7 @@
8349A8F01FE6257C00E26435 /* pc_ast.c */,
836F6E8618BDC2180095E648 /* pc_mxst.c */,
8306B0D12098458F000302D4 /* pcm_sre.c */,
83D20076248DDB770048BD24 /* pcm_success.c */,
836F6E8B18BDC2180095E648 /* pona.c */,
836F6E8C18BDC2180095E648 /* pos.c */,
8306B0C52098458D000302D4 /* ppst_streamfile.h */,
@@ -1907,6 +1926,8 @@
836F6EE918BDC2190095E648 /* rwx.c */,
836F6EEA18BDC2190095E648 /* s14_sss.c */,
8349A8F11FE6257D00E26435 /* sab.c */,
83D20078248DDB770048BD24 /* sadf.c */,
83D20079248DDB770048BD24 /* sadl.c */,
836F6EEB18BDC2190095E648 /* sat_baka.c */,
836F6EEC18BDC2190095E648 /* sat_dvi.c */,
836F6EED18BDC2190095E648 /* sat_sap.c */,
@@ -2072,6 +2093,7 @@
834FE0ED215C79ED000A5D3D /* fsb_interleave_streamfile.h in Headers */,
8351F32E2212B57000A606E4 /* ubi_bao_streamfile.h in Headers */,
8349A9111FE6258200E26435 /* bar_streamfile.h in Headers */,
83D2007A248DDB770048BD24 /* fsb_encrypted_streamfile.h in Headers */,
836F6F2718BDC2190095E648 /* g72x_state.h in Headers */,
83FC176F23AC58D100E1025F /* cri_utf.h in Headers */,
83C7282822BC8C1500678B4A /* mixing.h in Headers */,
@@ -2115,6 +2137,7 @@
8373341D23F60C7B00DE14DC /* g7221_decoder_lib.h in Headers */,
8306B0E820984590000302D4 /* opus_interleave_streamfile.h in Headers */,
83031EDD243C510500C3F3E0 /* xnb_streamfile.h in Headers */,
83D2007B248DDB770048BD24 /* mups_streamfile.h in Headers */,
8373341623F60C7B00DE14DC /* g7221_decoder_aes.h in Headers */,
8373341923F60C7B00DE14DC /* g7221_decoder_lib_data.h in Headers */,
83AFABBD23795202002F3947 /* ea_eaac_opus_streamfile.h in Headers */,
@@ -2167,7 +2190,7 @@
836F6B3018BDB8880095E648 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0940;
LastUpgradeCheck = 1150;
ORGANIZATIONNAME = "Christopher Snowhill";
TargetAttributes = {
836F6B3818BDB8880095E648 = {
@@ -2384,6 +2407,7 @@
834FE105215C79ED000A5D3D /* xmd.c in Sources */,
837CEADA23487E8300E62A4A /* acb.c in Sources */,
834FE0F6215C79ED000A5D3D /* derf.c in Sources */,
83D20081248DDB770048BD24 /* sadl.c in Sources */,
836F6F8B18BDC2190095E648 /* genh.c in Sources */,
83C7281922BC893D00678B4A /* fsb5_fev.c in Sources */,
8349A8EA1FE6253900E26435 /* blocked_ea_schl.c in Sources */,
@@ -2475,7 +2499,9 @@
836F6FD318BDC2190095E648 /* ps2_ccc.c in Sources */,
83C7281C22BC893D00678B4A /* sfh.c in Sources */,
834FE0FC215C79ED000A5D3D /* vai.c in Sources */,
83D2007F248DDB770048BD24 /* mups.c in Sources */,
83AA5D171F6E2F600020821C /* mpeg_custom_utils_ealayer3.c in Sources */,
83D20080248DDB770048BD24 /* sadf.c in Sources */,
83345A521F8AEB2800B2EAA4 /* xvag.c in Sources */,
836F6F3918BDC2190095E648 /* SASSC_decoder.c in Sources */,
8306B0A920984552000302D4 /* blocked_adm.c in Sources */,
@@ -2507,7 +2533,6 @@
83AA5D191F6E2F600020821C /* ea_xas_decoder.c in Sources */,
836F6F9318BDC2190095E648 /* ivaud.c in Sources */,
836F6F8518BDC2190095E648 /* exakt_sc.c in Sources */,
836F6FA618BDC2190095E648 /* nds_sad.c in Sources */,
8306B0F120984590000302D4 /* ppst.c in Sources */,
832BF81C21E0514B006F50F1 /* xpcm.c in Sources */,
836F702B18BDC2190095E648 /* sdt.c in Sources */,
@@ -2726,6 +2751,7 @@
836F6FEA18BDC2190095E648 /* ps2_msa.c in Sources */,
836F6F3618BDC2190095E648 /* ogg_vorbis_decoder.c in Sources */,
8306B0E520984590000302D4 /* ubi_lyn.c in Sources */,
83D2007D248DDB770048BD24 /* kat.c in Sources */,
836F6F7618BDC2190095E648 /* brstm.c in Sources */,
836F700718BDC2190095E648 /* ps2_vgv.c in Sources */,
836F704F18BDC2190095E648 /* xwb.c in Sources */,
@@ -2753,6 +2779,7 @@
83A21F8C201D8982000F04B9 /* kma9.c in Sources */,
8342469420C4D23000926E48 /* h4m.c in Sources */,
834FE111215C79ED000A5D3D /* ck.c in Sources */,
83D2007C248DDB770048BD24 /* ktsr.c in Sources */,
836F704E18BDC2190095E648 /* xss.c in Sources */,
836F6FD118BDC2190095E648 /* ps2_bg00.c in Sources */,
836F6F4118BDC2190095E648 /* blocked.c in Sources */,
@@ -2772,6 +2799,7 @@
836F6FBA18BDC2190095E648 /* ngc_ymf.c in Sources */,
83F1EE2E245D4FB20076E182 /* vadpcm_decoder.c in Sources */,
836F705018BDC2190095E648 /* ydsp.c in Sources */,
83D2007E248DDB770048BD24 /* pcm_success.c in Sources */,
8306B0B720984552000302D4 /* blocked_str_snds.c in Sources */,
836F702718BDC2190095E648 /* sat_baka.c in Sources */,
832389501D2246C300482226 /* hca.c in Sources */,
@@ -2956,7 +2984,7 @@
836F6B6218BDB8880095E648 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = "";
@@ -2986,7 +3014,7 @@
836F6B6318BDB8880095E648 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = "";


+ 1
- 0
Frameworks/vgmstream/vgmstream/src/coding/coding.h View File

@@ -348,6 +348,7 @@ uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data * data);
void ffmpeg_set_channel_remapping(ffmpeg_codec_data * data, int *channels_remap);
const char* ffmpeg_get_codec_name(ffmpeg_codec_data * data);
void ffmpeg_set_force_seek(ffmpeg_codec_data * data);
const char* ffmpeg_get_metadata_value(ffmpeg_codec_data* data, const char* key);


/* ffmpeg_decoder_utils.c (helper-things) */


+ 2
- 0
Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c View File

@@ -155,6 +155,8 @@ int ffmpeg_make_riff_xma1(uint8_t * buf, size_t buf_size, size_t sample_count, s
put_16bitLE(buf+off+0x12, speakers);
}

/* xmaencode decoding rejects XMA1 without "seek" chunk, though it doesn't seem to use it */

memcpy(buf+riff_size-4-4, "data", 4);
put_32bitLE(buf+riff_size-4, data_size); /* data size */



+ 18
- 0
Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c View File

@@ -941,4 +941,22 @@ void ffmpeg_set_force_seek(ffmpeg_codec_data * data) {
//stream = data->formatCtx->streams[data->streamIndex];
}

const char* ffmpeg_get_metadata_value(ffmpeg_codec_data* data, const char* key) {
AVDictionary* avd;
AVDictionaryEntry* avde;

if (!data || !data->codec)
return NULL;

avd = data->formatCtx->streams[data->streamIndex]->metadata;
if (!avd)
return NULL;

avde = av_dict_get(avd, key, NULL, AV_DICT_IGNORE_SUFFIX);
if (!avde)
return NULL;

return avde->value;
}

#endif

+ 11
- 5
Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c View File

@@ -11,7 +11,7 @@
* - expand type: IMA style or variations; low or high nibble first
*/

static const int ADPCMTable[89] = {
static const int ADPCMTable[90] = {
7, 8, 9, 10, 11, 12, 13, 14,
16, 17, 19, 21, 23, 25, 28, 31,
34, 37, 41, 45, 50, 55, 60, 66,
@@ -23,7 +23,9 @@ static const int ADPCMTable[89] = {
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
32767
32767,

0 /* garbage value for Ubisoft IMA (see blocked_ubi_sce.c) */
};

static const int IMA_IndexTable[16] = {
@@ -1054,10 +1056,14 @@ void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspa

if (has_header) {
first_sample -= 10; //todo fix hack (needed to adjust nibble offset below)
}

if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
if (step_index < 0) step_index = 0;
if (step_index > 88) step_index = 88;
} else {
if (step_index < 0) step_index = 0;
if (step_index > 89) step_index = 89;
}

for (i = first_sample; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
off_t byte_offset = channelspacing == 1 ?


+ 10
- 3
Frameworks/vgmstream/vgmstream/src/formats.c View File

@@ -106,6 +106,7 @@ static const char* extension_list[] = {
"bik2",
//"bin", //common
"bk2",
"blk",
"bmdx",
"bms",
"bnk",
@@ -137,6 +138,7 @@ static const char* extension_list[] = {
"cxs",

"da",
"dat",
"data",
"dax",
"dbm",
@@ -237,6 +239,7 @@ static const char* extension_list[] = {
"joe",
"jstm",

"kat",
"kces",
"kcey", //fake extension/header id for .pcm (renamed, to be removed)
"khv", //fake extension/header id for .vas (renamed, to be removed)
@@ -244,6 +247,7 @@ static const char* extension_list[] = {
"kovs", //fake extension/header id for .kvs
"kns",
"kraw",
"ktsl2asbin",
"ktss", //fake extension/header id for .kns
"kvs",

@@ -322,6 +326,7 @@ static const char* extension_list[] = {
"mta2",
"mtaf",
"mul",
"mups",
"mus",
"musc",
"musx",
@@ -1141,7 +1146,7 @@ static const meta_info meta_info_list[] = {
{meta_CSTM, "Nintendo CSTM Header"},
{meta_FSTM, "Nintendo FSTM Header"},
{meta_KT_WIIBGM, "Koei Tecmo WiiBGM Header"},
{meta_KTSS, "Koei Tecmo Nintendo Stream KTSS Header"},
{meta_KTSS, "Koei Tecmo KTSS header"},
{meta_IDSP_NAMCO, "Namco IDSP header"},
{meta_WIIU_BTSND, "Nintendo Wii U Menu Boot Sound"},
{meta_MCA, "Capcom MCA header"},
@@ -1218,7 +1223,7 @@ static const meta_info meta_info_list[] = {
{meta_UBI_BAO, "Ubisoft BAO header"},
{meta_DSP_SWITCH_AUDIO, "UE4 Switch Audio header"},
{meta_TA_AAC_VITA, "tri-Ace AAC (Vita) header"},
{meta_DSP_SADF, "Procyon Studio SADF header"},
{meta_SADF, "Procyon Studio SADF header"},
{meta_H4M, "Hudson HVQM4 header"},
{meta_ASF, "Argonaut ASF header"},
{meta_XMD, "Konami XMD header"},
@@ -1292,7 +1297,9 @@ static const meta_info meta_info_list[] = {
{meta_WWISE_FX, "Audiokinetic Wwise FX header"},
{meta_DIVA, "DIVA header"},
{meta_IMUSE, "LucasArts iMUSE header"},

{meta_KTSR, "Koei Tecmo KTSR header"},
{meta_KAT, "Sega KAT header"},
{meta_PCM_SUCCESS, "Success PCM header"},
};

void get_vgmstream_coding_description(VGMSTREAM *vgmstream, char *out, size_t out_size) {


+ 6
- 6
Frameworks/vgmstream/vgmstream/src/layout/blocked_ubi_sce.c View File

@@ -44,13 +44,13 @@ void block_update_ubi_sce(off_t block_offset, VGMSTREAM* vgmstream) {
vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset + header_size * i + 0x04, sf);
vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset + header_size * i + 0x08, sf);

/* TODO figure out
* First step seems to always be a special value for the decoder, unsure of meaning.
* 0 = too quiet and max = 88 = waveform starts a bit off and clicky. First hist is usually +-1,
* other frames look, fine not sure what are they aiming for.
*/
/* First step is always 0x500, not sure if it's a bug or a feature but the game just takes it as is and
* ends up reading 0 from out-of-bounds memory area which causes a pop at the start. Yikes.
* It gets clampled later so the rest of the sound plays ok.
* We put 89 here as our special index which contains 0 to simulate this.
*/
if (vgmstream->ch[i].adpcm_step_index == 0x500) {
vgmstream->ch[i].adpcm_step_index = 88;
vgmstream->ch[i].adpcm_step_index = 89;
}
}
}


+ 670
- 641
Frameworks/vgmstream/vgmstream/src/meta/acb.c
File diff suppressed because it is too large
View File


+ 14
- 12
Frameworks/vgmstream/vgmstream/src/meta/aix.c View File

@@ -3,13 +3,15 @@
#include "aix_streamfile.h"


#define MAX_SEGMENTS 50 /* usually segment0=intro, segment1=loop/main, sometimes ~5, rarely ~40 */
/* usually segment0=intro, segment1=loop/main, sometimes ~5, rarely ~40~115
* as pseudo dynamic/multi-song container [Sega Ages 2500 Vol 28 Tetris Collection (PS2)] */
#define MAX_SEGMENTS 120

static VGMSTREAM *build_segmented_vgmstream(STREAMFILE *streamFile, off_t *segment_offsets, size_t *segment_sizes, int32_t *segment_samples, int segment_count, int layer_count);
static VGMSTREAM* build_segmented_vgmstream(STREAMFILE* sf, off_t* segment_offsets, size_t* segment_sizes, int32_t* segment_samples, int segment_count, int layer_count);

/* AIX - N segments with M layers (2ch ADX) inside [SoulCalibur IV (PS3), Dragon Ball Z: Burst Limit (PS3)] */
VGMSTREAM * init_vgmstream_aix(STREAMFILE *sf) {
VGMSTREAM * vgmstream = NULL;
VGMSTREAM* init_vgmstream_aix(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;

off_t segment_offsets[MAX_SEGMENTS] = {0};
size_t segment_sizes[MAX_SEGMENTS] = {0};
@@ -106,8 +108,8 @@ fail:
return NULL;
}

static VGMSTREAM *build_layered_vgmstream(STREAMFILE *streamFile, off_t segment_offset, size_t segment_size, int layer_count) {
VGMSTREAM *vgmstream = NULL;
static VGMSTREAM *build_layered_vgmstream(STREAMFILE* sf, off_t segment_offset, size_t segment_size, int layer_count) {
VGMSTREAM* vgmstream = NULL;
layered_layout_data* data = NULL;
int i;
STREAMFILE* temp_sf = NULL;
@@ -119,7 +121,7 @@ static VGMSTREAM *build_layered_vgmstream(STREAMFILE *streamFile, off_t segment_

for (i = 0; i < layer_count; i++) {
/* build the layer STREAMFILE */
temp_sf = setup_aix_streamfile(streamFile, segment_offset, segment_size, i, "adx");
temp_sf = setup_aix_streamfile(sf, segment_offset, segment_size, i, "adx");
if (!temp_sf) goto fail;

/* build the sub-VGMSTREAM */
@@ -149,9 +151,9 @@ fail:
return NULL;
}

static VGMSTREAM *build_segmented_vgmstream(STREAMFILE *streamFile, off_t *segment_offsets, size_t *segment_sizes, int32_t *segment_samples, int segment_count, int layer_count) {
VGMSTREAM *vgmstream = NULL;
segmented_layout_data *data = NULL;
static VGMSTREAM *build_segmented_vgmstream(STREAMFILE* sf, off_t* segment_offsets, size_t* segment_sizes, int32_t* segment_samples, int segment_count, int layer_count) {
VGMSTREAM* vgmstream = NULL;
segmented_layout_data* data = NULL;
int i, loop_flag, loop_start_segment, loop_end_segment;


@@ -161,7 +163,7 @@ static VGMSTREAM *build_segmented_vgmstream(STREAMFILE *streamFile, off_t *segme

for (i = 0; i < segment_count; i++) {
/* build the layered sub-VGMSTREAM */
data->segments[i] = build_layered_vgmstream(streamFile, segment_offsets[i], segment_sizes[i], layer_count);
data->segments[i] = build_layered_vgmstream(sf, segment_offsets[i], segment_sizes[i], layer_count);
if (!data->segments[i]) goto fail;

data->segments[i]->num_samples = segment_samples[i]; /* just in case */
@@ -177,7 +179,7 @@ static VGMSTREAM *build_segmented_vgmstream(STREAMFILE *streamFile, off_t *segme
* - 2 segments: intro + loop [SoulCalibur IV (PS3)]
* - 3 segments: intro + loop + end [Dragon Ball Z: Burst Limit (PS3), Metroid: Other M (Wii)]
* - 4/5 segments: intros + loop + ends [Danball Senki (PSP)]
* - 39 segments: no loops but multiple segments for dynamic parts? [Tetris Collection (PS2)] */
* - +39 segments: no loops but multiple segments for dynamic parts? [Tetris Collection (PS2)] */
loop_flag = (segment_count > 0 && segment_count <= 5);
loop_start_segment = (segment_count > 3) ? 2 : 1;
loop_end_segment = (segment_count > 3) ? (segment_count - 2) : 1;


+ 9
- 2
Frameworks/vgmstream/vgmstream/src/meta/bnsf_keys.h View File

@@ -5,7 +5,11 @@ typedef struct {
const char* key;
} bnsfkey_info;

/* Known keys, extracted from games' exe/files */
/* Known keys, from games' exe (iM@S, near "nus" strings) or files (Tales, config in audio bigfiles).
*
* In memdumps, first 16 chars of key can be found XORed with "Ua#oK3P94vdxX,ft" after AES 'Td'
* mix tables (that end with 8D4697A3 A38D4697 97A38D46 4697A38D), then can be cross referenced
* with other strings (max 24 chars) in the memdump. */
static const bnsfkey_info s14key_list[] = {

/* THE iDOLM@STER 2 (PS3/X360) */
@@ -17,6 +21,9 @@ static const bnsfkey_info s14key_list[] = {
/* Tales of Berseria (PS3) */
{"SPSLOC13"},

/* THE iDOLM@STER: One For All (PS3) */
{"86c215d7655eefb5c77ae92c"},

};

#endif/*_BNSF_KEYS_H_*/
#endif /*_BNSF_KEYS_H_*/

+ 11
- 9
Frameworks/vgmstream/vgmstream/src/meta/deblock_streamfile.c View File

@@ -2,7 +2,7 @@

//todo move to utils or something

static void block_callback_default(STREAMFILE *sf, deblock_io_data *data) {
static void block_callback_default(STREAMFILE* sf, deblock_io_data* data) {
data->block_size = data->cfg.chunk_size;
data->skip_size = data->cfg.skip_size;
data->data_size = data->block_size - data->skip_size;
@@ -10,7 +10,7 @@ static void block_callback_default(STREAMFILE *sf, deblock_io_data *data) {
//;VGM_LOG("DEBLOCK: of=%lx, bs=%lx, ss=%lx, ds=%lx\n", data->physical_offset, data->block_size, data->skip_size, data->data_size);
}

static size_t deblock_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_t length, deblock_io_data* data) {
static size_t deblock_io_read(STREAMFILE* sf, uint8_t* dest, off_t offset, size_t length, deblock_io_data* data) {
size_t total_read = 0;

//;VGM_LOG("DEBLOCK: of=%lx, sz=%x, po=%lx\n", offset, length, data->physical_offset);
@@ -25,9 +25,7 @@ static size_t deblock_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_
data->skip_size = 0;

data->step_count = data->cfg.step_start;
/*
data->read_count = data->cfg.read_count;
*/
//data->read_count = data->cfg.read_count;
}

/* read blocks */
@@ -98,6 +96,10 @@ static size_t deblock_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_
to_read = length;
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, sf);

if (data->cfg.read_callback) {
data->cfg.read_callback(dest, data, bytes_consumed, bytes_done);
}

total_read += bytes_done;
dest += bytes_done;
offset += bytes_done;
@@ -112,7 +114,7 @@ static size_t deblock_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_
return total_read;
}

static size_t deblock_io_size(STREAMFILE *streamfile, deblock_io_data* data) {
static size_t deblock_io_size(STREAMFILE* sf, deblock_io_data* data) {
uint8_t buf[0x04];

if (data->logical_size)
@@ -124,7 +126,7 @@ static size_t deblock_io_size(STREAMFILE *streamfile, deblock_io_data* data) {
}

/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
deblock_io_read(streamfile, buf, 0x7FFFFFFF, 1, data);
deblock_io_read(sf, buf, 0x7FFFFFFF, 1, data);
data->logical_size = data->logical_offset;
//todo tests:
@@ -141,8 +143,8 @@ static size_t deblock_io_size(STREAMFILE *streamfile, deblock_io_data* data) {
* decoder can't easily use blocked layout, or some other weird feature. It "filters" data so
* reader only sees clean data without blocks. Must pass setup config and a callback that sets
* sizes of a single block. */
STREAMFILE* open_io_deblock_streamfile_f(STREAMFILE *sf, deblock_config_t *cfg) {
STREAMFILE *new_sf = NULL;
STREAMFILE* open_io_deblock_streamfile_f(STREAMFILE* sf, deblock_config_t *cfg) {
STREAMFILE* new_sf = NULL;
deblock_io_data io_data = {0};

/* prepare data */


+ 4
- 2
Frameworks/vgmstream/vgmstream/src/meta/deblock_streamfile.h View File

@@ -34,7 +34,9 @@ struct deblock_config_t {
size_t interleave_last_count;

/* callback that setups deblock_io_data state, normally block_size and data_size */
void (*block_callback)(STREAMFILE *sf, deblock_io_data *data);
void (*block_callback)(STREAMFILE* sf, deblock_io_data* data);
/* callback that alters block, with the current position into the block (0=beginning) */
void (*read_callback)(uint8_t* dst, deblock_io_data* data, size_t block_pos, size_t read_size);
} ;

struct deblock_io_data {
@@ -56,6 +58,6 @@ struct deblock_io_data {
off_t physical_end;
};

STREAMFILE* open_io_deblock_streamfile_f(STREAMFILE *sf, deblock_config_t *cfg);
STREAMFILE* open_io_deblock_streamfile_f(STREAMFILE* sf, deblock_config_t* cfg);

#endif /* _DEBLOCK_STREAMFILE_H_ */

+ 3
- 0
Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c View File

@@ -503,6 +503,9 @@ fail:
static STREAMFILE *open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) {
static const char *const mapfile_pairs[][2] = {
/* standard cases, replace map part with mus part (from the end to preserve prefixes) */
{"game.mpf", "Game_Stream.mus"}, /* Skate */
{"ipod.mpf", "Ipod_Stream.mus"},
{"world.mpf", "World_Stream.mus"},
{"FreSkate.mpf", "track.mus,ram.mus"}, /* Skate It */
{"nsf_sing.mpf", "track_main.mus"}, /* Need for Speed: Nitro */
{"nsf_wii.mpf", "Track.mus"}, /* Need for Speed: Nitro */


+ 1
- 9
Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c View File

@@ -264,7 +264,6 @@ fail:

/* EA BNK with variable header - from EA games SFXs; also created by sx.exe */
VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE* sf) {
off_t offset;
int target_stream = sf->stream_index;

/* check extension */
@@ -276,15 +275,8 @@ VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE* sf) {
if (!check_extensions(sf,"bnk,sdt,mus,abk,ast"))
goto fail;

/* check header (doesn't use EA blocks, otherwise very similar to SCHl) */
if (read_32bitBE(0x100,sf) == EA_BNK_HEADER_LE)
offset = 0x100; /* Harry Potter and the Goblet of Fire (PS2) .mus have weird extra 0x100 bytes */
else
offset = 0x00;

if (target_stream == 0) target_stream = 1;

return parse_bnk_header(sf, offset, target_stream - 1, 0);
return parse_bnk_header(sf, 0x00, target_stream - 1, 0);
fail:
return NULL;


+ 92
- 52
Frameworks/vgmstream/vgmstream/src/meta/ffmpeg.c View File

@@ -3,34 +3,28 @@

#ifdef VGM_USE_FFMPEG

static int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile);

/**
* Generic init FFmpeg and vgmstream for any file supported by FFmpeg.
* Called by vgmstream when trying to identify the file type (if the player allows it).
*/
VGMSTREAM * init_vgmstream_ffmpeg(STREAMFILE *streamFile) {
return init_vgmstream_ffmpeg_offset( streamFile, 0, streamFile->get_size(streamFile) );
}
static int read_pos_file(uint8_t* buf, size_t bufsize, STREAMFILE* sf);
static int find_ogg_loops(ffmpeg_codec_data* data, int32_t* p_loop_start, int32_t* p_loop_end);

VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size) {
VGMSTREAM *vgmstream = NULL;
ffmpeg_codec_data *data = NULL;
/* parses any file supported by FFmpeg and not handled elsewhere (mainly: MP4/AAC, MP3, MPC, FLAC) */
VGMSTREAM* init_vgmstream_ffmpeg(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
ffmpeg_codec_data* data = NULL;
int loop_flag = 0;
int32_t loop_start = 0, loop_end = 0, num_samples = 0;
int total_subsongs, target_subsong = streamFile->stream_index;
int total_subsongs, target_subsong = sf->stream_index;

/* no checks */
//if (!check_extensions(streamFile, "..."))
//if (!check_extensions(sf, "..."))
// goto fail;

/* don't try to open headers and other mini files */
if (get_streamfile_size(streamFile) <= 0x1000)
if (get_streamfile_size(sf) <= 0x1000)
goto fail;


/* init ffmpeg */
data = init_ffmpeg_offset(streamFile, start, size);
data = init_ffmpeg_offset(sf, 0, get_streamfile_size(sf));
if (!data) return NULL;

total_subsongs = data->streamCount;
@@ -41,38 +35,43 @@ VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start,
{
uint8_t posbuf[4+4+4];

if ( read_pos_file(posbuf, 4+4+4, streamFile) ) {
loop_start = get_32bitLE(posbuf+0);
loop_end = get_32bitLE(posbuf+4);
if (read_pos_file(posbuf, 4+4+4, sf)) {
loop_start = get_s32le(posbuf+0);
loop_end = get_s32le(posbuf+4);
loop_flag = 1; /* incorrect looping will be validated outside */
/* FFmpeg can't always determine totalSamples correctly so optionally load it (can be 0/NULL)
* won't crash and will output silence if no loop points and bigger than actual stream's samples */
num_samples = get_32bitLE(posbuf+8);
num_samples = get_s32le(posbuf+8);
}
}

/* try to read Ogg loop tags (abridged) */
if (loop_flag == 0 && read_u32be(0x00, sf) == 0x4F676753) { /* "OggS" */
loop_flag = find_ogg_loops(data, &loop_start, &loop_end);
}

/* hack for AAC files (will return 0 samples if not an actual file) */
if (!num_samples && check_extensions(streamFile, "aac,laac")) {
num_samples = aac_get_samples(streamFile, 0x00, get_streamfile_size(streamFile));
if (!num_samples && check_extensions(sf, "aac,laac")) {
num_samples = aac_get_samples(sf, 0x00, get_streamfile_size(sf));
}

#ifdef VGM_USE_MPEG
/* hack for MP3 files (will return 0 samples if not an actual file)
* .mus: Marc Ecko's Getting Up (PC) */
if (!num_samples && check_extensions(streamFile, "mp3,lmp3,mus")) {
num_samples = mpeg_get_samples(streamFile, 0x00, get_streamfile_size(streamFile));
if (!num_samples && check_extensions(sf, "mp3,lmp3,mus")) {
num_samples = mpeg_get_samples(sf, 0x00, get_streamfile_size(sf));
}
#endif

/* hack for MPC, that seeks/resets incorrectly due to seek table shenanigans */
if (read_32bitBE(0x00, streamFile) == 0x4D502B07 || /* "MP+\7" (Musepack V7) */
read_32bitBE(0x00, streamFile) == 0x4D50434B) { /* "MPCK" (Musepack V8) */
if (read_u32be(0x00, sf) == 0x4D502B07 || /* "MP+\7" (Musepack V7) */
read_u32be(0x00, sf) == 0x4D50434B) { /* "MPCK" (Musepack V8) */
ffmpeg_set_force_seek(data);
}

/* default but often inaccurate when calculated using bitrate (wrong for VBR) */
if (!num_samples) {
num_samples = data->totalSamples;
num_samples = data->totalSamples; /* may be 0 if FFmpeg can't precalculate it */
}


@@ -87,15 +86,8 @@ VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start,
vgmstream->layout_type = layout_none;

vgmstream->num_samples = num_samples;
if (loop_flag) {
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
}

/* this may happen for some streams if FFmpeg can't determine it (ex. AAC) */
if (vgmstream->num_samples <= 0)
goto fail;

vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->channel_layout = ffmpeg_get_channel_layout(vgmstream->codec_data);

return vgmstream;
@@ -111,46 +103,94 @@ fail:
}


/**
* open file containing looping data and copy to buffer
*
* returns true if found and copied
*/
int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile) {
/* open file containing looping data and copy to buffer, returns true if found and copied */
int read_pos_file(uint8_t* buf, size_t bufsize, STREAMFILE* sf) {
char posname[PATH_LIMIT];
char filename[PATH_LIMIT];
/*size_t bytes_read;*/
STREAMFILE * streamFilePos= NULL;
STREAMFILE* sf_pos = NULL;

streamFile->get_name(streamFile,filename,sizeof(filename));
get_streamfile_name(sf,filename,sizeof(filename));

if (strlen(filename)+4 > sizeof(posname)) goto fail;
if (strlen(filename)+4 > sizeof(posname))
goto fail;

/* try to open a posfile using variations: "(name.ext).pos" */
{
strcpy(posname, filename);
strcat(posname, ".pos");
streamFilePos = streamFile->open(streamFile,posname,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (streamFilePos) goto found;
sf_pos = open_streamfile(sf, posname);;
if (sf_pos) goto found;

goto fail;
}

found:
//if (get_streamfile_size(streamFilePos) != bufsize) goto fail;
//if (get_streamfile_size(sf_pos) != bufsize) goto fail;

/* allow pos files to be of different sizes in case of new features, just fill all we can */
memset(buf, 0, bufsize);
read_streamfile(buf, 0, bufsize, streamFilePos);
read_streamfile(buf, 0, bufsize, sf_pos);

close_streamfile(streamFilePos);
close_streamfile(sf_pos);

return 1;

fail:
if (streamFilePos) close_streamfile(streamFilePos);

close_streamfile(sf_pos);
return 0;
}


/* loop tag handling could be unified with ogg_vorbis.c, but that one has a extra features too */
static int find_ogg_loops(ffmpeg_codec_data* data, int32_t* p_loop_start, int32_t* p_loop_end) {
char* endptr;
const char* value;
int loop_flag = 0;
int32_t loop_start = -1, loop_end = -1;

// Try to detect the loop flags based on current file metadata
value = ffmpeg_get_metadata_value(data, "LoopStart");
if (value != NULL) {
loop_start = strtol(value, &endptr, 10);
loop_flag = 1;
}

value = ffmpeg_get_metadata_value(data, "LoopEnd");
if (value != NULL) {
loop_end = strtol(value, &endptr, 10);
loop_flag = 1;
}

if (loop_flag) {
if (loop_end <= 0) {
// Detected a loop, but loop_end is still undefined or wrong. Try to calculate it.
value = ffmpeg_get_metadata_value(data, "LoopLength");
if (value != NULL) {
int loop_length = strtol(value, &endptr, 10);

if (loop_start != -1) loop_end = loop_start + loop_length;
}
}

if (loop_end <= 0) {
// Looks a calculation was not possible, or tag value is wrongly set. Use the end of track as end value
loop_end = data->totalSamples;
}

if (loop_start <= 0) {
// Weird edge case: loopend is defined and there's a loop, but loopstart was never defined. Reset to sane value
loop_start = 0;
}
} else {
// Every other attempt to detect loop information failed, reset start/end flags to sane values
loop_start = 0;
loop_end = 0;
}

*p_loop_start = loop_start;
*p_loop_end = loop_end;
return loop_flag;
}

#endif

+ 606
- 600
Frameworks/vgmstream/vgmstream/src/meta/fsb.c
File diff suppressed because it is too large
View File


+ 65
- 61
Frameworks/vgmstream/vgmstream/src/meta/fsb5.c View File

@@ -33,45 +33,45 @@ typedef struct {

/* ********************************************************************************** */

static layered_layout_data* build_layered_fsb5_celt(STREAMFILE *streamFile, fsb5_header* fsb5);
static layered_layout_data* build_layered_fsb5_atrac9(STREAMFILE *streamFile, fsb5_header* fsb5, off_t configs_offset, size_t configs_size);
static layered_layout_data* build_layered_fsb5_celt(STREAMFILE* sf, fsb5_header* fsb5);
static layered_layout_data* build_layered_fsb5_atrac9(STREAMFILE* sf, fsb5_header* fsb5, off_t configs_offset, size_t configs_size);

/* FSB5 - FMOD Studio multiplatform format */
VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
fsb5_header fsb5 = {0};
int target_subsong = streamFile->stream_index;
int target_subsong = sf->stream_index;
int i;


/* checks */
/* .fsb: standard
* .snd: Alchemy engine (also Unity) */
if (!check_extensions(streamFile,"fsb,snd"))
if (!check_extensions(sf,"fsb,snd"))
goto fail;

if (read_32bitBE(0x00,streamFile) != 0x46534235) /* "FSB5" */
if (read_32bitBE(0x00,sf) != 0x46534235) /* "FSB5" */
goto fail;

/* 0x00 is rare (seen in Tales from Space Vita) */
fsb5.version = read_32bitLE(0x04,streamFile);
fsb5.version = read_32bitLE(0x04,sf);
if (fsb5.version != 0x00 && fsb5.version != 0x01) goto fail;

fsb5.total_subsongs = read_32bitLE(0x08,streamFile);
fsb5.sample_header_size = read_32bitLE(0x0C,streamFile);
fsb5.name_table_size = read_32bitLE(0x10,streamFile);
fsb5.sample_data_size = read_32bitLE(0x14,streamFile);
fsb5.codec = read_32bitLE(0x18,streamFile);
fsb5.total_subsongs = read_32bitLE(0x08,sf);
fsb5.sample_header_size = read_32bitLE(0x0C,sf);
fsb5.name_table_size = read_32bitLE(0x10,sf);
fsb5.sample_data_size = read_32bitLE(0x14,sf);
fsb5.codec = read_32bitLE(0x18,sf);
/* version 0x01 - 0x1c(4): zero, 0x24(16): hash, 0x34(8): unk
* version 0x00 has an extra field (always 0?) at 0x1c */
if (fsb5.version == 0x01) {
/* found by tests and assumed to be flags, no games known */
fsb5.flags = read_32bitLE(0x20,streamFile);
fsb5.flags = read_32bitLE(0x20,sf);
}
fsb5.base_header_size = (fsb5.version==0x00) ? 0x40 : 0x3C;

if ((fsb5.sample_header_size + fsb5.name_table_size + fsb5.sample_data_size + fsb5.base_header_size) != get_streamfile_size(streamFile)) {
VGM_LOG("FSB5: bad size (%x + %x + %x + %x != %x)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(streamFile));
if ((fsb5.sample_header_size + fsb5.name_table_size + fsb5.sample_data_size + fsb5.base_header_size) != get_streamfile_size(sf)) {
VGM_LOG("FSB5: bad size (%x + %x + %x + %x != %x)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(sf));
goto fail;
}

@@ -87,8 +87,8 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
off_t data_offset = 0;
uint32_t sample_mode1, sample_mode2; /* maybe one uint64? */

sample_mode1 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+0x00,streamFile);
sample_mode2 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+0x04,streamFile);
sample_mode1 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+0x00,sf);
sample_mode2 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+0x04,sf);
stream_header_size += 0x08;

/* get samples */
@@ -133,7 +133,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
uint32_t extraflag, extraflag_type, extraflag_size, extraflag_end;

do {
extraflag = read_32bitLE(extraflag_offset,streamFile);
extraflag = read_32bitLE(extraflag_offset,sf);
extraflag_type = (extraflag >> 25) & 0x7F; /* bits 32..26 (7) */
extraflag_size = (extraflag >> 1) & 0xFFFFFF; /* bits 25..1 (24)*/
extraflag_end = (extraflag & 0x01); /* bit 0 (1) */
@@ -142,15 +142,15 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
if (i + 1 == target_subsong) {
switch(extraflag_type) {
case 0x01: /* channels */
fsb5.channels = read_8bit(extraflag_offset+0x04,streamFile);
fsb5.channels = read_8bit(extraflag_offset+0x04,sf);
break;
case 0x02: /* sample rate */
fsb5.sample_rate = read_32bitLE(extraflag_offset+0x04,streamFile);
fsb5.sample_rate = read_32bitLE(extraflag_offset+0x04,sf);
break;
case 0x03: /* loop info */
fsb5.loop_start = read_32bitLE(extraflag_offset+0x04,streamFile);
fsb5.loop_start = read_32bitLE(extraflag_offset+0x04,sf);
if (extraflag_size > 0x04) { /* probably not needed */
fsb5.loop_end = read_32bitLE(extraflag_offset+0x08,streamFile);
fsb5.loop_end = read_32bitLE(extraflag_offset+0x08,sf);
fsb5.loop_end += 1; /* correct compared to FMOD's tools */
}
//;VGM_LOG("FSB5: stream %i loop start=%i, loop end=%i, samples=%i\n", i, fsb5.loop_start, fsb5.loop_end, fsb5.num_samples);
@@ -183,7 +183,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
case 0x05: /* unknown 32b */
/* rare, found in Tearaway (Vita) with value 0 in first stream and
* Shantae and the Seven Sirens (Mobile) with value 0x0003bd72 BE in #44 (Arena Town) */
VGM_LOG("FSB5: stream %i flag %x with value %08x\n", i, extraflag_type, read_32bitLE(extraflag_offset+0x04,streamFile));
VGM_LOG("FSB5: stream %i flag %x with value %08x\n", i, extraflag_type, read_32bitLE(extraflag_offset+0x04,sf));
break;
case 0x06: /* XMA seek table */
/* no need for it */
@@ -209,7 +209,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
break;
case 0x0d: /* unknown 32b (config? usually 0x3fnnnn00 BE and sometimes 0x3dnnnn00 BE) */
/* found in some XMA2/Vorbis/FADPCM */
VGM_LOG("FSB5: stream %i flag %x with value %08x\n", i, extraflag_type, read_32bitLE(extraflag_offset+0x04,streamFile));
VGM_LOG("FSB5: stream %i flag %x with value %08x\n", i, extraflag_type, read_32bitLE(extraflag_offset+0x04,sf));
break;
default:
VGM_LOG("FSB5: stream %i unknown flag 0x%x at %x + 0x04 (size 0x%x)\n", i, extraflag_type, (uint32_t)extraflag_offset, extraflag_size);
@@ -233,8 +233,8 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
else {
off_t next_data_offset;
uint32_t next_sample_mode1, next_sample_mode2;
next_sample_mode1 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+stream_header_size+0x00,streamFile);
next_sample_mode2 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+stream_header_size+0x04,streamFile);
next_sample_mode1 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+stream_header_size+0x00,sf);
next_sample_mode2 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+stream_header_size+0x04,sf);
next_data_offset = (((next_sample_mode2 & 0x03) << 25) | ((next_sample_mode1 >> 7) & 0x1FFFFFF)) << 5;

fsb5.stream_size = next_data_offset - data_offset;
@@ -252,7 +252,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
/* get stream name */
if (fsb5.name_table_size) {
off_t name_suboffset = fsb5.base_header_size + fsb5.sample_header_size + 0x04*(target_subsong-1);
fsb5.name_offset = fsb5.base_header_size + fsb5.sample_header_size + read_32bitLE(name_suboffset,streamFile);
fsb5.name_offset = fsb5.base_header_size + fsb5.sample_header_size + read_32bitLE(name_suboffset,sf);
}


@@ -270,7 +270,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
vgmstream->stream_size = fsb5.stream_size;
vgmstream->meta_type = meta_FSB5;
if (fsb5.name_offset)
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, fsb5.name_offset,streamFile);
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, fsb5.name_offset,sf);

switch (fsb5.codec) {
case 0x00: /* FMOD_SOUND_FORMAT_NONE */
@@ -313,7 +313,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = 0x02;
}
dsp_read_coefs_be(vgmstream,streamFile,fsb5.extradata_offset,0x2E);
dsp_read_coefs_be(vgmstream,sf,fsb5.extradata_offset,0x2E);
break;

case 0x07: /* FMOD_SOUND_FORMAT_IMAADPCM [Skylanders] */
@@ -347,12 +347,12 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
block_count = fsb5.stream_size / block_size + (fsb5.stream_size % block_size ? 1 : 0);

bytes = ffmpeg_make_riff_xma2(buf, 0x100, vgmstream->num_samples, fsb5.stream_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, fsb5.stream_offset,fsb5.stream_size);
vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, fsb5.stream_offset,fsb5.stream_size);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;

xma_fix_raw_samples(vgmstream, streamFile, fsb5.stream_offset,fsb5.stream_size, 0, 0,0); /* samples look ok */
xma_fix_raw_samples(vgmstream, sf, fsb5.stream_offset,fsb5.stream_size, 0, 0,0); /* samples look ok */
break;
}
#endif
@@ -363,7 +363,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {

cfg.fsb_padding = (vgmstream->channels > 2 ? 16 : 4); /* observed default */

vgmstream->codec_data = init_mpeg_custom(streamFile, fsb5.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
vgmstream->codec_data = init_mpeg_custom(sf, fsb5.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
break;
@@ -375,7 +375,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
int is_multistream = fsb5.channels > 2;

if (is_multistream) {
vgmstream->layout_data = build_layered_fsb5_celt(streamFile, &fsb5);
vgmstream->layout_data = build_layered_fsb5_celt(sf, &fsb5);
if (!vgmstream->layout_data) goto fail;
vgmstream->coding_type = coding_CELT_FSB;
vgmstream->layout_type = layout_layered;
@@ -398,7 +398,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {


/* skip frame size in newer FSBs [Day of the Tentacle Remastered (Vita), Tearaway Unfolded (PS4)] */
if (configs_size >= 0x08 && (uint8_t)read_8bit(configs_offset, streamFile) != 0xFE) { /* ATRAC9 sync */
if (configs_size >= 0x08 && (uint8_t)read_8bit(configs_offset, sf) != 0xFE) { /* ATRAC9 sync */
configs_offset += 0x04;
configs_size -= 0x04;
}
@@ -407,7 +407,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {

if (is_multistream) {
/* multichannel made of various streams [Little Big Planet (Vita)] */
vgmstream->layout_data = build_layered_fsb5_atrac9(streamFile, &fsb5, configs_offset, configs_size);
vgmstream->layout_data = build_layered_fsb5_atrac9(sf, &fsb5, configs_offset, configs_size);
if (!vgmstream->layout_data) goto fail;
vgmstream->coding_type = coding_ATRAC9;
vgmstream->layout_type = layout_layered;
@@ -417,7 +417,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
atrac9_config cfg = {0};

cfg.channels = vgmstream->channels;
cfg.config_data = read_32bitBE(configs_offset,streamFile);
cfg.config_data = read_32bitBE(configs_offset,sf);
//cfg.encoder_delay = 0x100; //todo not used? num_samples seems to count all data

vgmstream->codec_data = init_atrac9(&cfg);
@@ -434,14 +434,14 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
uint8_t buf[0x100];
int bytes, format, average_bps, block_align;

format = read_16bitBE(fsb5.extradata_offset+0x00,streamFile);
block_align = (uint16_t)read_16bitBE(fsb5.extradata_offset+0x02,streamFile);
average_bps = (uint32_t)read_32bitBE(fsb5.extradata_offset+0x04,streamFile);
format = read_16bitBE(fsb5.extradata_offset+0x00,sf);
block_align = (uint16_t)read_16bitBE(fsb5.extradata_offset+0x02,sf);
average_bps = (uint32_t)read_32bitBE(fsb5.extradata_offset+0x04,sf);
/* rest: seek entries + mini seek table? */
/* XWMA encoder only does up to 6ch (doesn't use FSB multistreams for more) */

bytes = ffmpeg_make_riff_xwma(buf,0x100, format, fsb5.stream_size, vgmstream->channels, vgmstream->sample_rate, average_bps, block_align);
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, fsb5.stream_offset,fsb5.stream_size);
vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, fsb5.stream_offset,fsb5.stream_size);
if ( !vgmstream->codec_data ) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
@@ -455,11 +455,11 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {

cfg.channels = vgmstream->channels;
cfg.sample_rate = vgmstream->sample_rate;
cfg.setup_id = read_32bitLE(fsb5.extradata_offset,streamFile);
cfg.setup_id = read_32bitLE(fsb5.extradata_offset,sf);

vgmstream->layout_type = layout_none;
vgmstream->coding_type = coding_VORBIS_custom;
vgmstream->codec_data = init_vorbis_custom(streamFile, fsb5.stream_offset, VORBIS_FSB, &cfg);
vgmstream->codec_data = init_vorbis_custom(sf, fsb5.stream_offset, VORBIS_FSB, &cfg);
if (!vgmstream->codec_data) goto fail;

break;
@@ -477,7 +477,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
goto fail;
}

if (!vgmstream_open_stream(vgmstream,streamFile,fsb5.stream_offset))
if (!vgmstream_open_stream(vgmstream,sf,fsb5.stream_offset))
goto fail;

return vgmstream;
@@ -488,15 +488,15 @@ fail:
}


static layered_layout_data* build_layered_fsb5_celt(STREAMFILE *streamFile, fsb5_header* fsb5) {
static layered_layout_data* build_layered_fsb5_celt(STREAMFILE* sf, fsb5_header* fsb5) {
layered_layout_data* data = NULL;
STREAMFILE* temp_streamFile = NULL;
STREAMFILE* temp_sf = NULL;
int i, layers = (fsb5->channels+1) / 2;
size_t interleave;

if (read_32bitBE(fsb5->stream_offset+0x00,streamFile) != 0x17C30DF3) /* FSB CELT frame ID */
if (read_32bitBE(fsb5->stream_offset+0x00,sf) != 0x17C30DF3) /* FSB CELT frame ID */
goto fail;
interleave = 0x04+0x04+read_32bitLE(fsb5->stream_offset+0x04,streamFile); /* frame size */
interleave = 0x04+0x04+read_32bitLE(fsb5->stream_offset+0x04,sf); /* frame size */

//todo unknown interleave for max quality odd channel streams (found in test files)
/* FSB5 odd channels use 2ch+2ch...+1ch streams, and the last only goes up to 0x17a, and other
@@ -533,29 +533,31 @@ static layered_layout_data* build_layered_fsb5_celt(STREAMFILE *streamFile, fsb5
goto fail;
#endif

temp_streamFile = setup_fsb5_streamfile(streamFile, fsb5->stream_offset, fsb5->stream_size, layers, i, interleave);
if (!temp_streamFile) goto fail;
temp_sf = setup_fsb5_streamfile(sf, fsb5->stream_offset, fsb5->stream_size, layers, i, interleave);
if (!temp_sf) goto fail;

if (!vgmstream_open_stream(data->layers[i], temp_streamFile, 0x00))
if (!vgmstream_open_stream(data->layers[i], temp_sf, 0x00))
goto fail;

close_streamfile(temp_sf);
temp_sf = NULL;
}

/* setup layered VGMSTREAMs */
if (!setup_layout_layered(data))
goto fail;
close_streamfile(temp_streamFile);
return data;

fail:
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
free_layout_layered(data);
return NULL;
}


static layered_layout_data* build_layered_fsb5_atrac9(STREAMFILE *streamFile, fsb5_header* fsb5, off_t configs_offset, size_t configs_size) {
static layered_layout_data* build_layered_fsb5_atrac9(STREAMFILE* sf, fsb5_header* fsb5, off_t configs_offset, size_t configs_size) {
layered_layout_data* data = NULL;
STREAMFILE* temp_streamFile = NULL;
STREAMFILE* temp_sf = NULL;
int i, layers = (configs_size / 0x04);
size_t interleave = 0;

@@ -566,7 +568,7 @@ static layered_layout_data* build_layered_fsb5_atrac9(STREAMFILE *streamFile, fs

/* open each layer subfile (2ch+2ch..+1/2ch) */
for (i = 0; i < layers; i++) {
uint32_t config = read_32bitBE(configs_offset + 0x04*i, streamFile);
uint32_t config = read_32bitBE(configs_offset + 0x04*i, sf);
int channel_index, layer_channels;
size_t frame_size;

@@ -609,21 +611,23 @@ static layered_layout_data* build_layered_fsb5_atrac9(STREAMFILE *streamFile, fs
goto fail;
#endif

temp_streamFile = setup_fsb5_streamfile(streamFile, fsb5->stream_offset, fsb5->stream_size, layers, i, interleave);
if (!temp_streamFile) goto fail;
temp_sf = setup_fsb5_streamfile(sf, fsb5->stream_offset, fsb5->stream_size, layers, i, interleave);
if (!temp_sf) goto fail;

if (!vgmstream_open_stream(data->layers[i], temp_streamFile, 0x00))
if (!vgmstream_open_stream(data->layers[i], temp_sf, 0x00))
goto fail;

close_streamfile(temp_sf);
temp_sf = NULL;
}

/* setup layered VGMSTREAMs */
if (!setup_layout_layered(data))
goto fail;
close_streamfile(temp_streamFile);
return data;

fail:
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
free_layout_layered(data);
return NULL;
}

+ 74
- 54
Frameworks/vgmstream/vgmstream/src/meta/fsb5_fev.c View File

@@ -1,54 +1,74 @@
#include "meta.h"
#include "../coding/coding.h"
/* FEV+FSB5 container [Just Cause 3 (PC), Shantae: Half-Genie Hero (Switch)] */
VGMSTREAM * init_vgmstream_fsb5_fev_bank(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
off_t subfile_offset, chunk_offset, first_offset = 0x0c;
size_t subfile_size, chunk_size;
/* checks */
if (!check_extensions(streamFile, "bank"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x52494646) /* "RIFF" */
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x46455620) /* "FEV " */
goto fail;
/* .fev is an event format referencing various external .fsb, but FMOD can bake .fev and .fsb to
* form a .bank, which is the format we support here (regular .fev is complex and not very interesting).
* Format is RIFF with FMT (main), LIST (config) and SND (FSB5 data), we want the FSB5 offset inside LIST */
if (!find_chunk_le(streamFile, 0x4C495354,first_offset,0, &chunk_offset,NULL)) /* "LIST" */
goto fail;
if (read_32bitBE(chunk_offset+0x00,streamFile) != 0x50524F4A || /* "PROJ" */
read_32bitBE(chunk_offset+0x04,streamFile) != 0x424E4B49) /* "BNKI" */
goto fail; /* event .fev has "OBCT" instead of "BNKI" */
/* inside BNKI is a bunch of LIST each with event subchunks and finally the fsb offset */
first_offset = chunk_offset + 0x04;
if (!find_chunk_le(streamFile, 0x534E4448,first_offset,0, &chunk_offset,&chunk_size)) /* "SNDH" */
goto fail;
if (chunk_size != 0x0c)
goto fail; /* assuming only one FSB5 is possible */
subfile_offset = read_32bitLE(chunk_offset+0x04,streamFile);
subfile_size = read_32bitLE(chunk_offset+0x08,streamFile);
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, "fsb");
if (!temp_streamFile) goto fail;
vgmstream = init_vgmstream_fsb5(temp_streamFile);
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"

/* FEV+FSB5 container [Just Cause 3 (PC), Shantae: Half-Genie Hero (Switch)] */
VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE *temp_sf = NULL;
off_t subfile_offset, chunk_offset, first_offset = 0x0c;
size_t subfile_size, chunk_size;


/* checks */
if (!check_extensions(sf, "bank"))
goto fail;

if (read_32bitBE(0x00,sf) != 0x52494646) /* "RIFF" */
goto fail;
if (read_32bitBE(0x08,sf) != 0x46455620) /* "FEV " */
goto fail;

/* .fev is an event format referencing various external .fsb, but FMOD can bake .fev and .fsb to
* form a .bank, which is the format we support here (regular .fev is complex and not very interesting).
* Format is RIFF with FMT (main), LIST (config) and SND (FSB5 data), we want the FSB5 offset inside LIST */
if (!find_chunk_le(sf, 0x4C495354,first_offset,0, &chunk_offset,NULL)) /* "LIST" */
goto fail;

if (read_32bitBE(chunk_offset+0x00,sf) != 0x50524F4A || /* "PROJ" */
read_32bitBE(chunk_offset+0x04,sf) != 0x424E4B49) /* "BNKI" */
goto fail; /* event .fev has "OBCT" instead of "BNKI" */

/* inside BNKI is a bunch of LIST each with event subchunks and finally fsb offset */
first_offset = chunk_offset + 0x04;
if (!find_chunk_le(sf, 0x534E4448,first_offset,0, &chunk_offset,&chunk_size)) /* "SNDH" */
goto fail;

/* 0x00: unknown (version? ex LE: 0x00080003, 0x00080005) */
{
int banks;

/* multiple banks is possible but rare (only seen an extra "Silence" FSB5 in Guacamelee 2 (Switch),
* which on PC is a regular subsong in the only FSB5) */
banks = (chunk_size - 0x04) / 0x08;
VGM_ASSERT(banks > 1, "FSB5FEV: multiple banks found\n");

/* Could try to set stream index based on FSB subsong ranges, also fixing num_streams and stream_index
* kinda involved and hard to test so for now just ignore it and use first offset */

if (banks > 2)
goto fail;
if (banks == 2) {
off_t temp_offset = read_32bitLE(chunk_offset + 0x04 + 0x08*1 + 0x00,sf);
//size_t temp_size = read_32bitLE(chunk_offset + 0x04 + 0x08*1 + 0x04,sf);

int bank_subsongs = read_32bitLE(temp_offset + 0x08,sf);
if (bank_subsongs != 1) goto fail;
}
}

subfile_offset = read_32bitLE(chunk_offset+0x04,sf);
subfile_size = read_32bitLE(chunk_offset+0x08,sf);

temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, "fsb");
if (!temp_sf) goto fail;

vgmstream = init_vgmstream_fsb5(temp_sf);
close_streamfile(temp_sf);

return vgmstream;

fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

+ 85
- 164
Frameworks/vgmstream/vgmstream/src/meta/fsb_encrypted.c View File

@@ -1,164 +1,85 @@
#include "meta.h"
#include "fsb_keys.h"
#define FSB_KEY_MAX 128 /* probably 32 */
static STREAMFILE* setup_fsb_streamfile(STREAMFILE *streamFile, const uint8_t * key, size_t key_size, int is_alt);
/* fully encrypted FSBs */
VGMSTREAM * init_vgmstream_fsb_encrypted(STREAMFILE * streamFile) {
VGMSTREAM * vgmstream = NULL;
/* checks */
/* .fsb: standard
* .fsb.xen: various Guitar Hero (X360) */
if ( !check_extensions(streamFile, "fsb,xen") )
goto fail;
/* ignore non-encrypted FSB */
if ((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) == 0x46534200) /* "FSB\0" */
goto fail;
/* try fsbkey + all combinations of FSB4/5 and decryption algorithms */
{
STREAMFILE *temp_streamFile = NULL;
uint8_t key[FSB_KEY_MAX];
size_t key_size = read_key_file(key, FSB_KEY_MAX, streamFile);
if (key_size) {
{
temp_streamFile = setup_fsb_streamfile(streamFile, key,key_size, 0);
if (!temp_streamFile) goto fail;
if (!vgmstream) vgmstream = init_vgmstream_fsb(temp_streamFile);
if (!vgmstream) vgmstream = init_vgmstream_fsb5(temp_streamFile);
close_streamfile(temp_streamFile);
}
if (!vgmstream) {
temp_streamFile = setup_fsb_streamfile(streamFile, key,key_size, 1);
if (!temp_streamFile) goto fail;
if (!vgmstream) vgmstream = init_vgmstream_fsb(temp_streamFile);
if (!vgmstream) vgmstream = init_vgmstream_fsb5(temp_streamFile);
close_streamfile(temp_streamFile);
}
}
}
/* try all keys until one works */
if (!vgmstream) {
int i;
STREAMFILE *temp_streamFile = NULL;
for (i = 0; i < fsbkey_list_count; i++) {
fsbkey_info entry = fsbkey_list[i];
//;VGM_LOG("fsbkey: size=%i, is_fsb5=%i, is_alt=%i\n", entry.fsbkey_size,entry.is_fsb5, entry.is_alt);
temp_streamFile = setup_fsb_streamfile(streamFile, entry.fsbkey, entry.fsbkey_size, entry.is_alt);
if (!temp_streamFile) goto fail;
if (fsbkey_list[i].is_fsb5) {
vgmstream = init_vgmstream_fsb5(temp_streamFile);
} else {
vgmstream = init_vgmstream_fsb(temp_streamFile);
}
close_streamfile(temp_streamFile);
if (vgmstream) break;
}
}
if (!vgmstream)
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
typedef struct {
uint8_t key[FSB_KEY_MAX];
size_t key_size;
int is_alt;
} fsb_decryption_data;
/* Encrypted FSB info from guessfsb and fsbext */
static size_t fsb_decryption_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, fsb_decryption_data* data) {
static const unsigned char reverse_bits_table[] = { /* LUT to simplify, could use some bitswap function */
0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
};
size_t bytes_read;
int i;
bytes_read = streamfile->read(streamfile, dest, offset, length);
/* decrypt data (inverted bits and xor) */
for (i = 0; i < bytes_read; i++) {
uint8_t xor = data->key[(offset + i) % data->key_size];
uint8_t val = dest[i];
if (data->is_alt) {
dest[i] = reverse_bits_table[val ^ xor];
}
else {
dest[i] = reverse_bits_table[val] ^ xor;
}
}
return bytes_read;
}
static STREAMFILE* setup_fsb_streamfile(STREAMFILE *streamFile, const uint8_t * key, size_t key_size, int is_alt) {
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
fsb_decryption_data io_data = {0};
size_t io_data_size = sizeof(fsb_decryption_data);
/* setup decryption with key (external) */
if (!key_size || key_size > FSB_KEY_MAX) goto fail;
memcpy(io_data.key, key, key_size);
io_data.key_size = key_size;
io_data.is_alt = is_alt;
/* setup subfile */
new_streamFile = open_wrap_streamfile(streamFile);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, fsb_decryption_read,NULL);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"fsb");
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
return temp_streamFile;
fail:
close_streamfile(temp_streamFile);
return NULL;
}
#include "meta.h"
#include "fsb_keys.h"
#include "fsb_encrypted_streamfile.h"


/* fully encrypted FSBs */
VGMSTREAM* init_vgmstream_fsb_encrypted(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;

/* checks */
/* .fsb: standard
* .fsb.xen: various Guitar Hero (X360/PC) */
if (!check_extensions(sf, "fsb,xen"))
goto fail;

/* ignore non-encrypted FSB */
if ((read_u32be(0x00,sf) & 0xFFFFFF00) == 0x46534200) /* "FSB\0" */
goto fail;


/* try fsbkey + all combinations of FSB4/5 and decryption algorithms */
{
STREAMFILE* temp_sf = NULL;
uint8_t key[FSB_KEY_MAX];
size_t key_size = read_key_file(key, FSB_KEY_MAX, sf);

if (key_size) {
{
temp_sf = setup_fsb_streamfile(sf, key,key_size, 0);
if (!temp_sf) goto fail;

if (!vgmstream) vgmstream = init_vgmstream_fsb(temp_sf);
if (!vgmstream) vgmstream = init_vgmstream_fsb5(temp_sf);

close_streamfile(temp_sf);
}

if (!vgmstream) {
temp_sf = setup_fsb_streamfile(sf, key,key_size, 1);
if (!temp_sf) goto fail;

if (!vgmstream) vgmstream = init_vgmstream_fsb(temp_sf);
if (!vgmstream) vgmstream = init_vgmstream_fsb5(temp_sf);

close_streamfile(temp_sf);
}
}
}


/* try all keys until one works */
if (!vgmstream) {
int i;
STREAMFILE* temp_sf = NULL;

for (i = 0; i < fsbkey_list_count; i++) {
fsbkey_info entry = fsbkey_list[i];
//;VGM_LOG("fsbkey: size=%i, is_fsb5=%i, is_alt=%i\n", entry.fsbkey_size,entry.is_fsb5, entry.is_alt);

temp_sf = setup_fsb_streamfile(sf, entry.fsbkey, entry.fsbkey_size, entry.is_alt);
if (!temp_sf) goto fail;

if (fsbkey_list[i].is_fsb5) {
vgmstream = init_vgmstream_fsb5(temp_sf);
} else {
vgmstream = init_vgmstream_fsb(temp_sf);
}

if (vgmstream)
dump_streamfile(temp_sf, 0);

close_streamfile(temp_sf);
if (vgmstream) break;
}
}

if (!vgmstream)
goto fail;

return vgmstream;

fail:
close_vgmstream(vgmstream);
return NULL;
}

+ 73
- 0
Frameworks/vgmstream/vgmstream/src/meta/fsb_encrypted_streamfile.h View File

@@ -0,0 +1,73 @@
#ifndef _FSB_ENCRYPTED_STREAMFILE_H_
#define _FSB_ENCRYPTED_H_

#define FSB_KEY_MAX 128 /* probably 32 */


typedef struct {
uint8_t key[FSB_KEY_MAX];
size_t key_size;
int is_alt;
} fsb_decryption_data;

/* Encrypted FSB info from guessfsb and fsbext */
static size_t fsb_decryption_read(STREAMFILE* sf, uint8_t *dest, off_t offset, size_t length, fsb_decryption_data* data) {
static const unsigned char reverse_bits_table[] = { /* LUT to simplify, could use some bitswap function */
0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
};
size_t bytes_read;
int i;

bytes_read = read_streamfile(dest, offset, length, sf);

/* decrypt data (inverted bits and xor) */
for (i = 0; i < bytes_read; i++) {
uint8_t xor = data->key[(offset + i) % data->key_size];
uint8_t val = dest[i];
if (data->is_alt) {
dest[i] = reverse_bits_table[val ^ xor];
}
else {
dest[i] = reverse_bits_table[val] ^ xor;
}
}

return bytes_read;
}

static STREAMFILE* setup_fsb_streamfile(STREAMFILE* sf, const uint8_t* key, size_t key_size, int is_alt) {
STREAMFILE* new_sf = NULL;
fsb_decryption_data io_data = {0};
size_t io_data_size = sizeof(fsb_decryption_data);

/* setup decryption with key (external) */
if (!key_size || key_size > FSB_KEY_MAX)
return NULL;

memcpy(io_data.key, key, key_size);
io_data.key_size = key_size;
io_data.is_alt = is_alt;

/* setup subfile */
new_sf = open_wrap_streamfile(sf);
new_sf = open_io_streamfile_f(new_sf, &io_data,io_data_size, fsb_decryption_read,NULL);
new_sf = open_fakename_streamfile(new_sf, NULL,"fsb");
return new_sf;
}

#endif /* _FSB5_STREAMFILE_H_ */

+ 3
- 0
Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h View File

@@ -337,6 +337,9 @@ static const hcakey_info hcakey_list[] = {
/* I Chu EtoileStage (Android) */
{1433227444226663680}, // 13E3D8C45778A500

/* 22/7 Ongaku no Jikan (Android) */
{20190906}, // 00000000013416BA

/* Dragalia Lost (iOS/Android) */
{2967411924141, subkeys_dgl, sizeof(subkeys_dgl) / sizeof(subkeys_dgl[0]) }, // 000002B2E7889CAD



+ 82
- 0
Frameworks/vgmstream/vgmstream/src/meta/kat.c View File

@@ -0,0 +1,82 @@
#include "meta.h"
#include "../coding/coding.h"

/* .KAT - standard sound bank format used on Dreamcast */
VGMSTREAM *init_vgmstream_kat(STREAMFILE *sf) {
VGMSTREAM *vgmstream = NULL;
uint32_t entry_offset, type, start_offset, data_size, sample_rate, channels, bit_depth, loop_start, loop_end;
int loop_flag;
int num_sounds, target_stream = sf->stream_index;

/* checks */
if (!check_extensions(sf, "kat"))
goto fail;

num_sounds = read_u32le(0x00, sf);

if (target_stream == 0) target_stream = 1;
if (target_stream < 0 || num_sounds == 0 || target_stream > num_sounds)
goto fail;

entry_offset = 0x04 + (target_stream - 1) * 0x2c;

type = read_u32le(entry_offset + 0x00, sf);
if (type != 0x01) /* only type 0x01 is supported, other types are MIDI, programs, etc */
goto fail;

bit_depth = read_u32le(entry_offset + 0x14, sf);
if (bit_depth != 4 && bit_depth != 8 && bit_depth != 16)
goto fail;

start_offset = read_u32le(entry_offset + 0x04, sf);
data_size = read_u32le(entry_offset + 0x08, sf);
sample_rate = read_u32le(entry_offset + 0x0c, sf);
if (sample_rate > 48000)
goto fail;

loop_flag = read_u32le(entry_offset + 0x10, sf);
loop_start = read_u32le(entry_offset + 0x1c, sf);
loop_end = read_u32le(entry_offset + 0x20, sf);

channels = 1; /* mono only */

/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;

/* fill in the vital statistics */
vgmstream->meta_type = meta_KAT;
vgmstream->sample_rate = sample_rate;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->stream_size = data_size;
vgmstream->num_streams = num_sounds;

switch (bit_depth) {
case 4:
vgmstream->coding_type = coding_AICA_int;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = yamaha_bytes_to_samples(data_size, channels);
break;
case 8:
vgmstream->coding_type = coding_PCM8;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channels, 8);
break;
case 16:
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channels, 16);
break;
default:
goto fail;
}

if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;

fail:
close_vgmstream(vgmstream);
return NULL;
}

+ 566
- 0
Frameworks/vgmstream/vgmstream/src/meta/ktsr.c View File

@@ -0,0 +1,566 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"

typedef enum { NONE, MSADPCM, DSP, GCADPCM, ATRAC9, KVS, /*KNS*/ } ktsr_codec;

#define MAX_CHANNELS 8

typedef struct {
int total_subsongs;
int target_subsong;
ktsr_codec codec;

int platform;
int format;

int channels;
int sample_rate;
int32_t num_samples;
int32_t loop_start;
int loop_flag;
off_t extra_offset;
uint32_t channel_layout;

int is_external;
off_t stream_offsets[MAX_CHANNELS];
size_t stream_sizes[MAX_CHANNELS];

off_t sound_name_offset;
off_t config_name_offset;
char name[255+1];
} ktsr_header;

static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf);
static layered_layout_data* build_layered_atrac9(ktsr_header* ktsr, STREAMFILE *sf, uint32_t config_data);


/* KTSR - Koei Tecmo sound resource countainer */
VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE *sf_b = NULL;
ktsr_header ktsr = {0};
int target_subsong = sf->stream_index;
int separate_offsets = 0;


/* checks */
/* .ktsl2asbin: common [Atelier Ryza (PC/Switch), Nioh (PC)] */
if (!check_extensions(sf, "ktsl2asbin"))
goto fail;

/* KTSR can be a memory file (ktsl2asbin), streams (ktsl2stbin) and global config (ktsl2gcbin)
* This accepts ktsl2asbin with internal data, or opening external streams as subsongs.
* Some info from KTSR.bt */

if (read_u32be(0x00, sf) != 0x4B545352) /* "KTSR" */
goto fail;
if (read_u32be(0x04, sf) != 0x777B481A) /* hash(?) id: 0x777B481A=as, 0x0294DDFC=st, 0xC638E69E=gc */
goto fail;

if (target_subsong == 0) target_subsong = 1;
ktsr.target_subsong = target_subsong;

if (!parse_ktsr(&ktsr, sf))
goto fail;

/* open companion body */
if (ktsr.is_external) {
sf_b = open_streamfile_by_ext(sf, "ktsl2stbin");
if (!sf_b) {
VGM_LOG("KTSR: companion file not found\n");
goto fail;
}
}
else {
sf_b = sf;
}


/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(ktsr.channels, ktsr.loop_flag);
if (!vgmstream) goto fail;

vgmstream->meta_type = meta_KTSR;
vgmstream->sample_rate = ktsr.sample_rate;
vgmstream->num_samples = ktsr.num_samples;
vgmstream->loop_start_sample = ktsr.loop_start;
vgmstream->loop_end_sample = ktsr.num_samples;
vgmstream->stream_size = ktsr.stream_sizes[0];
vgmstream->num_streams = ktsr.total_subsongs;
vgmstream->channel_layout = ktsr.channel_layout;
strcpy(vgmstream->stream_name, ktsr.name);

switch(ktsr.codec) {

case MSADPCM:
vgmstream->coding_type = coding_MSADPCM_int;
vgmstream->layout_type = layout_none;
separate_offsets = 1;

/* 0x00: samples per frame */
vgmstream->frame_size = read_u16le(ktsr.extra_offset + 0x02, sf_b);
break;

case DSP:
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
separate_offsets = 1;

dsp_read_coefs_le(vgmstream, sf, ktsr.extra_offset + 0x1c, 0x60);
dsp_read_hist_le (vgmstream, sf, ktsr.extra_offset + 0x40, 0x60);
break;

#ifdef VGM_USE_ATRAC9
case ATRAC9: {
/* 0x00: samples per frame */
/* 0x02: frame size */
uint32_t config_data = read_u32be(ktsr.extra_offset + 0x04, sf);
if ((config_data & 0xFF) == 0xFE) /* later versions(?) in LE */
config_data = read_u32le(ktsr.extra_offset + 0x04, sf);

vgmstream->layout_data = build_layered_atrac9(&ktsr, sf_b, config_data);
if (!vgmstream->layout_data) goto fail;
vgmstream->layout_type = layout_layered;
vgmstream->coding_type = coding_ATRAC9;
break;

#if 0
atrac9_config cfg = {0};
if (ktsr.channels > 1) {
VGM_LOG("1\n");
goto fail;
}

/* 0x00: samples per frame */
/* 0x02: frame size */
cfg.config_data = read_u32be(ktsr.extra_offset + 0x04, sf_b);
if ((cfg.config_data & 0xFF) == 0xFE) /* later versions(?) in LE */
cfg.config_data = read_u32le(ktsr.extra_offset + 0x04, sf_b);

cfg.channels = vgmstream->channels;
cfg.encoder_delay = 256; /* observed default (ex. Attack on Titan PC vs Vita) */

vgmstream->codec_data = init_atrac9(&cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_ATRAC9;
vgmstream->layout_type = layout_none;
break;
#endif
}
#endif

#ifdef VGM_USE_VORBIS
case KVS: {
VGMSTREAM *ogg_vgmstream = NULL; //TODO: meh
STREAMFILE *sf_kvs = setup_subfile_streamfile(sf_b, ktsr.stream_offsets[0], ktsr.stream_sizes[0], "kvs");
if (!sf_kvs) goto fail;

ogg_vgmstream = init_vgmstream_ogg_vorbis(sf_kvs);
close_streamfile(sf_kvs);
if (ogg_vgmstream) {
ogg_vgmstream->stream_size = vgmstream->stream_size;
ogg_vgmstream->num_streams = vgmstream->num_streams;
ogg_vgmstream->channel_layout = vgmstream->channel_layout;
/* loops look shared */
strcpy(ogg_vgmstream->stream_name, vgmstream->stream_name);