Updated VGMStream to r1050-3043-g295ffac0

CQTexperiment
Christopher Snowhill 2020-06-07 19:57:02 -07:00
parent 3cdebc8425
commit ebfb7e1207
40 changed files with 4297 additions and 2319 deletions

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 = "";

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) */

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 */

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

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 ?

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) {

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;
}
}
}

File diff suppressed because it is too large Load Diff

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;

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_*/

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 */

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_ */

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 */

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;

View File

@ -3,34 +3,28 @@
#ifdef VGM_USE_FFMPEG
static int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *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);
/**
* 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) );
}
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

File diff suppressed because it is too large Load Diff

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;
}

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;
}

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;
}

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_ */

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

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;
}

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);
close_vgmstream(vgmstream);
if (sf_b != sf) close_streamfile(sf_b);
return ogg_vgmstream;
}
else {
goto fail;
}
break;
}
#endif
default:
goto fail;
}
if (!vgmstream_open_stream_bf(vgmstream, sf_b, ktsr.stream_offsets[0], 1))
goto fail;
/* data offset per channel is absolute (not actual interleave since there is padding) in some cases */
if (separate_offsets) {
int i;
for (i = 0; i < ktsr.channels; i++) {
vgmstream->ch[i].offset = ktsr.stream_offsets[i];
}
}
if (sf_b != sf) close_streamfile(sf_b);
return vgmstream;
fail:
if (sf_b != sf) close_streamfile(sf_b);
close_vgmstream(vgmstream);
return NULL;
}
static layered_layout_data* build_layered_atrac9(ktsr_header* ktsr, STREAMFILE* sf, uint32_t config_data) {
STREAMFILE* temp_sf = NULL;
layered_layout_data* data = NULL;
int layers = ktsr->channels;
int i;
/* init layout */
data = init_layout_layered(layers);
if (!data) goto fail;
for (i = 0; i < layers; i++) {
data->layers[i] = allocate_vgmstream(1, 0);
if (!data->layers[i]) goto fail;
data->layers[i]->sample_rate = ktsr->sample_rate;
data->layers[i]->num_samples = ktsr->num_samples;
#ifdef VGM_USE_ATRAC9
{
atrac9_config cfg = {0};
cfg.config_data = config_data;
cfg.channels = 1;
cfg.encoder_delay = 256; /* observed default (ex. Attack on Titan PC vs Vita) */
data->layers[i]->codec_data = init_atrac9(&cfg);
if (!data->layers[i]->codec_data) goto fail;
data->layers[i]->coding_type = coding_ATRAC9;
data->layers[i]->layout_type = layout_none;
}
#else
goto fail;
#endif
temp_sf = setup_subfile_streamfile(sf, ktsr->stream_offsets[i], ktsr->stream_sizes[i], NULL);
if (!temp_sf) goto fail;
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;
return data;
fail:
close_streamfile(temp_sf);
free_layout_layered(data);
return NULL;
}
static int parse_codec(ktsr_header* ktsr) {
/* platform + format to codec, simplified until more codec combos are found */
switch(ktsr->platform) {
case 0x01: /* PC */
if (ktsr->is_external)
ktsr->codec = KVS;
else if (ktsr->format == 0x00)
ktsr->codec = MSADPCM;
else
goto fail;
break;
case 0x03: /* VITA */
if (ktsr->is_external)
goto fail;
else if (ktsr->format == 0x01)
ktsr->codec = ATRAC9;
else
goto fail;
break;
case 0x04: /* Switch */
if (ktsr->is_external)
goto fail; /* KTSS? */
else if (ktsr->format == 0x00)
ktsr->codec = DSP;
else
goto fail;
break;
default:
goto fail;
}
return 1;
fail:
VGM_LOG("KTSR: unknown codec combo: ext=%x, fmt=%x, ptf=%x\n", ktsr->is_external, ktsr->format, ktsr->platform);
return 0;
}
static int parse_ktsr_subfile(ktsr_header* ktsr, STREAMFILE* sf, off_t offset) {
off_t suboffset, starts_offset, sizes_offset;
int i;
uint32_t type;
type = read_u32be(offset + 0x00, sf);
//size = read_u32le(offset + 0x04, sf);
/* probably could check the flag in sound header, but the format is kinda messy */
switch(type) { /* hash-id? */
case 0x38D0437D: /* external [Nioh (PC), Atelier Ryza (PC)] */
/* 08 subtype? (ex. 0x522B86B9)
* 0c channels
* 10 ? (always 0x002706B8)
* 14 codec? (05=KVS)
* 18 sample rate
* 1c num samples
* 20 null?
* 24 loop start or -1 (loop end is num samples)
* 28 channel layout (or null?)
* 2c null
* 30 null
* 34 data offset (absolute to external stream, points to actual format and not to mini-header)
* 38 data size
* 3c always 0x0200
*/
ktsr->channels = read_u32le(offset + 0x0c, sf);
ktsr->format = read_u32le(offset + 0x14, sf);
/* other fields will be read in the external stream */
ktsr->channel_layout= read_u32le(offset + 0x28, sf);
ktsr->stream_offsets[0] = read_u32le(offset + 0x34, sf);
ktsr->stream_sizes[0] = read_u32le(offset + 0x38, sf);
ktsr->is_external = 1;
if (ktsr->format != 0x05) {
VGM_LOG("KTSR: unknown subcodec at %lx\n", offset);
goto fail;
}
break;
case 0x41FDBD4E: /* internal [Attack on Titan: Wings of Freedom (Vita)] */
case 0x6FF273F9: /* internal [Attack on Titan: Wings of Freedom (PC/Vita)] */
case 0x6FCAB62E: /* internal [Marvel Ultimate Alliance 3: The Black Order (Switch)] */
case 0x6AD86FE9: /* internal [Atelier Ryza (PC/Switch), Persona5 Scramble (Switch)] */
case 0x10250527: /* internal [Fire Emblem: Three Houses DLC (Switch)] */
/* 08 subtype? (0x6029DBD2, 0xD20A92F90, 0xDC6FF709)
* 0c channels
* 10 format? (00=platform's ADPCM? 01=ATRAC9?)
* 11 bps? (always 16)
* 12 null
* 14 sample rate
* 18 num samples
* 1c null or 0x100?
* 20 loop start or -1 (loop end is num samples)
* 24 channel layout or null
* 28 header offset (within subfile)
* 2c header size [B, C]
* 30 offset to data start offset [A, C] or to data start+size [B]
* 34 offset to data size [A, C] or same per channel
* 38 always 0x0200
* -- header
* -- data start offset
* -- data size
*/
ktsr->channels = read_u32le(offset + 0x0c, sf);
ktsr->format = read_u8 (offset + 0x10, sf);
ktsr->sample_rate = read_s32le(offset + 0x14, sf);
ktsr->num_samples = read_s32le(offset + 0x18, sf);
ktsr->loop_start = read_s32le(offset + 0x20, sf);
ktsr->channel_layout= read_u32le(offset + 0x24, sf);
ktsr->extra_offset = read_u32le(offset + 0x28, sf) + offset;
if (type == 0x41FDBD4E || type == 0x6FF273F9) /* v1 */
suboffset = offset + 0x2c;
else
suboffset = offset + 0x30;
if (ktsr->channels > MAX_CHANNELS) {
VGM_LOG("KTSR: max channels found\n");
goto fail;
}
starts_offset = read_u32le(suboffset + 0x00, sf) + offset;
sizes_offset = read_u32le(suboffset + 0x04, sf) + offset;
for (i = 0; i < ktsr->channels; i++) {
ktsr->stream_offsets[i] = read_u32le(starts_offset + 0x04*i, sf) + offset;
ktsr->stream_sizes[i] = read_u32le(sizes_offset + 0x04*i, sf);
}
ktsr->loop_flag = (ktsr->loop_start >= 0);
break;
default:
/* streams also have their own chunks like 0x09D4F415, not needed here */
VGM_LOG("KTSR: unknown subheader at %lx\n", offset);
goto fail;
}
if (!parse_codec(ktsr))
goto fail;
return 1;
fail:
VGM_LOG("KTSR: error parsing subheader\n");
return 0;
}
static void build_name(ktsr_header* ktsr, STREAMFILE* sf) {
char sound_name[255] = {0};
char config_name[255] = {0};
/* names can be different or same but usually config is better */
if (ktsr->sound_name_offset) {
read_string(sound_name, sizeof(sound_name), ktsr->sound_name_offset, sf);
}
if (ktsr->config_name_offset) {
read_string(config_name, sizeof(config_name), ktsr->config_name_offset, sf);
}
//if (longname[0] && shortname[0]) {
// snprintf(ktsr->name, sizeof(ktsr->name), "%s; %s", longname, shortname);
//}
if (config_name[0]) {
snprintf(ktsr->name, sizeof(ktsr->name), "%s", config_name);
}
else if (sound_name[0]) {
snprintf(ktsr->name, sizeof(ktsr->name), "%s", sound_name);
}
}
static void parse_longname(ktsr_header* ktsr, STREAMFILE* sf, uint32_t target_id) {
/* more configs than sounds is possible so we need target_id first */
off_t offset, end, name_offset;
uint32_t stream_id;
offset = 0x40;
end = get_streamfile_size(sf);
while (offset < end) {
uint32_t type = read_u32be(offset + 0x00, sf); /* hash-id? */
uint32_t size = read_u32le(offset + 0x04, sf);
switch(type) {
case 0xBD888C36: /* config */
stream_id = read_u32be(offset + 0x08, sf);
if (stream_id != target_id)
break;
name_offset = read_u32le(offset + 0x28, sf);
if (name_offset > 0)
ktsr->config_name_offset = offset + name_offset;
return; /* id found */
default:
break;
}
offset += size;
}
}
static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) {
off_t offset, end, header_offset, name_offset;
uint32_t stream_id = 0, stream_count;
/* 00: KTSR
* 04: type
* 08: version?
* 0a: unknown (usually 00, 02/03 seen in Vita)
* 0b: platform (01=PC, 03=Vita, 04=Switch)
* 0c: game id?
* 10: null
* 14: null
* 18: file size
* 1c: file size
* up to 40: reserved
* until end: entries (totals not defined) */
ktsr->platform = read_u8(0x0b,sf);
if (read_u32le(0x18, sf) != read_u32le(0x1c, sf))
goto fail;
if (read_u32le(0x1c, sf) != get_streamfile_size(sf))
goto fail;
offset = 0x40;
end = get_streamfile_size(sf);
while (offset < end) {
uint32_t type = read_u32be(offset + 0x00, sf); /* hash-id? */
uint32_t size = read_u32le(offset + 0x04, sf);
/* parse chunk-like subfiles, usually N configs then N songs */
switch(type) {
case 0x6172DBA8: /* padding (empty) */
case 0xBD888C36: /* config (floats, stream id, etc, may have extended name) */
case 0xC9C48EC1: /* unknown (has some string inside like "boss") */
break;
case 0xC5CCCB70: /* sound (internal data or external stream) */
//VGM_LOG("info at %lx\n", offset);
ktsr->total_subsongs++;
/* sound table:
* 08: stream id (used in several places)
* 0c: unknown (low number but not version?)
* 0e: external flag
* 10: sub-streams?
* 14: offset to header offset
* 18: offset to name
* --: name
* --: header offset
* --: header
* --: subheader (varies) */
if (ktsr->total_subsongs == ktsr->target_subsong) {
//;VGM_LOG("KTSR: target at %lx\n", offset);
stream_id = read_u32be(offset + 0x08,sf);
//ktsr->is_external = read_u16le(offset + 0x0e,sf);
stream_count = read_u32le(offset + 0x10,sf);
if (stream_count != 1) {
VGM_LOG("KTSR: unknown stream count\n");
goto fail;
}
header_offset = read_u32le(offset + 0x14, sf);
name_offset = read_u32le(offset + 0x18, sf);
if (name_offset > 0)
ktsr->sound_name_offset = offset + name_offset;
header_offset = read_u32le(offset + header_offset, sf) + offset;
if (!parse_ktsr_subfile(ktsr, sf, header_offset))
goto fail;
}
break;
default:
/* streams also have their own chunks like 0x09D4F415, not needed here */
VGM_LOG("KTSR: unknown chunk at %lx\n", offset);
goto fail;
}
offset += size;
}
if (ktsr->target_subsong > ktsr->total_subsongs)
goto fail;
parse_longname(ktsr, sf, stream_id);
build_name(ktsr, sf);
return 1;
fail:
return 0;
}

