Merge pull request #1201 from bnnm/hxd-etc

- Fix extensionless files in foobar
- Tweak UE4 wav detection [GTA SA Remaster (Switch)]
- Remove .vb from ps_headerless (use TXTH)
- Add .sig/sag extensions
- Remove fake .tec extension (use .str + TXTH)
- Redo .hxd+str [Fatal Frame 3 (PS2), Tokobot (PS2)]
- Remove .dxh (use .hxd+str)
This commit is contained in:
bnnm 2022-08-14 13:35:56 +02:00 committed by GitHub
commit 1d5e27b115
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 5397 additions and 5425 deletions

View File

@ -679,6 +679,8 @@ static int convert_file(cli_config* cfg) {
int32_t len_samples; int32_t len_samples;
vgmstream_set_log_stdout(VGM_LOG_LEVEL_ALL);
/* for plugin testing */ /* for plugin testing */
if (cfg->validate_extensions) { if (cfg->validate_extensions) {
int valid; int valid;
@ -693,8 +695,6 @@ static int convert_file(cli_config* cfg) {
if (!valid) goto fail; if (!valid) goto fail;
} }
vgmstream_set_log_stdout(VGM_LOG_LEVEL_ALL);
/* open streamfile and pass subsong */ /* open streamfile and pass subsong */
{ {
STREAMFILE* sf = open_stdio_streamfile(cfg->infilename); STREAMFILE* sf = open_stdio_streamfile(cfg->infilename);

View File

@ -12,7 +12,6 @@ This list is not complete and many other files are supported.
- .bmdx - .bmdx
- .ccc - .ccc
- .cnk - .cnk
- .dxh
- .enth - .enth
- .fag - .fag
- .filp - .filp

View File

@ -69,7 +69,7 @@ as explained below, but often will use default values. Accepted codec strings:
# * For many PS1/PS2/PS3 games # * For many PS1/PS2/PS3 games
# * Interleave is multiple of 0x10 (default), often +0x1000 # * Interleave is multiple of 0x10 (default), often +0x1000
# - PSX_bf PlayStation ADPCM with bad flags # - PSX_bf PlayStation ADPCM with bad flags
# * Variation with garbage data, for rare PS2 games # * Variation with garbage data, for rare PS2 games [Fatal Frame (PS2)]
# - HEVAG Vita/PS4 ADPCM # - HEVAG Vita/PS4 ADPCM
# * For some Vita/PS4 games # * For some Vita/PS4 games
# * Interleave is multiple of 0x10 (default) # * Interleave is multiple of 0x10 (default)

File diff suppressed because it is too large Load Diff

View File

@ -166,7 +166,6 @@ static const char* extension_list[] = {
"dspw", "dspw",
"dtk", "dtk",
"dvi", "dvi",
"dxh",
"dyx", //txth/reserved [Shrek 4 (iOS)] "dyx", //txth/reserved [Shrek 4 (iOS)]
"e4x", "e4x",
@ -442,6 +441,7 @@ static const char* extension_list[] = {
"sab", "sab",
"sad", "sad",
"saf", "saf",
"sag",
"sam", //txth/reserved [Lost Kingdoms 2 (GC)] "sam", //txth/reserved [Lost Kingdoms 2 (GC)]
"sap", "sap",
"sb0", "sb0",
@ -456,6 +456,7 @@ static const char* extension_list[] = {
"sbin", "sbin",
"sbr", "sbr",
"sbv", "sbv",
"sig",
"sm0", "sm0",
"sm1", "sm1",
"sm2", "sm2",
@ -539,7 +540,6 @@ static const char* extension_list[] = {
"szd3", "szd3",
"tad", "tad",
"tec",
"tgq", "tgq",
"tgv", "tgv",
"thp", "thp",
@ -567,7 +567,7 @@ static const char* extension_list[] = {
"vam", //txth/reserved [Rocket Power: Beach Bandits (PS2)] "vam", //txth/reserved [Rocket Power: Beach Bandits (PS2)]
"vas", "vas",
"vawx", "vawx",
"vb", "vb", //txth/reserved [Tantei Jinguji Saburo: Mikan no Rupo (PS1)]
"vbk", "vbk",
"vbx", //txth/reserved [THE Taxi 2 (PS2)] "vbx", //txth/reserved [THE Taxi 2 (PS2)]
"vds", "vds",
@ -1048,7 +1048,7 @@ static const meta_info meta_info_list[] = {
{meta_ACM, "InterPlay ACM Header"}, {meta_ACM, "InterPlay ACM Header"},
{meta_MUS_ACM, "InterPlay MUS ACM header"}, {meta_MUS_ACM, "InterPlay MUS ACM header"},
{meta_PS2_KCES, "Konami KCES Header"}, {meta_PS2_KCES, "Konami KCES Header"},
{meta_PS2_DXH, "Tokobot Plus DXH Header"}, {meta_HXD, "Tecmo HXD Header"},
{meta_VSV, "Square Enix .vsv Header"}, {meta_VSV, "Square Enix .vsv Header"},
{meta_RIFF_WAVE_labl, "RIFF WAVE header with loop markers"}, {meta_RIFF_WAVE_labl, "RIFF WAVE header with loop markers"},
{meta_RIFF_WAVE_smpl, "RIFF WAVE header with sample looping info"}, {meta_RIFF_WAVE_smpl, "RIFF WAVE header with sample looping info"},
@ -1060,7 +1060,6 @@ static const meta_info meta_info_list[] = {
{meta_PS2_PCM, "Konami KCEJ East .PCM header"}, {meta_PS2_PCM, "Konami KCEJ East .PCM header"},
{meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV PS2 header"}, {meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV PS2 header"},
{meta_PS2_VAS, "Konami .VAS header"}, {meta_PS2_VAS, "Konami .VAS header"},
{meta_PS2_TEC, "assumed TECMO badflagged stream by .tec extension"},
{meta_PS2_ENTH, ".enth Header"}, {meta_PS2_ENTH, ".enth Header"},
{meta_SDT, "High Voltage .sdt header"}, {meta_SDT, "High Voltage .sdt header"},
{meta_NGC_TYDSP, ".tydsp Header"}, {meta_NGC_TYDSP, ".tydsp Header"},

View File

@ -468,7 +468,7 @@
<ClCompile Include="meta\ps2_bg00.c" /> <ClCompile Include="meta\ps2_bg00.c" />
<ClCompile Include="meta\ps2_bmdx.c" /> <ClCompile Include="meta\ps2_bmdx.c" />
<ClCompile Include="meta\ps2_ccc.c" /> <ClCompile Include="meta\ps2_ccc.c" />
<ClCompile Include="meta\ps2_dxh.c" /> <ClCompile Include="meta\hxd.c" />
<ClCompile Include="meta\ps2_enth.c" /> <ClCompile Include="meta\ps2_enth.c" />
<ClCompile Include="meta\exst.c" /> <ClCompile Include="meta\exst.c" />
<ClCompile Include="meta\ps2_filp.c" /> <ClCompile Include="meta\ps2_filp.c" />
@ -504,7 +504,6 @@
<ClCompile Include="meta\ps2_sps.c" /> <ClCompile Include="meta\ps2_sps.c" />
<ClCompile Include="meta\svag_kcet.c" /> <ClCompile Include="meta\svag_kcet.c" />
<ClCompile Include="meta\svag_snk.c" /> <ClCompile Include="meta\svag_snk.c" />
<ClCompile Include="meta\ps2_tec.c" />
<ClCompile Include="meta\ps2_tk5.c" /> <ClCompile Include="meta\ps2_tk5.c" />
<ClCompile Include="meta\vag.c" /> <ClCompile Include="meta\vag.c" />
<ClCompile Include="meta\ps2_vas.c" /> <ClCompile Include="meta\ps2_vas.c" />

View File

@ -868,7 +868,7 @@
<ClCompile Include="meta\ps2_ccc.c"> <ClCompile Include="meta\ps2_ccc.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\ps2_dxh.c"> <ClCompile Include="meta\hxd.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\ps2_enth.c"> <ClCompile Include="meta\ps2_enth.c">
@ -976,9 +976,6 @@
<ClCompile Include="meta\svag_snk.c"> <ClCompile Include="meta\svag_snk.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\ps2_tec.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps2_tk5.c"> <ClCompile Include="meta\ps2_tk5.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>

View File

@ -101,7 +101,7 @@ static const adxkey_info adxkey8_list[] = {
{0x5f5d,0x552b,0x5507, "DATAM-KK2",0}, {0x5f5d,0x552b,0x5507, "DATAM-KK2",0},
/* Sakura Taisen: Atsuki Chishio ni (PS2) [Sega] */ /* Sakura Taisen: Atsuki Chishio ni (PS2) [Sega] */
{0x645d,0x6011,0x5c29, NULL,0}, // keystring may be printf'd "%08X" + number (unlikely key: "[Seq][ADX] illegal cri or libsd status.") {0x645d,0x6011,0x5c29, "[Seq][ADX] illegal cri or libsd status.",0}, // actual keystring (obfuscation probably)
/* Sakura Taisen Monogatari: Mysterious Paris (PS2) [Sega] */ /* Sakura Taisen Monogatari: Mysterious Paris (PS2) [Sega] */
{0x62ad,0x4b13,0x5957, "inoue4126",0}, {0x62ad,0x4b13,0x5957, "inoue4126",0},

View File

@ -83,7 +83,6 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
/* checks */ /* checks */
if (!is_id32be(0x00,sf, "FORM")) if (!is_id32be(0x00,sf, "FORM"))
goto fail; goto fail;
VGM_LOG("1\n");
/* .aif: common (AIFF or AIFC), .aiff: common AIFF, .aifc: common AIFC /* .aif: common (AIFF or AIFC), .aiff: common AIFF, .aifc: common AIFC
* .laif/laiff/laifc: for plugins * .laif/laiff/laifc: for plugins

143
src/meta/hxd.c Normal file
View File

@ -0,0 +1,143 @@
#include "meta.h"
#include "../coding/coding.h"
/* HXD - from Tecmo games [Tokobot Plus (PS2), Fatal Frame 2/3 (PS2), Gallop Racer 2004 (PS2)] */
VGMSTREAM* init_vgmstream_hxd(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sf_body = NULL;
uint32_t stream_offset, header_size, stream_size, interleave, loop_start, loop_end;
int channels, loop_flag, bank, sample_rate;
int total_subsongs, target_subsong = sf->stream_index;
/* checks */
if (!is_id32be(0x00,sf, "\0DXH"))
goto fail;
/* .hxd: actual extension (filenames in companion files/exe) */
if (!check_extensions(sf, "hxd"))
goto fail;
/* 0x04: version? (0x1000) */
total_subsongs = read_u32le(0x08,sf);
bank = read_u32le(0x0c,sf);
header_size = read_u32le(0x10,sf);
interleave = read_u32le(0x14,sf); /* 0 in banks */
/* 0x18-1c: null */
/* Reject incorrectly ripped files, as .hxd is the header and data is always separate.
* Rips with header+data pasted were allowed before, but since bigfiles may store
* data first then header, audio could play wrong for no apparent reason. */
if (header_size != get_streamfile_size(sf))
goto fail;
/* .hxd has 2 modes, banks with N subsongs or bgm with N channels. In both cases
* there is header info per stream, though bgm just repeats values. */
if (bank) {
channels = 1;
}
else {
channels = total_subsongs; /* seen 1/2 */
total_subsongs = 1;
}
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
{
uint32_t info_offset = 0x20 + (target_subsong - 1) * 0x1c;
uint32_t flags;
sample_rate = read_s32le(info_offset + 0x00,sf);
stream_offset = read_u32le(info_offset + 0x04,sf);
/* 0x08: pitch? (44100=0x0EB3, 32000=0x0AAA, 22050=0759, 16000=0x5505, etc) */
/* 0x0a: volume? (usually ~0x64, up to ~0x7F) */
/* 0x0c: config? (pan, etc?) */
flags = read_u16le(info_offset + 0x10,sf);
/* 0x12: ? (seen in FF2 XB) */
loop_start = read_u32le(info_offset + 0x14,sf) * 0x20;
loop_end = read_u32le(info_offset + 0x18,sf) * 0x20;
/* flags:
* - 0x20: loop flag
* - 0x10: ? (seen in banks)
* - 0x02: ? (common in streams, not always)
* - 0x01: ? (sometimes in streams) */
loop_flag = flags & 0x20;
/* different games use different combos */
if (bank) {
sf_body = open_streamfile_by_ext(sf, "bd"); /* Gallop Racer */
if (!sf_body) {
sf_body = open_streamfile_by_ext(sf, "str"); /* just in case */
}
if (!sf_body) goto fail;
}
else {
sf_body = open_streamfile_by_ext(sf, "str"); /* Fatal Frame 2/3, Gallop Racer */
if (!sf_body) {
sf_body = open_streamfile_by_ext(sf, "at3"); /* Tokobot Plus (still ADPCM) */
}
if (!sf_body) goto fail;
}
/* size is not in the header (probably just leaves it to PS-ADPCM's EOF markets) */
if (bank && target_subsong < total_subsongs) {
/* find next usable offset (sometimes offsets repeat) */ //TODO: meh
int i;
uint32_t next_offset = 0;
for (i = target_subsong; i < total_subsongs; i++) {
next_offset = read_u32le(0x20 + i * 0x1c + 0x04,sf);
if (next_offset > stream_offset)
break;
}
if (i == total_subsongs)
next_offset = get_streamfile_size(sf_body);
if (!next_offset)
goto fail;
stream_size = next_offset - stream_offset;
}
else {
stream_size = get_streamfile_size(sf_body) - stream_offset;
}
}
/* Xbox versions of Tecmo games use RIFF (music) or WBND/.xwb (sfx) in the body. Probably a quick
* hack since they reuse extensions like .pss for movies too, for now reject. */
if (read_u32be(0x00, sf_body) != 0)
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_HXD;
vgmstream->sample_rate = sample_rate;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
vgmstream->num_samples = ps_bytes_to_samples(stream_size, channels);
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channels);
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, channels);
if (!vgmstream->loop_end_sample)
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
if (!vgmstream_open_stream(vgmstream, sf_body, stream_offset))
goto fail;
close_streamfile(sf_body);
return vgmstream;
fail:
close_streamfile(sf_body);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -240,7 +240,7 @@ VGMSTREAM * init_vgmstream_acm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_kces(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ps2_kces(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_dxh(STREAMFILE * streamFile); VGMSTREAM* init_vgmstream_hxd(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_vsv(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_vsv(STREAMFILE * streamFile);
@ -255,8 +255,6 @@ VGMSTREAM * init_vgmstream_ps2_rkv(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_vas(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ps2_vas(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_tec(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_enth(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ps2_enth(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_sdt(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_sdt(STREAMFILE * streamFile);

View File

@ -1,76 +0,0 @@
#include "meta.h"
#include "../util.h"
/* DXH (from Tokobot Plus - Mysteries of the Karakuri) */
VGMSTREAM * init_vgmstream_ps2_dxh(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag = 0;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("dxh",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x00445848) /* 0\DXH" */
goto fail;
loop_flag = (read_32bitLE(0x50,streamFile)!=0);
channel_count = read_32bitLE(0x08,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x800;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x20,streamFile);
if (read_32bitBE(0x54,streamFile) == 0) {
/* if (loop_flag) { */
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = get_streamfile_size(streamFile)*28/16/channel_count;
vgmstream->num_samples = get_streamfile_size(streamFile)*28/16/channel_count;
/* } */
} else {
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitLE(0x50,streamFile)*0x20)*28/16/channel_count;
vgmstream->loop_end_sample = (read_32bitLE(0x54,streamFile)*0x20)*28/16/channel_count;
vgmstream->num_samples = (read_32bitLE(0x54,streamFile)*0x20)*28/16/channel_count;
}
}
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile);
vgmstream->meta_type = meta_PS2_DXH;
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,93 +0,0 @@
#include "meta.h"
#include "../util.h"
/* TEC (from TECMO games) */
/* probably TECMO Vag Stream */
VGMSTREAM * init_vgmstream_ps2_tec(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
int loop_flag;
int channel_count;
int current_chunk;
off_t start_offset;
int dataBuffer = 0;
int Founddata = 0;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("tec",filename_extension(filename))) goto fail;
loop_flag = 0;
channel_count = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x0;
vgmstream->channels = channel_count;
vgmstream->sample_rate = 44100;
vgmstream->coding_type = coding_PSX_badflags;
vgmstream->num_samples = get_streamfile_size(streamFile)*28/16/channel_count;
if (loop_flag) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = get_streamfile_size(streamFile)*28/16/channel_count;
}
// Check the first frame header (should be always zero)
if ((uint8_t)(read_8bit(0x00,streamFile) != 0x0))
goto fail;
// Scan for Interleave
{
current_chunk = 16;
while (!Founddata && current_chunk < 65536) {
dataBuffer = (uint8_t)(read_8bit(current_chunk,streamFile));
if (dataBuffer == 0x0) { /* "0x0" */
Founddata = 1;
break;
}
current_chunk = current_chunk + 16;
}
}
// Cancel if we can't find an interleave
if (Founddata == 0) {
goto fail;
} else if (Founddata == 1) {
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = current_chunk;
}
// Cancel if the first flag isn't invalid/bad
if ((uint8_t)(read_8bit(0x01,streamFile) == 0x0))
goto fail;
if ((uint8_t)(read_8bit(0x01+current_chunk,streamFile) == 0x0))
goto fail;
vgmstream->meta_type = meta_PS2_TEC;
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -33,13 +33,10 @@ VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) {
/* checks /* checks
* .mib: common, but many ext-less files are renamed to this. * .mib: common, but many ext-less files are renamed to this.
* .mi4: fake .mib to force another sample rate * .mi4: fake .mib to force another sample rate */
* .vb: Tantei Jinguuji Saburo - Mikan no Rupo (PS1)
* */
streamFile->get_name(streamFile,filename,sizeof(filename)); streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("mib",filename_extension(filename)) && if (strcasecmp("mib",filename_extension(filename)) &&
strcasecmp("mi4",filename_extension(filename)) && strcasecmp("mi4",filename_extension(filename)))
strcasecmp("vb",filename_extension(filename)))
goto fail; goto fail;
/* test if raw PS-ADPCM */ /* test if raw PS-ADPCM */
@ -126,10 +123,6 @@ VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) {
if(channel_count==0) if(channel_count==0)
channel_count=1; channel_count=1;
// force no loop
if(!strcasecmp("vb",filename_extension(filename)))
loopStart=0;
// Calc Loop Points & Interleave ... // Calc Loop Points & Interleave ...
if(loopStartPointsCount>=2) { if(loopStartPointsCount>=2) {
// can't get more then 0x10 loop point ! // can't get more then 0x10 loop point !
@ -191,9 +184,6 @@ VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) {
channel_count=newChannelCount; channel_count=newChannelCount;
} }
if (!strcasecmp("vb",filename_extension(filename)))
channel_count=1;
/* build the VGMSTREAM */ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,(loopEnd!=0)); vgmstream = allocate_vgmstream(channel_count,(loopEnd!=0));
@ -210,9 +200,6 @@ VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) {
if(!strcasecmp("mi4",filename_extension(filename))) if(!strcasecmp("mi4",filename_extension(filename)))
vgmstream->sample_rate = 48000; vgmstream->sample_rate = 48000;
if (!strcasecmp("vb",filename_extension(filename)))
vgmstream->sample_rate = 22050;
vgmstream->num_samples = (int32_t)(fileLength/16/channel_count*28); vgmstream->num_samples = (int32_t)(fileLength/16/channel_count*28);
if(loopEnd!=0) { if(loopEnd!=0) {

View File

@ -984,12 +984,16 @@ fail:
} }
/* for maximum annoyance later UE4 versions (~v4.2x?) interleave single frames instead of /* for maximum annoyance later UE4 versions (~v4.2x?) interleave single frames instead of
* half interleave, but don't have flags to detect so we need some heuristics */ * half interleave, but don't have flags to detect so we need some heuristics. Most later
* games with 0x36 chunk size use v2_interleave but notably Travis Strikes Again doesn't */
static size_t get_ue4_msadpcm_interleave(STREAMFILE* sf, riff_fmt_chunk* fmt, off_t start, size_t size) { static size_t get_ue4_msadpcm_interleave(STREAMFILE* sf, riff_fmt_chunk* fmt, off_t start, size_t size) {
size_t v1_interleave = size / fmt->channels; size_t v1_interleave = size / fmt->channels;
size_t v2_interleave = fmt->block_size; size_t v2_interleave = fmt->block_size;
uint8_t nibbles1[0x08] = {0}; uint8_t nibbles_half[0x20] = {0};
uint8_t nibbles2[0x08] = {0}; uint8_t nibbles_full[0x20] = {0};
int nibbles_size = sizeof(nibbles_full);
uint8_t empty[0x20] = {0};
int is_blank_half, is_blank_full;
/* old versions */ /* old versions */
@ -997,43 +1001,56 @@ static size_t get_ue4_msadpcm_interleave(STREAMFILE* sf, riff_fmt_chunk* fmt, of
return v1_interleave; return v1_interleave;
/* 6ch only observed in later versions [Fortnite (PC)], not padded */ /* 6ch only observed in later versions [Fortnite (PC)], not padded */
if (fmt->channels > 2) if (fmt->channels > 2 || fmt->channels < 2)
return v2_interleave; return v2_interleave;
read_streamfile(nibbles1, start + size - 0x08, sizeof(nibbles2), sf); read_streamfile(nibbles_half, start + v1_interleave - nibbles_size, nibbles_size, sf);
read_streamfile(nibbles2, start + v1_interleave - 0x08, sizeof(nibbles2), sf); is_blank_half = memcmp(nibbles_half, empty, nibbles_size) == 0;
read_streamfile(nibbles_full, start + size - nibbles_size, nibbles_size, sf);
is_blank_full = memcmp(nibbles_full, empty, nibbles_size) == 0;
/* last frame is almost always padded, so should at half interleave */ /* last frame is almost always padded, so should at half interleave */
if (get_u64be(nibbles1) == 0 && get_u64be(nibbles2) == 0) if (!is_blank_half && !is_blank_full) {
VGM_LOG("v1 a\n");
return v1_interleave; return v1_interleave;
}
/* last frame is padded, and half interleave is not: should be regular interleave*/
if (!is_blank_half && is_blank_full) {
VGM_LOG("v2 a\n");
return v2_interleave;
}
VGM_LOG("i=%i, i=%i\n", is_blank_half, is_blank_full);
/* last frame is silent-ish, so should at half interleave (TSA's SML_DarknessLoop_01, TSA_CAD_YAKATA) /* last frame is silent-ish, so should at half interleave (TSA's SML_DarknessLoop_01, TSA_CAD_YAKATA)
* this doesn't work too well b/c num_samples at 0x36 uses all data, may need adjustment */ * this doesn't work too well b/c num_samples at 0x36 uses all data, may need adjustment */
{ {
int i; int i;
int empty_nibbles1 = 1, empty_nibbles2 = 1; int empty_nibbles_full = 1, empty_nibbles_half = 1;
for (i = 0; i < sizeof(nibbles1); i++) { for (i = 0; i < sizeof(nibbles_full); i++) {
uint8_t n1 = ((nibbles1[i] >> 0) & 0x0f); uint8_t n1 = ((nibbles_full[i] >> 0) & 0x0f);
uint8_t n2 = ((nibbles1[i] >> 4) & 0x0f); uint8_t n2 = ((nibbles_full[i] >> 4) & 0x0f);
if ((n1 != 0x0 && n1 != 0xf && n1 != 0x1) || (n2 != 0x0 && n2 != 0xf && n2 != 0x1)) { if ((n1 != 0x0 && n1 != 0xf && n1 != 0x1) || (n2 != 0x0 && n2 != 0xf && n2 != 0x1)) {
empty_nibbles1 = 0; empty_nibbles_full = 0;
break; break;
} }
} }
for (i = 0; i < sizeof(nibbles2); i++) { for (i = 0; i < sizeof(nibbles_half); i++) {
uint8_t n1 = ((nibbles2[i] >> 0) & 0x0f); uint8_t n1 = ((nibbles_half[i] >> 0) & 0x0f);
uint8_t n2 = ((nibbles2[i] >> 4) & 0x0f); uint8_t n2 = ((nibbles_half[i] >> 4) & 0x0f);
if ((n1 != 0x0 && n1 != 0xf && n1 != 0x1) || (n2 != 0x0 && n2 != 0xf && n2 != 0x1)) { if ((n1 != 0x0 && n1 != 0xf && n1 != 0x1) || (n2 != 0x0 && n2 != 0xf && n2 != 0x1)) {
empty_nibbles2 = 0; empty_nibbles_half = 0;
break; break;
} }
} }
if (empty_nibbles1 && empty_nibbles2) if (empty_nibbles_full && empty_nibbles_half){
VGM_LOG("v1 b\n");
return v1_interleave; return v1_interleave;
}
} }
/* other tests? */ /* other tests? */

View File

@ -80,7 +80,7 @@ VGMSTREAM* init_vgmstream_vab(STREAMFILE* sf) {
uint8_t center, shift, min_note, max_note; uint8_t center, shift, min_note, max_note;
off_t programs_off, tones_off, waves_off, entry_off, data_offset; off_t programs_off, tones_off, waves_off, entry_off, data_offset;
size_t data_size; size_t data_size;
int target_subsong = sf->stream_index, is_vh = 0, program_num, tone_num, total_subsongs, int target_subsong = sf->stream_index, is_vh = 0, program_num, tone_num = 0, total_subsongs,
note, fine, uselimits, note, fine, uselimits,
channels, loop_flag, loop_start = 0, loop_end = 0; channels, loop_flag, loop_start = 0, loop_end = 0;
int i; int i;

View File

@ -89,16 +89,18 @@ VGMSTREAM* init_vgmstream_xwb(STREAMFILE* sf) {
/* checks */ /* checks */
/* .xwb: standard if (!is_id32be(0x00,sf, "WBND") &&
* .xna: Touhou Makukasai ~ Fantasy Danmaku Festival (PC) !is_id32le(0x00,sf, "WBND")) /* X360 */
* (extensionless): Ikaruga (X360/PC), Grabbed by the Ghoulies (Xbox) */
if (!check_extensions(sf,"xwb,xna,"))
goto fail;
if ((read_u32be(0x00,sf) != 0x57424E44) && /* "WBND" (LE) */
(read_u32be(0x00,sf) != 0x444E4257)) /* "DNBW" (BE) */
goto fail; goto fail;
xwb.little_endian = read_u32be(0x00,sf) == 0x57424E44; /* WBND */ /* .xwb: standard
* .xna: Touhou Makukasai ~ Fantasy Danmaku Festival (PC)
* (extensionless): Ikaruga (X360/PC), Grabbed by the Ghoulies (Xbox)
* .bd: Fatal Frame 2 (Xbox) */
if (!check_extensions(sf,"xwb,xna,bd"))
goto fail;
xwb.little_endian = is_id32be(0x00,sf, "WBND"); /* Xbox/PC */
if (xwb.little_endian) { if (xwb.little_endian) {
read_u32 = read_u32le; read_u32 = read_u32le;
read_s32 = read_s32le; read_s32 = read_s32le;

View File

@ -9,9 +9,9 @@
/* ****************************************** */ /* ****************************************** */
int vgmstream_ctx_is_valid(const char* filename, vgmstream_ctx_valid_cfg *cfg) { int vgmstream_ctx_is_valid(const char* filename, vgmstream_ctx_valid_cfg *cfg) {
const char ** extension_list; const char** extension_list;
size_t extension_list_len; size_t extension_list_len;
const char *extension; const char* extension;
int i; int i;
@ -21,12 +21,12 @@ int vgmstream_ctx_is_valid(const char* filename, vgmstream_ctx_valid_cfg *cfg) {
extension = filename_extension(filename); extension = filename_extension(filename);
} }
/* some metas accept extensionless files, but make sure it's not a path */ /* some metas accept extensionless files, but make sure it's not a path (unlikely but...) */
if (strlen(extension) <= 0) { if (strlen(extension) <= 0) {
int len = strlen(filename); int len = strlen(filename); /* foobar passes an extension as so len may be still 0 */
if (len <= 0) if (len <= 0 && !cfg->is_extension)
return 0; return 0;
if (filename[len - 1] == '/' || filename[len - 1] == '\\') if (len > 1 && (filename[len - 1] == '/' || filename[len - 1] == '\\'))
return 0; return 0;
return !cfg->reject_extensionless; return !cfg->reject_extensionless;
} }

View File

@ -95,14 +95,13 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_acm, init_vgmstream_acm,
init_vgmstream_mus_acm, init_vgmstream_mus_acm,
init_vgmstream_ps2_kces, init_vgmstream_ps2_kces,
init_vgmstream_ps2_dxh, init_vgmstream_hxd,
init_vgmstream_vsv, init_vgmstream_vsv,
init_vgmstream_scd_pcm, init_vgmstream_scd_pcm,
init_vgmstream_ps2_pcm, init_vgmstream_ps2_pcm,
init_vgmstream_ps2_rkv, init_vgmstream_ps2_rkv,
init_vgmstream_ps2_vas, init_vgmstream_ps2_vas,
init_vgmstream_ps2_vas_container, init_vgmstream_ps2_vas_container,
init_vgmstream_ps2_tec,
init_vgmstream_ps2_enth, init_vgmstream_ps2_enth,
init_vgmstream_sdt, init_vgmstream_sdt,
init_vgmstream_aix, init_vgmstream_aix,

View File

@ -389,13 +389,12 @@ typedef enum {
meta_BG00, /* Ibara, Mushihimesama */ meta_BG00, /* Ibara, Mushihimesama */
meta_PS2_RSTM, /* Midnight Club 3 */ meta_PS2_RSTM, /* Midnight Club 3 */
meta_PS2_KCES, /* Dance Dance Revolution */ meta_PS2_KCES, /* Dance Dance Revolution */
meta_PS2_DXH, /* Tokobot Plus - Myteries of the Karakuri */ meta_HXD,
meta_VSV, meta_VSV,
meta_SCD_PCM, /* Lunar - Eternal Blue */ meta_SCD_PCM, /* Lunar - Eternal Blue */
meta_PS2_PCM, /* Konami KCEJ East: Ephemeral Fantasia, Yu-Gi-Oh! The Duelists of the Roses, 7 Blades */ meta_PS2_PCM, /* Konami KCEJ East: Ephemeral Fantasia, Yu-Gi-Oh! The Duelists of the Roses, 7 Blades */
meta_PS2_RKV, /* Legacy of Kain - Blood Omen 2 (PS2) */ meta_PS2_RKV, /* Legacy of Kain - Blood Omen 2 (PS2) */
meta_PS2_VAS, /* Pro Baseball Spirits 5 */ meta_PS2_VAS, /* Pro Baseball Spirits 5 */
meta_PS2_TEC, /* TECMO badflagged stream */
meta_PS2_ENTH, /* Enthusia */ meta_PS2_ENTH, /* Enthusia */
meta_SDT, /* Baldur's Gate - Dark Alliance */ meta_SDT, /* Baldur's Gate - Dark Alliance */
meta_NGC_TYDSP, /* Ty - The Tasmanian Tiger */ meta_NGC_TYDSP, /* Ty - The Tasmanian Tiger */