View File

@ -137,7 +137,6 @@ VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE *streamFile, uint16_t subkey);
#ifdef VGM_USE_FFMPEG
VGMSTREAM * init_vgmstream_ffmpeg(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size);
VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE * streamFile);
#endif
@ -654,7 +653,10 @@ VGMSTREAM * init_vgmstream_naac(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ubi_sm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ubi_dat(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ubi_bnm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ubi_bnm_ps2(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ubi_blk(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ezw(STREAMFILE * streamFile);
@ -897,4 +899,12 @@ VGMSTREAM* init_vgmstream_diva(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_mups(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_kat(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_pcm_success(STREAMFILE* sf);
#endif /*_META_H*/

View File

@ -0,0 +1,42 @@
#include "meta.h"
#include "../coding/coding.h"
#include "mups_streamfile.h"
/* MUPS - from Watermelon/HUCARD games (same programmer) [Pier Solar and the Great Architects (PC), Ghost Blade HD (PC/Switch)] */
VGMSTREAM* init_vgmstream_mups(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE *temp_sf = NULL;
/* checks */
/* mups: header id?
* (extensionless): default? */
if (!check_extensions(sf, "mups,"))
goto fail;
if (read_u32be(0x00,sf) != 0x4D555053) /* "MUPS" */
goto fail;
if (read_u32be(0x08,sf) != 0x50737348) /* "PssH" */
goto fail;
/* just an Ogg with changed OggS/vorbis words (see streamfile) */
temp_sf = setup_mups_streamfile(sf, 0x08);
if (!temp_sf) goto fail;
#ifdef VGM_USE_VORBIS
vgmstream = init_vgmstream_ogg_vorbis(temp_sf);
if (!vgmstream) goto fail;
#else
goto fail;
#endif
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -0,0 +1,102 @@
#ifndef _MUPS_STREAMFILE_H_
#define _MUPS_STREAMFILE_H_
#include "deblock_streamfile.h"
static inline int32_t max32(int32_t val1, int32_t val2) {
if (val1 > val2)
return val2;
return val1;
}
static void read_callback(uint8_t* dst, deblock_io_data* data, size_t block_pos, size_t read_size) {
static const uint8_t oggs[] = { 0x4F, 0x67, 0x67, 0x53 };
static const uint8_t vorbis[] = { 0x76, 0x6F, 0x72, 0x62, 0x69, 0x73 };
int i, min, max;
/* Swaps Xiph magic words back (resulting page checksum is ok).
* Reads can start/end anywhere, but block_pos = 0 is always page start */
/* change "PssH" back to "OggS" */
if (block_pos < 0x04) {
min = block_pos;
if (min < 0x00)
min = 0x00;
max = block_pos + read_size;
if (max > 0x04)
max = 0x04;
for (i = min; i < max; i++) {
dst[i] = oggs[i - 0x00];
}
}
/* first page also needs "psolar" to "vorbis" */
if (data->logical_offset == 0 && block_pos < 0x23) {
min = block_pos;
if (min < 0x1d)
min = 0x1d;
max = block_pos + read_size;
if (max > 0x23)
max = 0x23;
for (i = min; i < max; i++) {
dst[i] = vorbis[i - 0x1d];
}
}
}
static int get_page_size(STREAMFILE* sf, off_t page_offset) {
static const int base_size = 0x1b;
uint8_t page[0x1b + 0x100];
uint8_t segments;
size_t page_size;
int i, bytes;
bytes = read_streamfile(page + 0x00, page_offset + 0x00, base_size, sf);
if (bytes != base_size) goto fail;
if (get_u32be(page + 0x00) != 0x50737348) /* "PssH" */
goto fail;
segments = get_u8(page + 0x1a);
bytes = read_streamfile(page + base_size, page_offset + base_size, segments, sf);
if (bytes != segments) goto fail;
page_size = base_size + segments;
for (i = 0; i < segments; i++) {
uint8_t segment_size = get_u8(page + base_size + i);
page_size += segment_size;
}
return page_size;
fail:
return -1; /* not a valid page */
}
static void block_callback(STREAMFILE* sf, deblock_io_data* data) {
off_t page_offset = data->physical_offset;
/* block size = OggS page size as we need read_callback called on page starts */
data->data_size = get_page_size(sf, page_offset);
data->block_size = data->data_size;
}
/* Fixes MUPS streams that contain mutated OggS */
static STREAMFILE* setup_mups_streamfile(STREAMFILE* sf, off_t stream_offset) {
STREAMFILE* new_sf = NULL;
deblock_config_t cfg = {0};
cfg.stream_start = stream_offset;
cfg.block_callback = block_callback;
cfg.read_callback = read_callback;
new_sf = open_wrap_streamfile(sf);
new_sf = open_io_deblock_streamfile_f(new_sf, &cfg);
new_sf = open_fakename_streamfile_f(new_sf, NULL, "ogg");
return new_sf;
}
#endif /* _MUPS_STREAMFILE_H_ */

View File

@ -655,48 +655,6 @@ fail:
return NULL;
}
/* sadf - Procyon Studio Header Variant [Xenoblade Chronicles 2 (Switch)] (sfx) */
VGMSTREAM * init_vgmstream_sadf(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int channel_count, loop_flag;
off_t start_offset;
/* checks */
if (!check_extensions(streamFile, "sad"))
goto fail;
if (read_32bitBE(0x00, streamFile) != 0x73616466) /* "sadf" */
goto fail;
channel_count = read_8bit(0x18, streamFile);
loop_flag = read_8bit(0x19, streamFile);
start_offset = read_32bitLE(0x1C, streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->num_samples = read_32bitLE(0x28, streamFile);
vgmstream->sample_rate = read_32bitLE(0x24, streamFile);
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x2c, streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x30, streamFile);
}
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = channel_count == 1 ? 0x8 :
read_32bitLE(0x20, streamFile) / channel_count;
vgmstream->meta_type = meta_DSP_SADF;
dsp_read_coefs_le(vgmstream, streamFile, 0x80, 0x80);
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* IDSP - Traveller's Tales header + interleaved dsps [Lego Batman (Wii), Lego Dimensions (Wii U)] */
VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile) {

View File

@ -0,0 +1,68 @@
#include "meta.h"
#include "../coding/coding.h"
/* PCM - from Success (related) games [Metal Saga (PS2), Tetris Kiwamemichi (PS2), Duel Masters: Rebirth of Super Dragon (PS2)] */
VGMSTREAM* init_vgmstream_pcm_success(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channels, sample_rate, interleave;
size_t data_size, loop_start, loop_end, loop_adjust;
/* checks */
if (!check_extensions(sf, "pcm"))
goto fail;
if (read_u32be(0x00,sf) != 0x50434D20) /* "PCM " */
goto fail;
if (read_u32le(0x04,sf) != 0x00010000) /* version? */
goto fail;
if (read_u32le(0x08,sf) + 0x8000 < get_streamfile_size(sf)) /* data size without padding */
goto fail;
interleave = 0x800;
start_offset = 0x800;
sample_rate = read_s32le(0x0c,sf);
channels = read_s32le(0x10,sf);
loop_flag = read_s32le(0x14,sf);
data_size = read_s32le(0x18,sf) * interleave * channels;
/* loops seems slightly off, so 'adjust' meaning may need to be tweaked */
loop_adjust = read_s32le(0x1c,sf) * channels; /* from 0..<0x800 */
loop_start = read_s32le(0x20,sf) * interleave * channels + loop_adjust;
loop_adjust = read_s32le(0x24,sf) * channels; /* always 0x800 (0 if no loop flag) */
loop_end = read_s32le(0x28,sf) * interleave * channels + (interleave * channels - loop_adjust);
/* 0x2c: always 1? */
/* 0x30/40: padding garbage (also at file end) */
/* not always accurate and has padding */
if (data_size > get_streamfile_size(sf) - start_offset)
data_size = get_streamfile_size(sf) - start_offset;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_PCM_SUCCESS;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = ps_bytes_to_samples(data_size, channels);
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channels);
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, channels);
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -8,7 +8,7 @@ VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int channel_count, loop_flag, sample_rate;
int32_t num_samples, loop_start = 0, loop_end = 0;
int32_t num_samples;
size_t file_size, data_size, unknown1, unknown2, interleave, padding_size;
@ -65,8 +65,6 @@ VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE *streamFile) {
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->stream_size = data_size;
vgmstream->coding_type = coding_PSX;

View File

@ -132,9 +132,10 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
}
switch (fmt->codec) {
case 0x00: /* Yamaha AICA ADPCM [Headhunter (DC), Bomber hehhe (DC)] (unofficial) */
case 0x00: /* Yamaha AICA ADPCM [Headhunter (DC), Bomber hehhe (DC), Rayman 2 (DC)] (unofficial) */
if (fmt->bps != 4) goto fail;
if (fmt->block_size != 0x02*fmt->channel_count) goto fail;
if (fmt->block_size != 0x02*fmt->channel_count &&
fmt->block_size != 0x01*fmt->channel_count) goto fail;
fmt->coding_type = coding_AICA_int;
fmt->interleave = 0x01;
break;
@ -370,14 +371,25 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
uint16_t codec = read_16bitLE(0x14,streamFile);
if (riff_size+0x08+0x01 == file_size)
riff_size += 0x01; /* [Shikkoku no Sharnoth (PC)] */
else if (riff_size == file_size && codec == 0x0069)
riff_size -= 0x08; /* [Dynasty Warriors 3 (Xbox), BloodRayne (Xbox)] */
else if (riff_size + 0x04 == file_size && codec == 0x0000)
riff_size -= 0x04; /* [Headhunter (DC), Bomber hehhe (DC)] */
else if (riff_size + 0x04 == file_size && codec == 0x0069)
riff_size -= 0x04; /* [Halo 2 (PC)] (possibly bad extractor? 'Gravemind Tool') */
else if (riff_size + 0x04 == file_size && codec == 0x0000)
riff_size -= 0x04; /* [Headhunter (DC), Bomber hehhe (DC)] */
else if (riff_size == file_size && codec == 0x0000)
riff_size -= 0x08; /* [Rayman 2 (DC)] */
else if (riff_size + 0x02 + 0x08 == file_size && codec == 0x0000)
riff_size -= 0x02; /* [Rayman 2 (DC)]-dcz */
else if (riff_size == file_size && codec == 0x0300)
riff_size -= 0x08; /* [Chrono Ma:gia (Android)] */
else if (riff_size >= file_size && read_32bitBE(0x24,streamFile) == 0x4E584246) /* "NXBF" */
riff_size = file_size - 0x08; /* [R:Racing Evolution (Xbox)] */
}
@ -405,7 +417,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
if (!read_fmt(0, streamFile, current_chunk, &fmt, mwv))
goto fail;
/* some Dreamcast/Naomi games again [Headhunter (DC), Bomber hehhe (DC)] */
/* some Dreamcast/Naomi games again [Headhunter (DC), Bomber hehhe (DC), Rayman 2 (DC)] */
if (fmt.codec == 0x0000 && chunk_size == 0x12)
chunk_size += 0x02;
break;
@ -924,6 +936,7 @@ static size_t get_ue4_msadpcm_interleave(STREAMFILE *sf, riff_fmt_chunk *fmt, of
return v2_interleave; /* favor newer games */
}
/* same but big endian, seen in the spec and in Kitchenette (PC) */
VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
riff_fmt_chunk fmt = {0};

View File

@ -0,0 +1,51 @@
#include "meta.h"
#include "../coding/coding.h"
/* sadf - from Procyon Studio audio driver games [Xenoblade Chronicles 2 (Switch)] (sfx) */
VGMSTREAM* init_vgmstream_sadf(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
int channel_count, loop_flag;
off_t start_offset;
/* checks */
/* .sad: assumed (from older sadX formats)
* .nop: assumed (from streamed files)
* (extensionless): name in .xsp bigfiles */
if (!check_extensions(sf, "sad,nop,"))
goto fail;
if (read_32bitBE(0x00, sf) != 0x73616466) /* "sadf" */
goto fail;
if (read_32bitBE(0x08, sf) != 0x6470636D) /* "dpcm" ("opus" is used too, see opus.c, "ipcm" supposedly too) */
goto fail;
channel_count = read_8bit(0x18, sf);
loop_flag = read_8bit(0x19, sf);
start_offset = read_32bitLE(0x1C, sf);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->num_samples = read_32bitLE(0x28, sf);
vgmstream->sample_rate = read_32bitLE(0x24, sf);
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x2c, sf);
vgmstream->loop_end_sample = read_32bitLE(0x30, sf);
}
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = channel_count == 1 ? 0x8 : read_32bitLE(0x20, sf) / channel_count;
vgmstream->meta_type = meta_SADF;
dsp_read_coefs_le(vgmstream, sf, 0x80, 0x80);
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,32 +1,30 @@
#include "meta.h"
#include "../util.h"
/* sadl - from DS games with Procyon Studio audio driver */
VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
/* sadl - from DS games with Procyon Studio audio driver [Professor Layton (DS), Soma Bringer (DS)] */
VGMSTREAM* init_vgmstream_sadl(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
int channel_count, loop_flag;
off_t start_offset;
int loop_flag, channel_count;
/* checks */
if (!check_extensions(streamFile, "sad"))
if (!check_extensions(sf, "sad"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x7361646c) /* "sadl" */
if (read_32bitBE(0x00,sf) != 0x7361646c) /* "sadl" */
goto fail;
if (read_32bitLE(0x40,streamFile) != get_streamfile_size(streamFile))
if (read_32bitLE(0x40,sf) != get_streamfile_size(sf))
goto fail;
loop_flag = read_8bit(0x31,streamFile);
channel_count = read_8bit(0x32,streamFile);
loop_flag = read_8bit(0x31,sf);
channel_count = read_8bit(0x32,sf);
start_offset = 0x100;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
switch (read_8bit(0x33,streamFile) & 6) {
switch (read_8bit(0x33,sf) & 6) {
case 4:
vgmstream->sample_rate = 32728;
break;
@ -42,20 +40,20 @@ VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) {
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
switch(read_8bit(0x33,streamFile) & 0xf0) {
switch(read_8bit(0x33,sf) & 0xf0) {
case 0x70: /* Ni no Kuni (DS), Professor Layton and the Curious Village (DS), Soma Bringer (DS) */
vgmstream->coding_type = coding_IMA_int;
vgmstream->num_samples = (read_32bitLE(0x40,streamFile)-start_offset)/channel_count*2;
vgmstream->loop_start_sample = (read_32bitLE(0x54,streamFile)-start_offset)/channel_count*2;
vgmstream->num_samples = (read_32bitLE(0x40,sf)-start_offset)/channel_count*2;
vgmstream->loop_start_sample = (read_32bitLE(0x54,sf)-start_offset)/channel_count*2;
vgmstream->loop_end_sample = vgmstream->num_samples;
break;
case 0xb0: /* Soma Bringer (DS), Rekishi Taisen Gettenka (DS) */
vgmstream->coding_type = coding_NDS_PROCYON;
vgmstream->num_samples = (read_32bitLE(0x40,streamFile)-start_offset)/channel_count/16*30;
vgmstream->loop_start_sample = (read_32bitLE(0x54,streamFile)-start_offset)/channel_count/16*30;
vgmstream->num_samples = (read_32bitLE(0x40,sf)-start_offset)/channel_count/16*30;
vgmstream->loop_start_sample = (read_32bitLE(0x54,sf)-start_offset)/channel_count/16*30;
vgmstream->loop_end_sample = vgmstream->num_samples;
break;
@ -63,7 +61,7 @@ VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) {
goto fail;
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;

View File

@ -1473,19 +1473,26 @@ static STREAMFILE * setup_bao_streamfile(ubi_bao_header *bao, STREAMFILE *stream
if (!new_streamFile) goto fail;
stream_segments[0] = new_streamFile;
new_streamFile = open_atomic_bao(bao->cfg.file_type, bao->stream_id, 1, streamFile);
if (!new_streamFile) goto fail;
stream_segments[1] = new_streamFile;
if (bao->stream_size - bao->prefetch_size != 0) {
new_streamFile = open_atomic_bao(bao->cfg.file_type, bao->stream_id, 1, streamFile);
if (!new_streamFile) goto fail;
stream_segments[1] = new_streamFile;
new_streamFile = open_clamp_streamfile(stream_segments[1], bao->stream_offset, (bao->stream_size - bao->prefetch_size));
if (!new_streamFile) goto fail;
stream_segments[1] = new_streamFile;
new_streamFile = open_clamp_streamfile(stream_segments[1], bao->stream_offset, (bao->stream_size - bao->prefetch_size));
if (!new_streamFile) goto fail;
stream_segments[1] = new_streamFile;
new_streamFile = open_multifile_streamfile(stream_segments, 2);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
stream_segments[0] = NULL;
stream_segments[1] = NULL;
new_streamFile = open_multifile_streamfile(stream_segments, 2);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
stream_segments[0] = NULL;
stream_segments[1] = NULL;
}
else {
/* weird but happens, streamed chunk is empty in this case */
temp_streamFile = new_streamFile;
stream_segments[0] = NULL;
}
}
else {
new_streamFile = open_atomic_bao(bao->cfg.file_type, bao->stream_id, bao->is_external, streamFile);
@ -1507,20 +1514,27 @@ static STREAMFILE * setup_bao_streamfile(ubi_bao_header *bao, STREAMFILE *stream
if (!new_streamFile) goto fail;
stream_segments[0] = new_streamFile;
new_streamFile = open_streamfile_by_filename(streamFile, bao->resource_name);
if (!new_streamFile) { VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name); goto fail; }
stream_segments[1] = new_streamFile;
if (bao->stream_size - bao->prefetch_size != 0) {
new_streamFile = open_streamfile_by_filename(streamFile, bao->resource_name);
if (!new_streamFile) { VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name); goto fail; }
stream_segments[1] = new_streamFile;
new_streamFile = open_clamp_streamfile(stream_segments[1], bao->stream_offset, (bao->stream_size - bao->prefetch_size));
if (!new_streamFile) goto fail;
stream_segments[1] = new_streamFile;
temp_streamFile = NULL;
new_streamFile = open_clamp_streamfile(stream_segments[1], bao->stream_offset, (bao->stream_size - bao->prefetch_size));
if (!new_streamFile) goto fail;
stream_segments[1] = new_streamFile;
temp_streamFile = NULL;
new_streamFile = open_multifile_streamfile(stream_segments, 2);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
stream_segments[0] = NULL;
stream_segments[1] = NULL;
new_streamFile = open_multifile_streamfile(stream_segments, 2);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
stream_segments[0] = NULL;
stream_segments[1] = NULL;
}
else {
/* weird but happens, streamed chunk is empty in this case */
temp_streamFile = new_streamFile;
stream_segments[0] = NULL;
}
}
else if (bao->is_external) {
new_streamFile = open_streamfile_by_filename(streamFile, bao->resource_name);
@ -1721,6 +1735,7 @@ static int config_bao_version(ubi_bao_header * bao, STREAMFILE *streamFile) {
case 0x001F0008: /* Rayman Raving Rabbids: TV Party (Wii)-package */
case 0x001F0010: /* Prince of Persia 2008 (PC/PS3/X360)-atomic-forge, Far Cry 2 (PS3)-atomic-dunia? */
case 0x001F0011: /* Naruto: The Broken Bond (X360)-package */
case 0x0021000C: /* Splinter Cell: Conviction (E3 2009 Demo)(X360)-package */
case 0x0022000D: /* Just Dance (Wii)-package */
case 0x0022001B: /* Prince of Persia: The Forgotten Sands (Wii)-package */
config_bao_entry(bao, 0xA4, 0x28); /* PC/Wii: 0xA8 */

File diff suppressed because it is too large Load Diff

View File

@ -24,37 +24,37 @@ typedef struct {
off_t stream_offset;
} xvag_header;
static int init_xvag_atrac9(STREAMFILE *streamFile, VGMSTREAM* vgmstream, xvag_header * xvag, off_t chunk_offset);
static layered_layout_data* build_layered_xvag(STREAMFILE *streamFile, xvag_header * xvag, off_t chunk_offset, off_t start_offset);
static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header * xvag, off_t chunk_offset);
static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header * xvag, off_t chunk_offset, off_t start_offset);
/* XVAG - Sony's Scream Tool/Stream Creator format (God of War III, Ratchet & Clank Future, The Last of Us, Uncharted) */
VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE* temp_streamFile = NULL;
VGMSTREAM* init_vgmstream_xvag(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
xvag_header xvag = {0};
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
off_t start_offset, chunk_offset, first_offset = 0x20;
size_t chunk_size;
int total_subsongs = 0, target_subsong = streamFile->stream_index;
int total_subsongs = 0, target_subsong = sf->stream_index;
/* checks */
/* .xvag: standard
* (extensionless): The Last Of Us (PS3) speech files */
if (!check_extensions(streamFile,"xvag,"))
if (!check_extensions(sf,"xvag,"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x58564147) /* "XVAG" */
if (read_32bitBE(0x00,sf) != 0x58564147) /* "XVAG" */
goto fail;
/* endian flag (XVAGs of the same game can use BE or LE, usually when reusing from other platforms) */
xvag.big_endian = read_8bit(0x08,streamFile) & 0x01;
xvag.big_endian = read_8bit(0x08,sf) & 0x01;
if (xvag.big_endian) {
read_32bit = read_32bitBE;
} else {
read_32bit = read_32bitLE;
}
start_offset = read_32bit(0x04,streamFile);
start_offset = read_32bit(0x04,sf);
/* 0x08: flags? (&0x01=big endian, 0x02=?, 0x06=full RIFF AT9?)
* 0x09: flags2? (0x00/0x01/0x04, speaker mode?)
* 0x0a: always 0?
@ -62,24 +62,24 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
/* "fmat": base format (always first) */
if (!find_chunk(streamFile, 0x666D6174,first_offset,0, &chunk_offset,&chunk_size, xvag.big_endian, 1)) /*"fmat"*/
if (!find_chunk(sf, 0x666D6174,first_offset,0, &chunk_offset,&chunk_size, xvag.big_endian, 1)) /*"fmat"*/
goto fail;
xvag.channels = read_32bit(chunk_offset+0x00,streamFile);
xvag.codec = read_32bit(chunk_offset+0x04,streamFile);
xvag.num_samples = read_32bit(chunk_offset+0x08,streamFile);
xvag.channels = read_32bit(chunk_offset+0x00,sf);
xvag.codec = read_32bit(chunk_offset+0x04,sf);
xvag.num_samples = read_32bit(chunk_offset+0x08,sf);
/* 0x0c: samples again? */
VGM_ASSERT(xvag.num_samples != read_32bit(chunk_offset+0x0c,streamFile), "XVAG: num_samples values don't match\n");
VGM_ASSERT(xvag.num_samples != read_32bit(chunk_offset+0x0c,sf), "XVAG: num_samples values don't match\n");
xvag.factor = read_32bit(chunk_offset+0x10,streamFile); /* for interleave */
xvag.sample_rate = read_32bit(chunk_offset+0x14,streamFile);
xvag.data_size = read_32bit(chunk_offset+0x18,streamFile); /* not always accurate */
xvag.factor = read_32bit(chunk_offset+0x10,sf); /* for interleave */
xvag.sample_rate = read_32bit(chunk_offset+0x14,sf);
xvag.data_size = read_32bit(chunk_offset+0x18,sf); /* not always accurate */
/* extra data, seen in versions 0x61+ */
if (chunk_size > 0x1c) {
/* number of interleaved subsongs */
xvag.subsongs = read_32bit(chunk_offset+0x1c,streamFile);
xvag.subsongs = read_32bit(chunk_offset+0x1c,sf);
/* number of interleaved layers (layers * channels_per_layer = channels) */
xvag.layers = read_32bit(chunk_offset+0x20,streamFile);
xvag.layers = read_32bit(chunk_offset+0x20,sf);
}
else {
xvag.subsongs = 1;
@ -99,9 +99,9 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
/* XVAG has no looping, but some PS3 PS-ADPCM seems to do full loops (without data flags) */
if (xvag.codec == 0x06 && xvag.subsongs == 1) {
size_t file_size = get_streamfile_size(streamFile);
size_t file_size = get_streamfile_size(sf);
/* simply test if last frame is not empty = may loop */
xvag.loop_flag = (read_8bit(file_size - 0x01, streamFile) != 0);
xvag.loop_flag = (read_8bit(file_size - 0x01, sf) != 0);
xvag.loop_start = 0;
xvag.loop_end = ps_bytes_to_samples(file_size - start_offset, xvag.channels);
}
@ -162,7 +162,7 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
if (xvag.layers > 1 && !(xvag.layers*1 == vgmstream->channels || xvag.layers*2 == vgmstream->channels)) goto fail;
/* "mpin": mpeg info */
if (!find_chunk(streamFile, 0x6D70696E,first_offset,0, &chunk_offset,NULL, xvag.big_endian, 1)) /*"mpin"*/
if (!find_chunk(sf, 0x6D70696E,first_offset,0, &chunk_offset,NULL, xvag.big_endian, 1)) /*"mpin"*/
goto fail;
/* all layers/subsongs share the same config; not very useful but for posterity:
@ -182,18 +182,18 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
* - 0x34: data size
* (rest is padding)
* */
cfg.chunk_size = read_32bit(chunk_offset+0x1c,streamFile);
cfg.skip_samples = read_32bit(chunk_offset+0x20,streamFile);
cfg.chunk_size = read_32bit(chunk_offset+0x1c,sf);
cfg.skip_samples = read_32bit(chunk_offset+0x20,sf);
cfg.interleave = cfg.chunk_size * xvag.factor;
vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_XVAG, &cfg);
vgmstream->codec_data = init_mpeg_custom(sf, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_XVAG, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
/* interleaved subsongs, rarely [Sly Cooper: Thieves in Time (PS3)] */
if (xvag.subsongs > 1) {
temp_streamFile = setup_xvag_streamfile(streamFile, start_offset, cfg.interleave,cfg.chunk_size, (target_subsong-1), total_subsongs);
if (!temp_streamFile) goto fail;
temp_sf = setup_xvag_streamfile(sf, start_offset, cfg.interleave,cfg.chunk_size, (target_subsong-1), total_subsongs);
if (!temp_sf) goto fail;
start_offset = 0;
}
@ -207,13 +207,13 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
/* "a9in": ATRAC9 info */
/* 0x00: frame size, 0x04: samples per frame, 0x0c: fact num_samples (no change), 0x10: encoder delay1 */
if (!find_chunk(streamFile, 0x6139696E,first_offset,0, &chunk_offset,NULL, xvag.big_endian, 1)) /*"a9in"*/
if (!find_chunk(sf, 0x6139696E,first_offset,0, &chunk_offset,NULL, xvag.big_endian, 1)) /*"a9in"*/
goto fail;
if (xvag.layers > 1) {
/* some Vita/PS4 multichannel [flower (Vita), Uncharted Collection (PS4)]. PS4 ATRAC9 also
* does single-stream >2ch, but this can do configs ATRAC9 can't, like 5ch/14ch/etc */
vgmstream->layout_data = build_layered_xvag(streamFile, &xvag, chunk_offset, start_offset);
vgmstream->layout_data = build_layered_xvag(sf, &xvag, chunk_offset, start_offset);
if (!vgmstream->layout_data) goto fail;
vgmstream->coding_type = coding_ATRAC9;
vgmstream->layout_type = layout_layered;
@ -222,12 +222,12 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
}
else {
/* interleaved subsongs (section layers) */
size_t frame_size = read_32bit(chunk_offset+0x00,streamFile);
size_t frame_size = read_32bit(chunk_offset+0x00,sf);
if (!init_xvag_atrac9(streamFile, vgmstream, &xvag, chunk_offset))
if (!init_xvag_atrac9(sf, vgmstream, &xvag, chunk_offset))
goto fail;
temp_streamFile = setup_xvag_streamfile(streamFile, start_offset, frame_size*xvag.factor,frame_size, (target_subsong-1), total_subsongs);
if (!temp_streamFile) goto fail;
temp_sf = setup_xvag_streamfile(sf, start_offset, frame_size*xvag.factor,frame_size, (target_subsong-1), total_subsongs);
if (!temp_sf) goto fail;
start_offset = 0;
}
@ -240,25 +240,25 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) {
}
if (!vgmstream_open_stream(vgmstream,temp_streamFile ? temp_streamFile : streamFile,start_offset))
if (!vgmstream_open_stream(vgmstream,temp_sf ? temp_sf : sf,start_offset))
goto fail;
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}
#ifdef VGM_USE_ATRAC9
static int init_xvag_atrac9(STREAMFILE *streamFile, VGMSTREAM* vgmstream, xvag_header * xvag, off_t chunk_offset) {
static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header * xvag, off_t chunk_offset) {
int32_t (*read_32bit)(off_t,STREAMFILE*) = xvag->big_endian ? read_32bitBE : read_32bitLE;
atrac9_config cfg = {0};
cfg.channels = vgmstream->channels;
cfg.config_data = read_32bitBE(chunk_offset+0x08,streamFile);
cfg.encoder_delay = read_32bit(chunk_offset+0x14,streamFile);
cfg.config_data = read_32bitBE(chunk_offset+0x08,sf);
cfg.encoder_delay = read_32bit(chunk_offset+0x14,sf);
vgmstream->codec_data = init_atrac9(&cfg);
if (!vgmstream->codec_data) goto fail;
@ -271,9 +271,9 @@ fail:
}
#endif
static layered_layout_data* build_layered_xvag(STREAMFILE *streamFile, xvag_header * xvag, off_t chunk_offset, off_t start_offset) {
static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header * xvag, off_t chunk_offset, off_t start_offset) {
layered_layout_data* data = NULL;
STREAMFILE* temp_streamFile = NULL;
STREAMFILE* temp_sf = NULL;
int32_t (*read_32bit)(off_t,STREAMFILE*) = xvag->big_endian ? read_32bitBE : read_32bitLE;
int i, layers = xvag->layers;
@ -296,12 +296,12 @@ static layered_layout_data* build_layered_xvag(STREAMFILE *streamFile, xvag_head
switch(xvag->codec) {
#ifdef VGM_USE_ATRAC9
case 0x09: {
size_t frame_size = read_32bit(chunk_offset+0x00,streamFile);
size_t frame_size = read_32bit(chunk_offset+0x00,sf);
if (!init_xvag_atrac9(streamFile, data->layers[i], xvag, chunk_offset))
if (!init_xvag_atrac9(sf, data->layers[i], xvag, chunk_offset))
goto fail;
temp_streamFile = setup_xvag_streamfile(streamFile, start_offset, frame_size*xvag->factor,frame_size, i, layers);
if (!temp_streamFile) goto fail;
temp_sf = setup_xvag_streamfile(sf, start_offset, frame_size*xvag->factor,frame_size, i, layers);
if (!temp_sf) goto fail;
break;
}
#endif
@ -309,9 +309,11 @@ static layered_layout_data* build_layered_xvag(STREAMFILE *streamFile, xvag_head
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_streamFile);
close_streamfile(temp_sf);
temp_sf = NULL;
}
/* setup layered VGMSTREAMs */
@ -320,7 +322,7 @@ static layered_layout_data* build_layered_xvag(STREAMFILE *streamFile, xvag_head
return data;
fail:
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
free_layout_layered(data);
return NULL;
}

View File

@ -680,9 +680,12 @@ STREAMFILE* open_fakename_streamfile(STREAMFILE *streamfile, const char *fakenam
}
if (fakeext) {
char * ext = strrchr(this_sf->fakename,'.');
if (ext != NULL)
char* ext = strrchr(this_sf->fakename,'.');
if (ext != NULL) {
ext[1] = '\0'; /* truncate past dot */
} else {
strcat(this_sf->fakename, "."); /* no extension = add dot */
}
strcat(this_sf->fakename, fakeext);
}
@ -1187,6 +1190,9 @@ static int find_chunk_internal(STREAMFILE *streamFile, uint32_t chunk_id, off_t
uint32_t chunk_size = read_32bit_size(offset + 0x04,streamFile);
//;VGM_LOG("CHUNK: type=%x, size=%x at %lx\n", chunk_type, chunk_size, offset);
if (chunk_type == 0xFFFFFFFF || chunk_size == 0xFFFFFFFF)
return 0;
if (chunk_type == chunk_id) {
if (out_chunk_offset) *out_chunk_offset = offset + 0x08;
if (out_chunk_size) *out_chunk_size = chunk_size;

View File

@ -61,8 +61,6 @@ void interleave_stereo(sample_t * buffer, int32_t sample_count) {
else
belongs = (tomove-sample_count)*2+1;
printf("move %d to %d\n",tomove,belongs);
temp = buffer[belongs];
buffer[belongs] = moving;
moving = temp;
@ -100,6 +98,14 @@ void put_32bitBE(uint8_t * buf, int32_t i) {
buf[3] = (uint8_t)(i & 0xFF);
}
int round10(int val) {
int round_val = val % 10;
if (round_val < 5) /* half-down rounding */
return val - round_val;
else
return val + (10 - round_val);
}
void swap_samples_le(sample_t *buf, int count) {
/* Windows can't be BE... I think */
#if !defined(_WIN32)

View File

@ -7,6 +7,8 @@
#ifndef _UTIL_H
#define _UTIL_H
/* very common functions, so static inline in .h is useful to avoid some call overhead */
/* host endian independent multi-byte integer reading */
static inline int16_t get_16bitBE(uint8_t * p) {
@ -91,13 +93,9 @@ static inline int clamp16(int32_t val) {
else return val;
}
static inline int round10(int val) {
int round_val = val % 10;
if (round_val < 5) /* half-down rounding */
return val - round_val;
else
return val + (10 - round_val);
}
/* less common functions, no need to inline */
int round10(int val);
/* return a file's extension (a pointer to the first character of the
* extension in the original filename or the ending null byte if no extension */

View File

@ -351,6 +351,9 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ubi_sb,
init_vgmstream_ubi_sm,
init_vgmstream_ubi_bnm,
init_vgmstream_ubi_bnm_ps2,
init_vgmstream_ubi_dat,
init_vgmstream_ubi_blk,
init_vgmstream_ezw,
init_vgmstream_vxn,
init_vgmstream_ea_snr_sns,
@ -494,6 +497,10 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_bkhd_fx,
init_vgmstream_diva,
init_vgmstream_imuse,
init_vgmstream_ktsr,
init_vgmstream_mups,
init_vgmstream_kat,
init_vgmstream_pcm_success,
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */

View File

@ -317,7 +317,6 @@ typedef enum {
meta_DSP_WII_WSD, /* Phantom Brave (WII) */
meta_WII_NDP, /* Vertigo (Wii) */
meta_DSP_YGO, /* Konami: Yu-Gi-Oh! The Falsebound Kingdom (NGC), Hikaru no Go 3 (NGC) */
meta_DSP_SADF, /* Procyon Studio SADF - Xenoblade Chronicles 2 (Switch) */
meta_STRM, /* Nintendo STRM */
meta_RSTM, /* Nintendo RSTM (Revolution Stream, similar to STRM) */
@ -430,7 +429,7 @@ typedef enum {
meta_NGC_SSM, /* Golden Gashbell Full Power */
meta_PS2_JOE, /* Wall-E / Pixar games */
meta_NGC_YMF, /* WWE WrestleMania X8 */
meta_SADL, /* .sad */
meta_SADL,
meta_PS2_CCC, /* Tokyo Xtreme Racer DRIFT 2 */
meta_FAG, /* Jackie Chan - Stuntmaster */
meta_PS2_MIHB, /* Merged MIH+MIB */
@ -691,6 +690,7 @@ typedef enum {
meta_WV2, /* Slave Zero (PC) */
meta_XAU_KONAMI, /* Yu-Gi-Oh - The Dawn of Destiny (Xbox) */
meta_DERF, /* Stupid Invaders (PC) */
meta_SADF,
meta_UTK,
meta_NXA,
meta_ADPCM_CAPCOM,
@ -739,6 +739,9 @@ typedef enum {
meta_WWISE_FX,
meta_DIVA,
meta_IMUSE,
meta_KTSR,
meta_KAT,
meta_PCM_SUCCESS,
} meta_t;
/* standard WAVEFORMATEXTENSIBLE speaker positions */