Updated VGMStream to r1640-11-gdfa3779a

CQTexperiment
Christopher Snowhill 2021-09-06 09:28:26 -07:00
parent b1f947c3b2
commit 42a6738e8f
59 changed files with 1663 additions and 1288 deletions

View File

@ -335,7 +335,6 @@
836F6FBD18BDC2190095E648 /* nwa.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8118BDC2180095E648 /* nwa.c */; };
836F6FBF18BDC2190095E648 /* otm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8318BDC2180095E648 /* otm.c */; };
836F6FC018BDC2190095E648 /* p3d.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8418BDC2180095E648 /* p3d.c */; };
836F6FC118BDC2190095E648 /* pc_adp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8518BDC2180095E648 /* pc_adp.c */; };
836F6FC218BDC2190095E648 /* pc_mxst.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8618BDC2180095E648 /* pc_mxst.c */; };
836F6FC718BDC2190095E648 /* pona.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8B18BDC2180095E648 /* pona.c */; };
836F6FC818BDC2190095E648 /* pos.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E8C18BDC2180095E648 /* pos.c */; };
@ -621,6 +620,11 @@
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 */; };
83D26A7A26E66D98001A9475 /* adp_bos.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D26A7626E66D98001A9475 /* adp_bos.c */; };
83D26A8126E66DC2001A9475 /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D26A7D26E66DC2001A9475 /* log.c */; };
83D26A8226E66DC2001A9475 /* chunks.h in Headers */ = {isa = PBXBuildFile; fileRef = 83D26A7E26E66DC2001A9475 /* chunks.h */; };
83D26A8326E66DC2001A9475 /* log.h in Headers */ = {isa = PBXBuildFile; fileRef = 83D26A7F26E66DC2001A9475 /* log.h */; settings = {ATTRIBUTES = (Public, ); }; };
83D26A8426E66DC2001A9475 /* chunks.c in Sources */ = {isa = PBXBuildFile; fileRef = 83D26A8026E66DC2001A9475 /* chunks.c */; };
83D6772D2653A30B00252130 /* libcelt_0061.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D6763026539A7200252130 /* libcelt_0061.framework */; };
83D6772E2653A31400252130 /* libcelt_0110.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D676BE26539F4F00252130 /* libcelt_0110.framework */; };
83D6772F2653A32B00252130 /* libcelt_0061.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83D6763026539A7200252130 /* libcelt_0061.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@ -1136,7 +1140,6 @@
836F6E8118BDC2180095E648 /* nwa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nwa.c; sourceTree = "<group>"; };
836F6E8318BDC2180095E648 /* otm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = otm.c; sourceTree = "<group>"; };
836F6E8418BDC2180095E648 /* p3d.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = p3d.c; sourceTree = "<group>"; };
836F6E8518BDC2180095E648 /* pc_adp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pc_adp.c; sourceTree = "<group>"; };
836F6E8618BDC2180095E648 /* pc_mxst.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pc_mxst.c; sourceTree = "<group>"; };
836F6E8B18BDC2180095E648 /* pona.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pona.c; sourceTree = "<group>"; };
836F6E8C18BDC2180095E648 /* pos.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pos.c; sourceTree = "<group>"; };
@ -1421,6 +1424,11 @@
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>"; };
83D26A7626E66D98001A9475 /* adp_bos.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adp_bos.c; sourceTree = "<group>"; };
83D26A7D26E66DC2001A9475 /* log.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = log.c; sourceTree = "<group>"; };
83D26A7E26E66DC2001A9475 /* chunks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chunks.h; sourceTree = "<group>"; };
83D26A7F26E66DC2001A9475 /* log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log.h; sourceTree = "<group>"; };
83D26A8026E66DC2001A9475 /* chunks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = chunks.c; sourceTree = "<group>"; };
83D6762B26539A7100252130 /* libcelt_0061.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libcelt_0061.xcodeproj; path = ../libcelt_0061/libcelt_0061/libcelt_0061.xcodeproj; sourceTree = "<group>"; };
83D676B926539F4E00252130 /* libcelt_0110.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libcelt_0110.xcodeproj; path = ../libcelt_0110/libcelt_0110/libcelt_0110.xcodeproj; sourceTree = "<group>"; };
83D731381A74968900CA1366 /* g719.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = g719.xcodeproj; path = ../g719/g719.xcodeproj; sourceTree = "<group>"; };
@ -1581,6 +1589,7 @@
836F6DDF18BDC2180095E648 /* coding */,
836F6DFF18BDC2180095E648 /* layout */,
836F6E2718BDC2180095E648 /* meta */,
83D26A7C26E66DC2001A9475 /* util */,
83AA7F892519C076004C5298 /* decode.c */,
83AA7F862519C076004C5298 /* decode.h */,
83A3F0711E3AD8B900D6A794 /* formats.c */,
@ -1779,6 +1788,7 @@
837CEAD623487E8300E62A4A /* acb.c */,
836F6E2B18BDC2180095E648 /* acm.c */,
83F2CCE125A5B41600F46FA8 /* acx.c */,
83D26A7626E66D98001A9475 /* adp_bos.c */,
83AA7F7A2519C042004C5298 /* adp_konami.c */,
834FE0CF215C79E8000A5D3D /* adpcm_capcom.c */,
83852B0A2680247900378854 /* ads_midway.c */,
@ -1997,7 +2007,6 @@
836F6E8318BDC2180095E648 /* otm.c */,
836F6E8418BDC2180095E648 /* p3d.c */,
8349A8FE1FE6257F00E26435 /* pc_adp_otns.c */,
836F6E8518BDC2180095E648 /* pc_adp.c */,
8349A8F01FE6257C00E26435 /* pc_ast.c */,
836F6E8618BDC2180095E648 /* pc_mxst.c */,
8306B0D12098458F000302D4 /* pcm_sre.c */,
@ -2228,6 +2237,17 @@
path = meta;
sourceTree = "<group>";
};
83D26A7C26E66DC2001A9475 /* util */ = {
isa = PBXGroup;
children = (
83D26A8026E66DC2001A9475 /* chunks.c */,
83D26A7E26E66DC2001A9475 /* chunks.h */,
83D26A7D26E66DC2001A9475 /* log.c */,
83D26A7F26E66DC2001A9475 /* log.h */,
);
path = util;
sourceTree = "<group>";
};
83D6762C26539A7200252130 /* Products */ = {
isa = PBXGroup;
children = (
@ -2270,11 +2290,13 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
83D26A8226E66DC2001A9475 /* chunks.h in Headers */,
836F705518BDC2190095E648 /* streamtypes.h in Headers */,
836F6F3518BDC2190095E648 /* nwa_decoder.h in Headers */,
83031EC9243C50A800C3F3E0 /* circus_decoder_lzxpcm.h in Headers */,
8346D97A25BF838C00D1A8B0 /* idtech_streamfile.h in Headers */,
8346D98425BF83B300D1A8B0 /* coding_utils_samples.h in Headers */,
83D26A8326E66DC2001A9475 /* log.h in Headers */,
83C7282222BC893D00678B4A /* mta2_streamfile.h in Headers */,
83AA7F802519C042004C5298 /* sab_streamfile.h in Headers */,
83A21F87201D8981000F04B9 /* fsb_keys.h in Headers */,
@ -2576,6 +2598,7 @@
8373341723F60C7B00DE14DC /* g7221_decoder_aes.c in Sources */,
836F702018BDC2190095E648 /* rkv.c in Sources */,
834FE0F4215C79ED000A5D3D /* wsi.c in Sources */,
83D26A7A26E66D98001A9475 /* adp_bos.c in Sources */,
836F703218BDC2190095E648 /* str_asr.c in Sources */,
837CEB0223487F2C00E62A4A /* raw_int.c in Sources */,
836F702818BDC2190095E648 /* sat_dvi.c in Sources */,
@ -2601,6 +2624,7 @@
836F6FB618BDC2190095E648 /* ngc_sck_dsp.c in Sources */,
836F6F2818BDC2190095E648 /* ima_decoder.c in Sources */,
837CEB072348809400E62A4A /* seb.c in Sources */,
83D26A8126E66DC2001A9475 /* log.c in Sources */,
8306B0DD20984590000302D4 /* waf.c in Sources */,
8306B0B320984552000302D4 /* blocked_thp.c in Sources */,
832BF80921E05135006F50F1 /* fag.c in Sources */,
@ -2760,7 +2784,6 @@
836F6FF318BDC2190095E648 /* ps2_rstm.c in Sources */,
8373342923F60CDC00DE14DC /* deblock_streamfile.c in Sources */,
836F6F7918BDC2190095E648 /* dc_asd.c in Sources */,
836F6FC118BDC2190095E648 /* pc_adp.c in Sources */,
836F703B18BDC2190095E648 /* vsf.c in Sources */,
836F6F8218BDC2190095E648 /* ea_schl.c in Sources */,
834FBCE826BBC7D00095647F /* tantalus_decoder.c in Sources */,
@ -2912,6 +2935,7 @@
836F6FA418BDC2190095E648 /* nds_hwas.c in Sources */,
83A21F8A201D8982000F04B9 /* fsb_encrypted.c in Sources */,
8306B0B120984552000302D4 /* blocked_halpst.c in Sources */,
83D26A8426E66DC2001A9475 /* chunks.c in Sources */,
836F6FD018BDC2190095E648 /* ps2_b1s.c in Sources */,
83AA5D181F6E2F600020821C /* mpeg_custom_utils_awc.c in Sources */,
83031ED1243C50DF00C3F3E0 /* encrypted.c in Sources */,

View File

@ -682,6 +682,6 @@ int mpc_get_samples(STREAMFILE* sf, off_t offset, int32_t* p_samples, int32_t* p
/* helper to pass a wrapped, clamped, fake extension-ed, SF to another meta */
STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, off_t subfile_offset, size_t subfile_size, const char* extension);
STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, offv_t subfile_offset, size_t subfile_size, const char* extension);
#endif /*_CODING_H*/

View File

@ -1015,21 +1015,21 @@ size_t aac_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) {
/* variable-sized var reader */
static int mpc_get_size(uint8_t* header, int header_size, int pos, int32_t* p_size) {
uint8_t tmp;
int32_t size = 0;
uint8_t tmp;
int32_t size = 0;
do {
do {
if (pos >= header_size)
return pos;
tmp = header[pos];
size = (size << 7) | (tmp & 0x7F);
pos++;
}
tmp = header[pos];
size = (size << 7) | (tmp & 0x7F);
pos++;
}
while((tmp & 0x80));
*p_size = size;
return pos;
*p_size = size;
return pos;
}
int mpc_get_samples(STREAMFILE* sf, off_t offset, int32_t* p_samples, int32_t* p_delay) {
@ -1092,8 +1092,8 @@ fail:
/* CUSTOM STREAMFILES */
/* ******************************************** */
STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, off_t subfile_offset, size_t subfile_size, const char* extension) {
STREAMFILE *new_sf = NULL;
STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, offv_t subfile_offset, size_t subfile_size, const char* extension) {
STREAMFILE* new_sf = NULL;
new_sf = open_wrap_streamfile(sf);
new_sf = open_clamp_streamfile_f(new_sf, subfile_offset, subfile_size);

View File

@ -115,9 +115,9 @@ void decode_ea_mt(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, in
* notify the decoder when a new substream begins (even with looping disabled). */
if (ch_data->loop_sample > 0 && ch_data->samples_done == ch_data->loop_sample) {
ch_data->samples_filled = 0;
ch_data->samples_discard = 0;
ch_data->samples_discard = 0;
/* offset is usually at loop_offset here, but not always (ex. loop_sample < 432) */
/* offset is usually at loop_offset here, but not always (ex. loop_sample < 432) */
ch_data->offset = ch_data->loop_offset;
utk_set_ptr(ctx, 0, 0); /* reset the buffer reader */
utk_reset(ctx); /* decoder init (all fields must be reset, for some edge cases) */

View File

@ -322,7 +322,7 @@ ffmpeg_codec_data* init_ffmpeg_header_offset_subsong(STREAMFILE* sf, uint8_t* he
goto fail;
if (size == 0 || start + size > get_streamfile_size(sf)) {
VGM_LOG("FFMPEG: wrong start+size found: %x + %x > %x \n", (uint32_t)start, (uint32_t)size, get_streamfile_size(sf));
vgm_asserti(size != 0, "FFMPEG: wrong start+size found: %x + %x > %x \n", (uint32_t)start, (uint32_t)size, get_streamfile_size(sf));
size = get_streamfile_size(sf) - start;
}

View File

@ -72,7 +72,7 @@ fail:
}
void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
int samples_done = 0;
int samples_done = 0;
const unsigned int channels = data->info.channelCount;
const unsigned int blockSize = data->info.blockSize;

View File

@ -30,25 +30,25 @@ void clHCA_delete(clHCA *);
int clHCA_DecodeHeader(clHCA *, const void *data, unsigned int size);
typedef struct clHCA_stInfo {
unsigned int version;
unsigned int headerSize;
unsigned int samplingRate;
unsigned int channelCount;
unsigned int blockSize;
unsigned int blockCount;
unsigned int version;
unsigned int headerSize;
unsigned int samplingRate;
unsigned int channelCount;
unsigned int blockSize;
unsigned int blockCount;
unsigned int encoderDelay; /* samples appended to the beginning */
unsigned int encoderPadding; /* samples appended to the end */
unsigned int loopEnabled;
unsigned int loopStartBlock;
unsigned int loopEndBlock;
unsigned int loopEnabled;
unsigned int loopStartBlock;
unsigned int loopEndBlock;
unsigned int loopStartDelay; /* samples in block before loop starts */
unsigned int loopEndPadding; /* samples in block after loop ends */
unsigned int samplesPerBlock; /* should be 1024 */
const char *comment;
unsigned int encryptionEnabled; /* requires keycode */
const char *comment;
unsigned int encryptionEnabled; /* requires keycode */
/* Derived sample formulas:
* - sample count: blockCount*samplesPerBlock - encoderDelay - encoderPadding;
/* Derived sample formulas:
* - sample count: blockCount*samplesPerBlock - encoderDelay - encoderPadding;
* - loop start sample = loopStartBlock*samplesPerBlock - encoderDelay + loopStartDelay
* - loop end sample = loopEndBlock*samplesPerBlock - encoderDelay + (samplesPerBlock - info.loopEndPadding)
*/

View File

@ -289,8 +289,8 @@ imuse_codec_data* init_imuse(STREAMFILE* sf, int channels) {
while (counter > 0) {
if (counter & i)
value += step;
step >>= 1;
counter >>= 1;
step >>= 1;
counter >>= 1;
}
data->adpcm_table[i + j * 64] = value; /* non sequential: all 64 [0]s, [1]s ... [88]s */

View File

@ -250,11 +250,11 @@ static void decode_mpeg_standard(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data
data->bytes_in_buffer = read_streamfile(data->buffer,stream->offset,data->buffer_size,stream->streamfile);
/* end of stream, fill rest with 0s */
if (data->bytes_in_buffer <= 0) {
VGM_ASSERT(samples_to_do < samples_done, "MPEG: end of stream, filling %i\n", (samples_to_do - samples_done));
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample));
break;
}
if (data->bytes_in_buffer <= 0) {
VGM_ASSERT(samples_to_do < samples_done, "MPEG: end of stream, filling %i\n", (samples_to_do - samples_done));
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample));
break;
}
data->buffer_full = 1;
data->buffer_used = 0;

View File

@ -26,8 +26,8 @@ extern void fft(int n, float* xRe, float* xIm, float* yRe, float* yIm);
#define RELIC_MAX_SIZE RELIC_SIZE_HIGH
#define RELIC_MAX_FREQ (RELIC_MAX_SIZE / 2)
#define RELIC_MAX_FFT (RELIC_MAX_SIZE / 4)
#define RELIC_MIN_BITRATE 256
#define RELIC_MAX_BITRATE 2048
#define RELIC_MIN_BITRATE 256
#define RELIC_MAX_BITRATE 2048
//#define RELIC_MAX_FRAME_SIZE ((RELIC_MAX_BITRATE / 8) + 0x04) /* extra 0x04 for the bitreader */

View File

@ -6,24 +6,22 @@
/* Based on Valery V. Anisimovsky's WS-AUD.txt */
static char WSTable2bit[4]={-2,-1,0,1};
static char WSTable4bit[16]={-9,-8,-6,-5,-4,-3,-2,-1,
0, 1, 2, 3, 4, 5 ,6, 8};
static char WSTable2bit[4] = { -2,-1,0,1 };
static char WSTable4bit[16] = { -9,-8,-6,-5,-4,-3,-2,-1, 0, 1, 2, 3, 4, 5 ,6, 8 };
/* We pass in the VGMSTREAM here, unlike in other codings, because
the decoder has to know about the block structure. */
void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channelspacing, int32_t first_sample,
int32_t samples_to_do) {
VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]);
int16_t hist = stream->adpcm_history1_16;
int16_t hist = stream->adpcm_history1_16;
off_t offset = stream->offset;
int samples_left_in_frame = stream->samples_left_in_frame;
off_t header_off = stream->frame_header_offset;
int i;
int32_t sample_count;
int i;
int32_t sample_count;
if (vgmstream->ws_output_size == vgmstream->current_block_size) {
/* uncompressed, we just need to convert to 16-bit */
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing,offset++) {

View File

@ -164,6 +164,7 @@ static const char* extension_list[] = {
"dtk",
"dvi",
"dxh",
"dyx", //txth/reserved [Shrek 4 (iOS)]
"e4x",
"eam",
@ -392,6 +393,7 @@ static const char* extension_list[] = {
"pona",
"pos",
"ps2stm", //fake extension for .stm (renamed? to be removed?)
"psb", //txth/reserved [Legend of Mana (Switch), Senxin Aleste (AC)]
"psf",
"psh", //fake extension for .vsv (to be removed)
"psnd",
@ -853,7 +855,7 @@ static const coding_info coding_info_list[] = {
{coding_FFmpeg, "FFmpeg"},
#endif
#ifdef VGM_USE_FDKAAC
{coding_MP4_AAC, "MPEG-4 AAC"},
{coding_MP4_AAC, "MPEG-4 AAC"},
#endif
};

View File

@ -239,7 +239,7 @@ void blocked_count_samples(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t offset) {
case coding_PCM8_U_int: block_samples = pcm8_bytes_to_samples(vgmstream->current_block_size, 1); break;
case coding_XBOX_IMA: block_samples = xbox_ima_bytes_to_samples(vgmstream->current_block_size, 1); break;
case coding_NGC_DSP: block_samples = dsp_bytes_to_samples(vgmstream->current_block_size, 1); break;
case coding_PSX: block_samples = ps_bytes_to_samples(vgmstream->current_block_size,1); break;
case coding_PSX: block_samples = ps_bytes_to_samples(vgmstream->current_block_size,1); break;
default:
VGM_LOG("BLOCKED: missing codec\n");
return;

View File

@ -5,7 +5,7 @@ VGMSTREAM* init_vgmstream_adp_bos(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag = 0;
int channels;
int channels;
/* checks */
if (!check_extensions(sf,"adp"))
@ -19,7 +19,7 @@ VGMSTREAM* init_vgmstream_adp_bos(STREAMFILE* sf) {
start_offset = 0x18;
/* build the VGMSTREAM */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;

View File

@ -83,14 +83,14 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) {
coding_type = coding_CRI_ADX_enc_8;
version = 0x0400;
}
VGM_ASSERT(version != 0x0400, "ADX: keystring not found\n");
vgm_asserti(version != 0x0400, "ADX: decryption keystring not found\n");
}
else if (version == 0x0409) {
if (find_adx_key(sf, 9, &xor_start, &xor_mult, &xor_add, subkey)) {
coding_type = coding_CRI_ADX_enc_9;
version = 0x0400;
}
VGM_ASSERT(version != 0x0400, "ADX: keycode not found\n");
vgm_asserti(version != 0x0400, "ADX: decryption keycode not found\n");
}
/* version + extra data */

View File

@ -234,7 +234,7 @@ static void load_awb_name(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstre
}
}
/* probably loaded */
/* probably loaded */
load_acb_wave_name(sf_acb, vgmstream, waveid, port, is_memory);
close_streamfile(sf_acb);

View File

@ -1,147 +1,154 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util.h"
static int bink_get_info(STREAMFILE *streamFile, int target_subsong, int * out_total_streams, size_t *out_stream_size, int * out_channel_count, int * out_sample_rate, int * out_num_samples);
/* BINK 1/2 - RAD Game Tools movies (audio/video format) */
VGMSTREAM * init_vgmstream_bik(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int channel_count = 0, loop_flag = 0, sample_rate = 0, num_samples = 0;
int total_subsongs = 0, target_subsong = streamFile->stream_index;
size_t stream_size;
/* checks */
/* .bik/bik2/bk2: standard
* .bika = fake extension for demuxed audio */
if (!check_extensions(streamFile,"bik,bika,bik2,bk2"))
goto fail;
/* check header "BIK" (bink 1) or "KB2" (bink 2), followed by version-char (audio is the same for both) */
if ((read_32bitBE(0x00,streamFile) & 0xffffff00) != 0x42494B00 &&
(read_32bitBE(0x00,streamFile) & 0xffffff00) != 0x4B423200 ) goto fail;
/* find target stream info and samples */
if (!bink_get_info(streamFile, target_subsong, &total_subsongs, &stream_size, &channel_count, &sample_rate, &num_samples))
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->layout_type = layout_none;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_BINK;
#ifdef VGM_USE_FFMPEG
{
/* target_subsong should be passed manually */
vgmstream->codec_data = init_ffmpeg_header_offset_subsong(streamFile, NULL,0, 0x0,get_streamfile_size(streamFile), target_subsong);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
}
#else
goto fail;
#endif
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/**
* Gets stream info, and number of samples in a BINK file by reading all frames' headers (as it's VBR),
* as they are not in the main header. The header for BINK1 and 2 is the same.
* (a ~3 min movie needs ~6000-7000 frames = fseeks, should be fast enough)
*/
static int bink_get_info(STREAMFILE *streamFile, int target_subsong, int * out_total_subsongs, size_t * out_stream_size, int * out_channel_count, int * out_sample_rate, int * out_num_samples) {
uint32_t *offsets = NULL;
uint32_t num_frames, num_samples_b = 0;
off_t cur_offset;
int i, j, sample_rate, channel_count;
int total_subsongs;
size_t stream_size = 0;
size_t filesize = get_streamfile_size(streamFile);
uint32_t signature = (read_32bitBE(0x00,streamFile) & 0xffffff00);
uint8_t revision = (read_32bitBE(0x00,streamFile) & 0xFF);
if (read_32bitLE(0x04,streamFile)+ 0x08 != filesize)
goto fail;
num_frames = (uint32_t)read_32bitLE(0x08,streamFile);
if (num_frames == 0 || num_frames > 0x100000) goto fail; /* something must be off (avoids big allocs below) */
/* multichannel/multilanguage audio is usually N streams of stereo/mono, no way to know channel layout */
total_subsongs = read_32bitLE(0x28,streamFile);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1 || total_subsongs > 255) goto fail;
/* find stream info and position in offset table */
cur_offset = 0x2c;
if ((signature == 0x42494B00 && (revision == 0x6b)) || /* k */
(signature == 0x4B423200 && (revision == 0x69 || revision == 0x6a || revision == 0x6b))) /* i,j,k */
cur_offset += 0x04; /* unknown v2 header field */
cur_offset += 0x04*total_subsongs; /* skip streams max packet bytes */
sample_rate = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x00,streamFile);
channel_count = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x02,streamFile) & 0x2000 ? 2 : 1; /* stereo flag */
cur_offset += 0x04*total_subsongs; /* skip streams info */
cur_offset += 0x04*total_subsongs; /* skip streams ids */
/* read frame offsets in a buffer, to avoid fseeking to the table back and forth */
offsets = malloc(sizeof(uint32_t) * num_frames);
if (!offsets) goto fail;
for (i=0; i < num_frames; i++) {
offsets[i] = read_32bitLE(cur_offset,streamFile) & 0xFFFFFFFE; /* mask first bit (= keyframe) */
cur_offset += 0x4;
if (offsets[i] > filesize) goto fail;
}
/* after the last index is the file size, validate just in case */
if (read_32bitLE(cur_offset,streamFile) != filesize) goto fail;
/* read each frame header and sum all samples
* a frame has N audio packets with a header (one per stream) + video packet */
for (i=0; i < num_frames; i++) {
cur_offset = offsets[i];
/* read audio packet headers per stream */
for (j=0; j < total_subsongs; j++) {
uint32_t ap_size = read_32bitLE(cur_offset+0x00,streamFile); /* not counting this int */
if (j == target_subsong-1) {
stream_size += 0x04 + ap_size;
if (ap_size > 0)
num_samples_b += read_32bitLE(cur_offset+0x04,streamFile); /* decoded samples in bytes */
break; /* next frame */
}
else { /* next stream packet or frame */
cur_offset += 4 + ap_size; //todo sometimes ap_size doesn't include itself (+4), others it does?
}
}
}
free(offsets);
if (out_total_subsongs) *out_total_subsongs = total_subsongs;
if (out_stream_size) *out_stream_size = stream_size;
if (out_sample_rate) *out_sample_rate = sample_rate;
if (out_channel_count) *out_channel_count = channel_count;
//todo returns a few more samples (~48) than binkconv.exe?
if (out_num_samples) *out_num_samples = num_samples_b / (2 * channel_count);
return 1;
fail:
free(offsets);
return 0;
}
#include "meta.h"
#include "../coding/coding.h"
#include "../util.h"
static int bink_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples);
/* BINK 1/2 - RAD Game Tools movies (audio/video format) */
VGMSTREAM* init_vgmstream_bik(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL;
int channels = 0, loop_flag = 0, sample_rate = 0, num_samples = 0;
int total_subsongs = 0, target_subsong = sf->stream_index;
size_t stream_size;
/* checks */
/* .bik/bik2/bk2: standard
* .bika: fake extension for demuxed audio */
if (!check_extensions(sf,"bik,bik2,bk2,bika"))
goto fail;
/* check bink1/2 header, followed by version-char (audio is the same) */
if ((read_32bitBE(0x00,sf) & 0xffffff00) != get_id32be("BIK\0") &&
(read_32bitBE(0x00,sf) & 0xffffff00) != get_id32be("KB2\0"))
goto fail;
/* find target stream info and samples */
if (!bink_get_info(sf, target_subsong, &total_subsongs, &stream_size, &channels, &sample_rate, &num_samples))
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->layout_type = layout_none;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_BINK;
#ifdef VGM_USE_FFMPEG
{
/* target_subsong should be passed manually */
vgmstream->codec_data = init_ffmpeg_header_offset_subsong(sf, NULL,0, 0x0,0, target_subsong);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
}
#else
goto fail;
#endif
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/**
* Gets stream info, and number of samples in a BINK file by reading all frames' headers (as it's VBR),
* as they are not in the main header. The header for BINK1 and 2 is the same.
* (a ~3 min movie needs ~6000-7000 frames = fseeks, should be fast enough)
*/
static int bink_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples) {
uint32_t* offsets = NULL;
uint32_t num_frames, num_samples_b = 0;
off_t cur_offset;
int i, j, sample_rate, channels;
int total_subsongs;
size_t stream_size = 0;
size_t filesize = get_streamfile_size(sf);
uint32_t signature = (read_32bitBE(0x00,sf) & 0xffffff00);
uint8_t revision = (read_32bitBE(0x00,sf) & 0xFF);
if (read_32bitLE(0x04,sf) + 0x08 != filesize)
goto fail;
num_frames = (uint32_t)read_32bitLE(0x08,sf);
if (num_frames == 0 || num_frames > 0x100000) goto fail; /* something must be off (avoids big allocs below) */
/* multichannel/multilanguage audio is usually N streams of stereo/mono, no way to know channel layout */
total_subsongs = read_32bitLE(0x28,sf);
if (total_subsongs < 1) {
vgm_logi("BIK: no audio in movie (ignore)\n");
goto fail;
}
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs > 255) goto fail;
/* find stream info and position in offset table */
cur_offset = 0x2c;
if ((signature == 0x42494B00 && (revision == 0x6b)) || /* k */
(signature == 0x4B423200 && (revision == 0x69 || revision == 0x6a || revision == 0x6b))) /* i,j,k */
cur_offset += 0x04; /* unknown v2 header field */
cur_offset += 0x04*total_subsongs; /* skip streams max packet bytes */
sample_rate = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x00,sf);
channels = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x02,sf) & 0x2000 ? 2 : 1; /* stereo flag */
cur_offset += 0x04*total_subsongs; /* skip streams info */
cur_offset += 0x04*total_subsongs; /* skip streams ids */
/* read frame offsets in a buffer, to avoid fseeking to the table back and forth */
offsets = malloc(sizeof(uint32_t) * num_frames);
if (!offsets) goto fail;
for (i=0; i < num_frames; i++) {
offsets[i] = read_32bitLE(cur_offset,sf) & 0xFFFFFFFE; /* mask first bit (= keyframe) */
cur_offset += 0x4;
if (offsets[i] > filesize) goto fail;
}
/* after the last index is the file size, validate just in case */
if (read_32bitLE(cur_offset,sf) != filesize) goto fail;
/* read each frame header and sum all samples
* a frame has N audio packets with a header (one per stream) + video packet */
for (i=0; i < num_frames; i++) {
cur_offset = offsets[i];
/* read audio packet headers per stream */
for (j=0; j < total_subsongs; j++) {
uint32_t ap_size = read_32bitLE(cur_offset+0x00,sf); /* not counting this int */
if (j == target_subsong-1) {
stream_size += 0x04 + ap_size;
if (ap_size > 0)
num_samples_b += read_32bitLE(cur_offset+0x04,sf); /* decoded samples in bytes */
break; /* next frame */
}
else { /* next stream packet or frame */
cur_offset += 4 + ap_size; //todo sometimes ap_size doesn't include itself (+4), others it does?
}
}
}
free(offsets);
if (p_total_subsongs) *p_total_subsongs = total_subsongs;
if (p_stream_size) *p_stream_size = stream_size;
if (p_sample_rate) *p_sample_rate = sample_rate;
if (p_channels) *p_channels = channels;
//todo returns a few more samples (~48) than binkconv.exe?
if (p_num_samples) *p_num_samples = num_samples_b / (2 * channels);
return 1;
fail:
free(offsets);
return 0;
}

View File

@ -1,5 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/chunks.h"
/* BKHD - Wwise soundbank container */
@ -19,9 +20,9 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
if (!check_extensions(sf,"bnk"))
goto fail;
if (read_u32be(0x00, sf) == 0x414B424B) /* "AKBK" [Shadowrun (X360)] */
if (is_id32be(0x00, sf, "AKBK")) /* [Shadowrun (X360)] */
base_offset = 0x0c;
if (read_u32be(base_offset + 0x00, sf) != 0x424B4844) /* "BKHD" */
if (!is_id32be(base_offset + 0x00, sf, "BKHD"))
goto fail;
big_endian = guess_endianness32bit(base_offset + 0x04, sf);
read_u32 = big_endian ? read_u32be : read_u32le;
@ -77,16 +78,41 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
subfile_size = read_u32(offset + 0x14, sf);
}
else {
off_t didx_offset, data_offset, offset;
size_t didx_size;
if (!find_chunk(sf, 0x44494458, 0x00,0, &didx_offset, &didx_size, big_endian, 0)) /* "DIDX" */
goto fail;
if (!find_chunk(sf, 0x44415441, 0x00,0, &data_offset, NULL, big_endian, 0)) /* "DATA" */
enum {
CHUNK_DIDX = 0x44494458, /* "DIDX" */
CHUNK_DATA = 0x44415441, /* "DATA" */
};
off_t didx_offset = 0, data_offset = 0, didx_size = 0, offset;
chunk_t rc = {0};
rc.be_size = big_endian;
rc.current = 0x00;
while (next_chunk(&rc, sf)) {
switch(rc.type) {
case CHUNK_DIDX:
didx_offset = rc.offset;
didx_size = rc.size;
break;
case CHUNK_DATA:
data_offset = rc.offset;
break;
default:
break;
}
}
if (!didx_offset || !data_offset)
goto fail;
total_subsongs = didx_size / 0x0c;
if (total_subsongs < 1) {
vgm_logi("BKHD: bank has no subsongs (ignore)\n");
goto fail;
}
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
if (target_subsong > total_subsongs) goto fail;
offset = didx_offset + (target_subsong - 1) * 0x0c;
subfile_id = read_u32(offset + 0x00, sf);

View File

@ -166,7 +166,7 @@ static void find_bnsf_key(STREAMFILE* sf, off_t start, g7221_codec_data* data, u
}
VGM_ASSERT(best_score > 0, "BNSF: best key=%.24s (score=%i)\n", best_key, best_score);
VGM_ASSERT(best_score < 0, "BNSF: key not found\n");
vgm_asserti(best_score < 0 , "BNSF: decryption key not found\n");
}
#define BNSF_MIN_KEY_LEN 3

View File

@ -1,68 +1,53 @@
/*
Wii U boot sound file for each game/app.
*/
#include "meta.h"
#include "../util.h"
VGMSTREAM * init_vgmstream_btsnd(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
int channel_count = 2;
int loop_flag;
off_t start_offset = 0x8;
/* check extension, case insensitive */
streamFile->get_name(streamFile, filename, sizeof(filename));
if (strcasecmp("btsnd", filename_extension(filename)))
goto fail;
/* Checking for loop start */
if (read_32bitBE(0x4, streamFile) > 0)
loop_flag = 1;
else
loop_flag = 0;
if (channel_count < 1) goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->sample_rate = 48000;
/* channels and loop flag are set by allocate_vgmstream */
// There's probably a better way to get the sample count...
vgmstream->num_samples = vgmstream->loop_end_sample = (get_streamfile_size(streamFile) - 8) / 4;
vgmstream->loop_start_sample = read_32bitBE(0x4, streamFile);
vgmstream->coding_type = coding_PCM16BE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x2; // Constant for this format
vgmstream->meta_type = meta_WIIU_BTSND;
/* open the file for reading by each channel */
{
int i;
for (i = 0; i<channel_count; i++) {
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[i].streamfile) goto fail;
vgmstream->ch[i].channel_start_offset =
vgmstream->ch[i].offset =
start_offset + i*vgmstream->interleave_block_size;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* .btsnd - Wii U boot sound file for each game/app */
VGMSTREAM* init_vgmstream_btsnd(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
int channels, loop_flag;
off_t start_offset, data_size;
int32_t num_samples, loop_start;
/* checks */
if (!check_extensions(sf, "btsnd"))
goto fail;
if (read_u32be(0x00,sf) != 0x02)
goto fail;
loop_start = read_s32be(0x04, sf);
start_offset = 0x08;
channels = 2;
loop_flag = loop_start > 0;
/* extra check since format is so simple */
data_size = get_streamfile_size(sf);
num_samples = pcm16_bytes_to_samples(data_size - start_offset, channels);
if (loop_start >= num_samples)
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_WIIU_BTSND;
vgmstream->sample_rate = 48000;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->coding_type = coding_PCM16BE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,13 +1,14 @@
#include "cri_utf.h"
#include "../util/log.h"
#define COLUMN_BITMASK_FLAG 0xf0
#define COLUMN_BITMASK_TYPE 0x0f
enum columna_flag_t {
COLUMN_FLAG_NAME = 0x10,
COLUMN_FLAG_DEFAULT = 0x20,
COLUMN_FLAG_ROW = 0x40,
COLUMN_FLAG_UNDEFINED = 0x80 /* shouldn't exist */
COLUMN_FLAG_NAME = 0x10,
COLUMN_FLAG_DEFAULT = 0x20,
COLUMN_FLAG_ROW = 0x40,
COLUMN_FLAG_UNDEFINED = 0x80 /* shouldn't exist */
};
enum column_type_t {
@ -113,7 +114,7 @@ utf_context* utf_open(STREAMFILE* sf, uint32_t table_offset, int* p_rows, const
/* 00: early (32b rows_offset?), 01: +2017 (no apparent differences) */
if (utf->version != 0x00 && utf->version != 0x01) {
VGM_LOG("@UTF: unknown version\n");
vgm_logi("@UTF: unknown version\n");
}
if (utf->table_offset + utf->table_size > get_streamfile_size(sf))
goto fail;
@ -169,7 +170,7 @@ utf_context* utf_open(STREAMFILE* sf, uint32_t table_offset, int* p_rows, const
!(utf->schema[i].flag & COLUMN_FLAG_NAME) ||
((utf->schema[i].flag & COLUMN_FLAG_DEFAULT) && (utf->schema[i].flag & COLUMN_FLAG_ROW)) ||
(utf->schema[i].flag & COLUMN_FLAG_UNDEFINED) ) {
VGM_LOG("@UTF: unknown column flag combo found\n");
vgm_logi("@UTF: unknown column flag combo found\n");
goto fail;
}
@ -197,7 +198,7 @@ utf_context* utf_open(STREAMFILE* sf, uint32_t table_offset, int* p_rows, const
//case COLUMN_TYPE_UINT128:
// value_size = 0x16;
default:
VGM_LOG("@UTF: unknown column type\n");
vgm_logi("@UTF: unknown column type\n");
goto fail;
}
@ -228,7 +229,7 @@ utf_context* utf_open(STREAMFILE* sf, uint32_t table_offset, int* p_rows, const
return utf;
fail:
utf_close(utf);
VGM_LOG("@UTF: fail\n");
vgm_logi("@UTF: init failure\n");
return NULL;
}

View File

@ -1,4 +1,5 @@
#include "deblock_streamfile.h"
#include "../util/log.h"
//todo move to utils or something

View File

@ -1,48 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
typedef struct {
uint32_t type;
uint32_t size;
uint32_t offset;
off_t current;
off_t max;
int le_type;
int be_size;
int full_size;
} chunk_t;
static int next_chunk(chunk_t* chunk, STREAMFILE* sf) {
uint32_t (*read_u32type)(off_t,STREAMFILE*) = !chunk->le_type ? read_u32be : read_u32le;
uint32_t (*read_u32size)(off_t,STREAMFILE*) = chunk->be_size ? read_u32be : read_u32le;
if (chunk->max == 0)
chunk->max = get_streamfile_size(sf);
if (chunk->current >= chunk->max)
return 0;
/* can be used to signal "stop" */
if (chunk->current < 0)
return 0;
chunk->type = read_u32type(chunk->current + 0x00,sf);
chunk->size = read_u32size(chunk->current + 0x04,sf);
chunk->offset = chunk->current + 0x04 + 0x04;
chunk->current += chunk->full_size ? chunk->size : 0x08 + chunk->size;
//;VGM_LOG("CHUNK: %x, %x, %x\n", dc.offset, chunk->type, chunk->size);
/* read past data */
if (chunk->type == 0xFFFFFFFF || chunk->size == 0xFFFFFFFF)
return 0;
/* empty chunk with 0 size, seen in some formats (XVAG uses it as end marker, Wwise doesn't) */
if (chunk->type == 0 || chunk->size == 0)
return 0;
/* more chunks remain */
return 1;
}
#include "../util/chunks.h"
enum {
CHUNK_RIFF = 0x52494646, /* "RIFF" */

View File

@ -2,49 +2,47 @@
#include "../coding/coding.h"
#include "../util.h"
/* .ADX - from Xenoblade 3D */
/* Xenoblade Chronicles 3D uses an adx extension as with
* the Wii version, but it's actually DSP ADPCM. */
VGMSTREAM * init_vgmstream_dsp_adx(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int loop_flag, channel_count;
/* .ADX - from Xenoblade 3D (3DS) */
VGMSTREAM* init_vgmstream_dsp_adx(STREAMFILE *sf) {
VGMSTREAM* vgmstream = NULL;
int loop_flag, channels;
int channel_header_spacing = 0x34;
/* check extension, case insensitive */
if (!check_extensions(streamFile,"adx")) goto fail;
/* check header */
if (read_32bitBE(0,streamFile)!=0x02000000) goto fail;
/* checks */
if (!check_extensions(sf,"adx"))
goto fail;
channel_count = read_32bitLE(0, streamFile);
loop_flag = read_16bitLE(0x6e, streamFile);
if (read_u32be(0x00,sf) != 0x02000000)
goto fail;
if (channel_count > 2 || channel_count < 0) goto fail;
channels = read_32bitLE(0, sf);
loop_flag = read_16bitLE(0x6e, sf);
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (channels > 2 || channels < 0) goto fail;
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_XB3D_ADX;
vgmstream->sample_rate = read_32bitLE(0x70,streamFile);
vgmstream->num_samples = read_32bitLE(0x74, streamFile);
vgmstream->loop_start_sample = read_32bitLE(0x78, streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x7c, streamFile);
dsp_read_coefs_le(vgmstream,streamFile, 0x4, channel_header_spacing);
vgmstream->sample_rate = read_32bitLE(0x70,sf);
vgmstream->num_samples = read_32bitLE(0x74, sf);
vgmstream->loop_start_sample = read_32bitLE(0x78, sf);
vgmstream->loop_end_sample = read_32bitLE(0x7c, sf);
dsp_read_coefs_le(vgmstream,sf, 0x4, channel_header_spacing);
/* semi-interleave: manually open streams at offset */
{
char filename[PATH_LIMIT];
int i;
streamFile->get_name(streamFile,filename,sizeof(filename));
for (i = 0; i<channel_count; i++) {
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename, STREAMFILE_DEFAULT_BUFFER_SIZE);
sf->get_name(sf,filename,sizeof(filename));
for (i = 0; i<channels; i++) {
vgmstream->ch[i].streamfile = sf->open(sf, filename, STREAMFILE_DEFAULT_BUFFER_SIZE);
vgmstream->ch[i].channel_start_offset =
vgmstream->ch[i].offset = read_32bitLE(0x34+i*channel_header_spacing, streamFile);
vgmstream->ch[i].offset = read_32bitLE(0x34+i*channel_header_spacing, sf);
if (!vgmstream->ch[i].streamfile) goto fail;
}
}

View File

@ -193,13 +193,14 @@ VGMSTREAM* init_vgmstream_ea_schl_video(STREAMFILE* sf) {
/* check extension */
/* .uv: early */
/* .dct: early-mid [ex. Need for Speed II SE (PC), FIFA 98 (PC)] */
/* .wve: early-mid [Madden NFL 99 (PC)] */
/* .mad: mid */
/* .vp6: late */
if (check_extensions(sf, "uv,dct")) {
/* starts with audio header block */
if (read_32bitBE(0x00, sf) != EA_BLOCKID_HEADER) /* "SCHl" */
goto fail;
} else if (check_extensions(sf, "mad")) {
} else if (check_extensions(sf, "mad,wve")) {
/* check initial movie block id */
if (read_32bitBE(0x00, sf) != 0x4D41446B) /* "MADk" */
goto fail;

View File

@ -18,28 +18,29 @@ typedef struct {
int32_t loop_end;
int loop_flag;
off_t sample_header_offset;
size_t sample_header_size;
size_t name_table_size;
size_t sample_data_size;
size_t base_header_size;
off_t extradata_offset;
size_t extradata_size;
uint32_t extradata_offset;
uint32_t extradata_size;
off_t stream_offset;
size_t stream_size;
off_t name_offset;
uint32_t stream_offset;
uint32_t stream_size;
uint32_t name_offset;
} fsb5_header;
/* ********************************************************************************** */
static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, fsb5_header* fsb5);
static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, STREAMFILE* sb, fsb5_header* fsb5);
/* FSB5 - Firelight's FMOD Studio SoundBank format */
VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sb = NULL;
fsb5_header fsb5 = {0};
uint32_t offset;
int target_subsong = sf->stream_index;
int i;
@ -53,7 +54,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
if (!is_id32be(0x00,sf, "FSB5"))
goto fail;
/* 0x00 is rare (seen in Tales from Space Vita) */
/* v0 is rare (seen in Tales from Space Vita) */
fsb5.version = read_u32le(0x04,sf);
if (fsb5.version != 0x00 && fsb5.version != 0x01)
goto fail;
@ -63,44 +64,48 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
fsb5.name_table_size = read_u32le(0x10,sf);
fsb5.sample_data_size = read_u32le(0x14,sf);
fsb5.codec = read_u32le(0x18,sf);
/* version 0x01 - 0x1c(4): zero, 0x24(16): hash, 0x34(8): unk
* version 0x00 has an extra field (always 0?) at 0x1c */
/* 0x1c: zero */
if (fsb5.version == 0x01) {
/* found by tests and assumed to be flags, no games known */
fsb5.flags = read_u32le(0x20,sf);
fsb5.flags = read_u32le(0x20,sf); /* found by tests and assumed to be flags, no games known */
/* 0x24: 128-bit hash */
/* 0x34: unknown (64-bit sub-hash?) */
fsb5.base_header_size = 0x3c;
}
else {
/* 0x20: zero/flags? */
/* 0x24: zero/flags? */
/* 0x28: 128-bit hash */
/* 0x38: unknown (64-bit sub-hash?) */
fsb5.base_header_size = 0x40;
}
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(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));
vgm_logi("FSB5: wrong size, expected %x + %x + %x + %x vs %x (re-rip)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(sf));
goto fail;
}
if (target_subsong == 0) target_subsong = 1;
if (target_subsong > fsb5.total_subsongs || fsb5.total_subsongs <= 0) goto fail;
fsb5.sample_header_offset = fsb5.base_header_size;
/* find target stream header and data offset, and read all needed values for later use
* (reads one by one as the size of a single stream header is variable) */
offset = fsb5.base_header_size;
for (i = 0; i < fsb5.total_subsongs; i++) {
size_t stream_header_size = 0;
off_t data_offset = 0;
uint32_t sample_mode1, sample_mode2; /* maybe one uint64? */
uint32_t stream_header_size = 0;
uint32_t data_offset = 0;
uint64_t sample_mode;
sample_mode1 = read_u32le(fsb5.sample_header_offset+0x00,sf);
sample_mode2 = read_u32le(fsb5.sample_header_offset+0x04,sf);
sample_mode = read_u64le(offset+0x00,sf);
stream_header_size += 0x08;
/* get samples */
fsb5.num_samples = ((sample_mode2 >> 2) & 0x3FFFFFFF); /* bits2: 31..2 (30) */
fsb5.num_samples = ((sample_mode >> 34) & 0x3FFFFFFF); /* bits: 63..34 (30) */
/* get offset inside data section */
/* up to 0x07FFFFFF * 0x20 = full 32b offset 0xFFFFFFE0 */
data_offset = (((sample_mode2 & 0x03) << 25) | ((sample_mode1 >> 7) & 0x1FFFFFF)) << 5; /* bits2: 1..0 (2) | bits1: 31..8 (25) */
/* get offset inside data section (max 32b offset 0xFFFFFFE0) */
data_offset = ((sample_mode >> 7) & 0x07FFFFFF) << 5; /* bits: 33..8 (25) */
/* get channels */
switch ((sample_mode1 >> 5) & 0x03) { /* bits1: 7..6 (2) */
switch ((sample_mode >> 5) & 0x03) { /* bits: 7..6 (2) */
case 0: fsb5.channels = 1; break;
case 1: fsb5.channels = 2; break;
case 2: fsb5.channels = 6; break; /* some Dark Souls 2 MPEG; some IMA ADPCM */
@ -111,7 +116,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
}
/* get sample rate */
switch ((sample_mode1 >> 1) & 0x0f) { /* bits1: 5..1 (4) */
switch ((sample_mode >> 1) & 0x0f) { /* bits: 5..1 (4) */
case 0: fsb5.sample_rate = 4000; break;
case 1: fsb5.sample_rate = 8000; break;
case 2: fsb5.sample_rate = 11000; break;
@ -129,8 +134,8 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
}
/* get extra flags */
if (sample_mode1 & 0x01) { /* bits1: 0 (1) */
off_t extraflag_offset = fsb5.sample_header_offset+0x08;
if (sample_mode & 0x01) { /* bits: 0 (1) */
uint32_t extraflag_offset = offset + 0x08;
uint32_t extraflag, extraflag_type, extraflag_size, extraflag_end;
do {
@ -217,7 +222,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
fsb5.channels = fsb5.channels * fsb5.layers;
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);
vgm_logi("FSB5: stream %i unknown flag 0x%x at %x + 0x04 + 0x%x (report)\n", i, extraflag_type, extraflag_offset, extraflag_size);
break;
}
}
@ -242,11 +247,10 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
fsb5.stream_size = fsb5.sample_data_size - data_offset;
}
else {
off_t next_data_offset;
uint32_t next_sample_mode1, next_sample_mode2;
next_sample_mode1 = read_u32le(fsb5.sample_header_offset+stream_header_size+0x00,sf);
next_sample_mode2 = read_u32le(fsb5.sample_header_offset+stream_header_size+0x04,sf);
next_data_offset = (((next_sample_mode2 & 0x03) << 25) | ((next_sample_mode1 >> 7) & 0x1FFFFFF)) << 5;
uint32_t next_data_offset;
uint64_t next_sample_mode;
next_sample_mode = read_u64le(offset+stream_header_size+0x00,sf);
next_data_offset = ((next_sample_mode >> 7) & 0x07FFFFFF) << 5;
fsb5.stream_size = next_data_offset - data_offset;
}
@ -255,9 +259,9 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
}
/* continue searching target */
fsb5.sample_header_offset += stream_header_size;
offset += stream_header_size;
}
/* target stream not found*/
if (!fsb5.stream_offset || !fsb5.stream_size)
goto fail;
@ -268,6 +272,17 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
}
/* FSB5 can hit +2GB offsets, but since decoders aren't ready to handle that use a subfile to hide big offsets
* (some FSB5 CLI versions make buggy offsets = bad output but this was fixed later) */
if (fsb5.stream_offset > 0x7FFFFFFF) {
sb = setup_subfile_streamfile(sf, fsb5.stream_offset, fsb5.stream_size, NULL);
fsb5.stream_offset = 0x00;
}
else {
sb = sf;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(fsb5.channels, fsb5.loop_flag);
if (!vgmstream) goto fail;
@ -282,7 +297,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
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,sf);
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, fsb5.name_offset, sf);
switch (fsb5.codec) {
case 0x00: /* FMOD_SOUND_FORMAT_NONE */
@ -301,11 +316,11 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
break;
case 0x03: /* FMOD_SOUND_FORMAT_PCM24 */
VGM_LOG("FSB5: FMOD_SOUND_FORMAT_PCM24 found\n");
vgm_logi("FSB5: FMOD_SOUND_FORMAT_PCM24 found (report)\n");
goto fail;
case 0x04: /* FMOD_SOUND_FORMAT_PCM32 */
VGM_LOG("FSB5: FMOD_SOUND_FORMAT_PCM32 found\n");
vgm_logi("FSB5: FMOD_SOUND_FORMAT_PCM32 found (report)\n");
goto fail;
case 0x05: /* FMOD_SOUND_FORMAT_PCMFLOAT [Anima: Gate of Memories (PC)] */
@ -325,7 +340,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = 0x02;
}
dsp_read_coefs_be(vgmstream,sf,fsb5.extradata_offset,0x2E);
dsp_read_coefs_be(vgmstream, sf, fsb5.extradata_offset, 0x2E);
break;
case 0x07: /* FMOD_SOUND_FORMAT_IMAADPCM [Skylanders] */
@ -359,12 +374,12 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
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(sf, buf,bytes, fsb5.stream_offset,fsb5.stream_size);
vgmstream->codec_data = init_ffmpeg_header_offset(sb, 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, sf, fsb5.stream_offset,fsb5.stream_size, 0, 0,0); /* samples look ok */
xma_fix_raw_samples(vgmstream, sb, fsb5.stream_offset, fsb5.stream_size, 0, 0,0); /* samples look ok */
break;
}
#endif
@ -375,7 +390,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
cfg.fsb_padding = (vgmstream->channels > 2 ? 16 : 4); /* observed default */
vgmstream->codec_data = init_mpeg_custom(sf, fsb5.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
vgmstream->codec_data = init_mpeg_custom(sb, fsb5.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
break;
@ -387,7 +402,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
fsb5.layers = (fsb5.channels <= 2) ? 1 : (fsb5.channels+1) / 2;
if (fsb5.layers > 1) {
vgmstream->layout_data = build_layered_fsb5(sf, &fsb5);
vgmstream->layout_data = build_layered_fsb5(sf, sb, &fsb5);
if (!vgmstream->layout_data) goto fail;
vgmstream->coding_type = coding_CELT_FSB;
vgmstream->layout_type = layout_layered;
@ -415,7 +430,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
if (fsb5.layers > 1) {
/* multichannel made of various layers [Little Big Planet (Vita)] */
vgmstream->layout_data = build_layered_fsb5(sf, &fsb5);
vgmstream->layout_data = build_layered_fsb5(sf, sb, &fsb5);
if (!vgmstream->layout_data) goto fail;
vgmstream->coding_type = coding_ATRAC9;
vgmstream->layout_type = layout_layered;
@ -449,7 +464,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
/* 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(sf, buf,bytes, fsb5.stream_offset,fsb5.stream_size);
vgmstream->codec_data = init_ffmpeg_header_offset(sb, buf,bytes, fsb5.stream_offset, fsb5.stream_size);
if ( !vgmstream->codec_data ) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
@ -465,7 +480,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
cfg.sample_rate = fsb5.sample_rate;
cfg.setup_id = read_u32le(fsb5.extradata_offset,sf);
vgmstream->codec_data = init_vorbis_custom(sf, fsb5.stream_offset, VORBIS_FSB, &cfg);
vgmstream->codec_data = init_vorbis_custom(sb, fsb5.stream_offset, VORBIS_FSB, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_VORBIS_custom;
vgmstream->layout_type = layout_none;
@ -479,13 +494,13 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
vgmstream->interleave_block_size = 0x8c;
break;
#if 0 //disabled until some game is found, can be created in the GUI tool
#if 0 //disabled until some game is found, can be created in the GUI tool
#ifdef VGM_USE_FFMPEG
case 0x11: { /* FMOD_SOUND_FORMAT_OPUS */
int skip = 312; //fsb_opus_get_encoder_delay(fsb5.stream_offset, sf); /* returns 120 but this seems correct */
int skip = 312; //fsb_opus_get_encoder_delay(fsb5.stream_offset, sb); /* returns 120 but this seems correct */
//vgmstream->num_samples -= skip;
vgmstream->codec_data = init_ffmpeg_fsb_opus(sf, fsb5.stream_offset, fsb5.stream_size, vgmstream->channels, skip, vgmstream->sample_rate);
vgmstream->codec_data = init_ffmpeg_fsb_opus(sb, fsb5.stream_offset, fsb5.stream_size, vgmstream->channels, skip, vgmstream->sample_rate);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
@ -494,22 +509,24 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
#endif
#endif
default:
VGM_LOG("FSB5: unknown codec %x found\n", fsb5.codec);
vgm_logi("FSB5: unknown codec 0x%x (report)\n", fsb5.codec);
goto fail;
}
if (!vgmstream_open_stream(vgmstream,sf,fsb5.stream_offset))
if (!vgmstream_open_stream(vgmstream, sb, fsb5.stream_offset))
goto fail;
if (sb != sf) close_streamfile(sb);
return vgmstream;
fail:
if (sb != sf) close_streamfile(sb);
close_vgmstream(vgmstream);
return NULL;
}
static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, fsb5_header* fsb5) {
static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, STREAMFILE* sb, fsb5_header* fsb5) {
layered_layout_data* data = NULL;
STREAMFILE* temp_sf = NULL;
size_t interleave, config = 0;
@ -526,9 +543,9 @@ static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, fsb5_header* fsb5
/* 2ch+2ch..+1ch or 2ch+2ch..+2ch = check last layer */
layer_channels = (i+1 == fsb5->layers && fsb5->channels % 2 == 1) ? 1 : 2;
if (read_u32be(fsb5->stream_offset+0x00,sf) != 0x17C30DF3) /* FSB CELT frame ID */
if (read_u32be(fsb5->stream_offset+0x00,sb) != 0x17C30DF3) /* FSB CELT frame ID */
goto fail;
interleave = 0x04+0x04+read_u32le(fsb5->stream_offset+0x04,sf); /* frame size */
interleave = 0x04+0x04+read_u32le(fsb5->stream_offset+0x04,sb); /* 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
@ -609,7 +626,7 @@ static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, fsb5_header* fsb5
}
temp_sf = setup_fsb5_streamfile(sf, fsb5->stream_offset, fsb5->stream_size, fsb5->layers, i, interleave);
temp_sf = setup_fsb5_streamfile(sb, fsb5->stream_offset, fsb5->stream_size, fsb5->layers, i, interleave);
if (!temp_sf) goto fail;
if (!vgmstream_open_stream(data->layers[i], temp_sf, 0x00))

View File

@ -128,7 +128,7 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
}
}
//;VGM_LOG("FSB5 FEV: offset=%lx, size=%x\n", subfile_offset,subfile_size);
//;VGM_LOG("FSB5 FEV: offset=%lx, size=%x\n", subfile_offset,subfile_size);
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, "fsb");
if (!temp_sf) goto fail;

View File

@ -30,7 +30,10 @@ VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) {
/* init vgmstream and library's context, will validate the HCA */
hca_data = init_hca(sf);
if (!hca_data) goto fail;
if (!hca_data) {
vgm_logi("HCA: unknown format (report)\n");
goto fail;
}
hca_info = hca_get_info(hca_data);
@ -184,7 +187,7 @@ static void find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t
done:
VGM_ASSERT(best_score > 1, "HCA: best key=%08x%08x (score=%i)\n",
(uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), best_score);
VGM_ASSERT(best_score < 0, "HCA: key not found\n");
vgm_asserti(best_score < 0, "HCA: decryption key not found\n");
}
#ifdef HCA_BRUTEFORCE

View File

@ -722,6 +722,9 @@ static const hcakey_info hcakey_list[] = {
// m HOLD'EM (Android)
{369211553984367}, // 00014FCBC385AF6F
// Sonic Colors Ultimate (multi)
{1991062320101111}, // 000712DC5250B6F7
};
#endif/*_HCA_KEYS_H_*/

View File

@ -23,8 +23,8 @@ typedef struct {
uint32_t channel_layout;
int is_external;
off_t stream_offsets[MAX_CHANNELS];
size_t stream_sizes[MAX_CHANNELS];
uint32_t stream_offsets[MAX_CHANNELS];
uint32_t stream_sizes[MAX_CHANNELS];
off_t sound_name_offset;
off_t config_name_offset;

View File

@ -1,50 +1,50 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
/* MUSC - from Krome's PS2 games (The Legend of Spyro, Ty the Tasmanian Tiger) */
VGMSTREAM * init_vgmstream_musc(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int loop_flag, channel_count;
off_t start_offset;
size_t data_size;
/* .mus is the real extension, .musc is the header ID */
if (!check_extensions(streamFile,"mus,musc"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4D555343) /* "MUSC" */
goto fail;
start_offset = read_32bitLE(0x10,streamFile);
data_size = read_32bitLE(0x14,streamFile);
if (start_offset + data_size != get_streamfile_size(streamFile))
goto fail;
/* always does full loops unless it ends in silence */
loop_flag = read_32bitBE(get_streamfile_size(streamFile) - 0x10,streamFile) != 0x0C000000;
channel_count = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x06,streamFile);
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->meta_type = meta_MUSC;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitLE(0x18,streamFile) / 2;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
/* MUSC - from Krome's PS2 games (The Legend of Spyro, Ty the Tasmanian Tiger) */
VGMSTREAM* init_vgmstream_musc(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
int loop_flag, channels;
off_t start_offset;
size_t data_size;
/* checks */
/* .mus: actual extension
* .musc: header ID */
if (!check_extensions(sf,"mus,musc"))
goto fail;
if (!is_id32be(0x00,sf, "MUSC"))
goto fail;
start_offset = read_u32le(0x10,sf);
data_size = read_u32le(0x14,sf);
if (start_offset + data_size != get_streamfile_size(sf))
goto fail;
/* always does full loops unless it ends in silence */
loop_flag = read_u32be(get_streamfile_size(sf) - 0x10,sf) != 0x0C000000;
channels = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_u16le(0x06,sf);
vgmstream->num_samples = ps_bytes_to_samples(data_size, channels);
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->meta_type = meta_MUSC;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_u32le(0x18,sf) / 2;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -279,6 +279,8 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk
}
default:
/* FFmpeg may play it */
//vgm_logi("WWISE: unknown codec 0x%04x (report)\n", fmt->format);
goto fail;
}
@ -418,8 +420,10 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
}
/* check for truncated RIFF */
if (file_size != riff_size + 0x08)
if (file_size != riff_size + 0x08) {
vgm_logi("RIFF: wrong expected size (report/re-rip?)\n");
goto fail;
}
/* read through chunks to verify format and find metadata */
{

View File

@ -1,187 +1,192 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util.h"
static int smacker_get_info(STREAMFILE *streamFile, int target_subsong, int * out_total_streams, size_t *out_stream_size, int * out_channel_count, int * out_sample_rate, int * out_num_samples);
/* SMK - RAD Game Tools Smacker movies (audio/video format) */
VGMSTREAM * init_vgmstream_smk(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int channel_count = 0, loop_flag = 0, sample_rate = 0, num_samples = 0;
int total_subsongs = 0, target_subsong = streamFile->stream_index;
size_t stream_size;
/* checks */
if (!check_extensions(streamFile,"smk"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x534D4B32 && /* "SMK2" */
read_32bitBE(0x00,streamFile) != 0x534D4B34) /* "SMK4" */
goto fail;
/* find target stream info */
if (!smacker_get_info(streamFile, target_subsong, &total_subsongs, &stream_size, &channel_count, &sample_rate, &num_samples))
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->layout_type = layout_none;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_SMACKER;
{
#ifdef VGM_USE_FFMPEG
/* target_subsong should be passed manually */
vgmstream->codec_data = init_ffmpeg_header_offset_subsong(streamFile, NULL,0, 0x0,get_streamfile_size(streamFile), target_subsong);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
#else
goto fail;
#endif
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
typedef enum {
SMK_AUDIO_PACKED = (1<<7),
SMK_AUDIO_PRESENT = (1<<6),
SMK_AUDIO_16BITS = (1<<5),
SMK_AUDIO_STEREO = (1<<4),
SMK_AUDIO_BINK_RDFT = (1<<3),
SMK_AUDIO_BINK_DCT = (1<<2),
//SMK_AUD_UNUSED1 = (1<<1),
//SMK_AUD_UNUSED0 = (1<<0),
} smk_audio_flag;
//todo test multilang streams and codecs other than SMACKAUD
/* Gets stream info, and number of samples in a file by reading frames
* info: https://wiki.multimedia.cx/index.php/Smacker */
static int smacker_get_info(STREAMFILE *sf, int target_subsong, int * out_total_subsongs, size_t * out_stream_size, int * out_channel_count, int * out_sample_rate, int * out_num_samples) {
STREAMFILE *sf_index = NULL;
uint32_t flags, total_frames, trees_sizes;
off_t size_offset, type_offset, data_offset;
int i, j, sample_rate = 0, channel_count = 0, num_samples = 0;
int total_subsongs, target_stream = 0;
size_t stream_size = 0;
uint8_t stream_flags = 0;
/* rough format:
* - header (id, frames, video info/config, audio info)
* - frame sizes table
* - frame info table
* - huffman trees
* - frame data
*/
/* read header */
total_frames = read_u32le(0x0c,sf);
if (total_frames <= 0 || total_frames > 0x100000) goto fail; /* something must be off */
flags = read_u32le(0x14,sf);
if (flags & 1) /* extra "ring frame" */
total_frames += 1;
trees_sizes = read_u32le(0x34,sf);
if (target_subsong == 0) target_subsong = 1;
total_subsongs = 0;
for (i = 0; i < 7; i++) { /* up to 7 audio (multilang?) streams */
uint32_t audio_info = read_u32le(0x48 + 0x04*i,sf);
uint8_t audio_flags = (audio_info >> 24) & 0xFF;
int audio_rate = audio_info & 0x00FFFFFF;
if (audio_flags & SMK_AUDIO_PRESENT) {
total_subsongs++;
if (target_subsong == total_subsongs) {
target_stream = i;
sample_rate = audio_rate & 0x00FFFFFF;
channel_count = (audio_flags & SMK_AUDIO_STEREO) ? 2 : 1;
stream_flags = audio_flags;
}
}
}
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
if (sample_rate == 0 || channel_count == 0) goto fail;
/* read size and type tables into buffer */
sf_index = reopen_streamfile(sf, total_frames*0x04 + total_frames*0x01);
if (!sf_index) goto fail;
/* read frames and sum all samples, since some codecs are VBR */
size_offset = 0x68;
type_offset = size_offset + total_frames*0x04;
data_offset = type_offset + total_frames*0x01 + trees_sizes;
for (i=0; i < total_frames; i++) {
uint32_t frame_size = read_u32le(size_offset,sf_index) & 0xFFFFFFFC; /* last 2 bits are keyframe flags */
uint8_t frame_type = read_u8 (type_offset,sf_index); /* 0: has palette, 1..7: has stream N) */
off_t offset = data_offset;
/* skip palette */
if (frame_type & (1<<0)) {
uint8_t palette_size = read_u8(offset,sf);
offset += palette_size * 4;
}
/* read target audio packet and ignore rest (though probably all streams are the same) */
for (j = 0; j < 7; j++) {
uint32_t audio_size;
/* check if stream N exists in this frame (supposedly streams can be go in separate frames) */
if ( !(frame_type & (1<<(j+1))) )
continue;
audio_size = read_u32le(offset,sf);
if (j == target_stream) {
/* resulting PCM bytes to samples */
if (stream_flags & SMK_AUDIO_PACKED) { /* Smacker and maybe Bink codecs */
uint32_t unpacked_size = read_u32le(offset+0x04,sf);
num_samples += unpacked_size / (0x02 * channel_count);
}
else if (stream_flags & SMK_AUDIO_16BITS) { /* PCM16 */
num_samples += (audio_size - 0x04) / (0x02 * channel_count);
}
else { /* PCM8 */
num_samples += (audio_size - 0x04) / (0x01 * channel_count);
}
}
stream_size += audio_size;
offset += audio_size;
}
/* rest is video packet (size = offset - data_offset) */
size_offset += 0x04;
type_offset += 0x01;
data_offset += frame_size;
}
if (out_total_subsongs) *out_total_subsongs = total_subsongs;
if (out_stream_size) *out_stream_size = stream_size;
if (out_sample_rate) *out_sample_rate = sample_rate;
if (out_channel_count) *out_channel_count = channel_count;
if (out_num_samples) *out_num_samples = num_samples;
close_streamfile(sf_index);
return 1;
fail:
close_streamfile(sf_index);
return 0;
}
#include "meta.h"
#include "../coding/coding.h"
#include "../util.h"
static int smacker_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples);
/* SMK - RAD Game Tools older Smacker movies (audio/video format) */
VGMSTREAM* init_vgmstream_smk(STREAMFILE *sf) {
VGMSTREAM* vgmstream = NULL;
int channels = 0, loop_flag = 0, sample_rate = 0, num_samples = 0;
int total_subsongs = 0, target_subsong = sf->stream_index;
size_t stream_size;
/* checks */
if (!check_extensions(sf,"smk"))
goto fail;
if (!is_id32be(0x00,sf, "SMK2") &&
!is_id32be(0x00,sf, "SMK4"))
goto fail;
/* find target stream info */
if (!smacker_get_info(sf, target_subsong, &total_subsongs, &stream_size, &channels, &sample_rate, &num_samples))
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_SMACKER;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
{
#ifdef VGM_USE_FFMPEG
/* target_subsong should be passed manually */
vgmstream->codec_data = init_ffmpeg_header_offset_subsong(sf, NULL,0, 0x00, 0, target_subsong);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
#else
goto fail;
#endif
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
typedef enum {
SMK_AUDIO_PACKED = (1<<7),
SMK_AUDIO_PRESENT = (1<<6),
SMK_AUDIO_16BITS = (1<<5),
SMK_AUDIO_STEREO = (1<<4),
SMK_AUDIO_BINK_RDFT = (1<<3),
SMK_AUDIO_BINK_DCT = (1<<2),
//SMK_AUD_UNUSED1 = (1<<1),
//SMK_AUD_UNUSED0 = (1<<0),
} smk_audio_flag;
//todo test multilang streams and codecs other than SMACKAUD
/* Gets stream info, and number of samples in a file by reading frames
* info: https://wiki.multimedia.cx/index.php/Smacker */
static int smacker_get_info(STREAMFILE* sf, int target_subsong, int* out_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples) {
STREAMFILE* sf_index = NULL;
uint32_t flags, total_frames, trees_sizes;
off_t size_offset, type_offset, data_offset;
int i, j, sample_rate = 0, channels = 0, num_samples = 0;
int total_subsongs, target_stream = 0;
size_t stream_size = 0;
uint8_t stream_flags = 0;
/* rough format:
* - header (id, frames, video info/config, audio info)
* - frame sizes table
* - frame info table
* - huffman trees
* - frame data
*/
/* read header */
total_frames = read_u32le(0x0c,sf);
if (total_frames <= 0 || total_frames > 0x100000) goto fail; /* something must be off */
flags = read_u32le(0x14,sf);
if (flags & 1) /* extra "ring frame" */
total_frames += 1;
trees_sizes = read_u32le(0x34,sf);
if (target_subsong == 0) target_subsong = 1;
total_subsongs = 0;
for (i = 0; i < 7; i++) { /* up to 7 audio (multilang?) streams */
uint32_t audio_info = read_u32le(0x48 + 0x04*i,sf);
uint8_t audio_flags = (audio_info >> 24) & 0xFF;
int audio_rate = audio_info & 0x00FFFFFF;
if (audio_flags & SMK_AUDIO_PRESENT) {
total_subsongs++;
if (target_subsong == total_subsongs) {
target_stream = i;
sample_rate = audio_rate & 0x00FFFFFF;
channels = (audio_flags & SMK_AUDIO_STEREO) ? 2 : 1;
stream_flags = audio_flags;
}
}
}
if (total_subsongs < 1) {
vgm_logi("SMK: no audio in movie (ignore)\n");
goto fail;
}
if (target_subsong < 0 || target_subsong > total_subsongs) goto fail;
if (sample_rate == 0 || channels == 0) goto fail;
/* read size and type tables into buffer */
sf_index = reopen_streamfile(sf, total_frames*0x04 + total_frames*0x01);
if (!sf_index) goto fail;
/* read frames and sum all samples, since some codecs are VBR */
size_offset = 0x68;
type_offset = size_offset + total_frames*0x04;
data_offset = type_offset + total_frames*0x01 + trees_sizes;
for (i = 0; i < total_frames; i++) {
uint32_t frame_size = read_u32le(size_offset,sf_index) & 0xFFFFFFFC; /* last 2 bits are keyframe flags */
uint8_t frame_type = read_u8 (type_offset,sf_index); /* 0: has palette, 1..7: has stream N) */
off_t offset = data_offset;
/* skip palette */
if (frame_type & (1<<0)) {
uint8_t palette_size = read_u8(offset,sf);
offset += palette_size * 4;
}
/* read target audio packet and ignore rest (though probably all streams are the same) */
for (j = 0; j < 7; j++) {
uint32_t audio_size;
/* check if stream N exists in this frame (supposedly streams can be go in separate frames) */
if ( !(frame_type & (1<<(j+1))) )
continue;
audio_size = read_u32le(offset,sf);
if (j == target_stream) {
/* resulting PCM bytes to samples */
if (stream_flags & SMK_AUDIO_PACKED) { /* Smacker and maybe Bink codecs */
uint32_t unpacked_size = read_u32le(offset+0x04,sf);
num_samples += unpacked_size / (0x02 * channels);
}
else if (stream_flags & SMK_AUDIO_16BITS) { /* PCM16 */
num_samples += (audio_size - 0x04) / (0x02 * channels);
}
else { /* PCM8 */
num_samples += (audio_size - 0x04) / (0x01 * channels);
}
}
stream_size += audio_size;
offset += audio_size;
}
/* rest is video packet (size = offset - data_offset) */
size_offset += 0x04;
type_offset += 0x01;
data_offset += frame_size;
}
if (out_total_subsongs) *out_total_subsongs = total_subsongs;
if (p_stream_size) *p_stream_size = stream_size;
if (p_sample_rate) *p_sample_rate = sample_rate;
if (p_channels) *p_channels = channels;
if (p_num_samples) *p_num_samples = num_samples;
close_streamfile(sf_index);
return 1;
fail:
close_streamfile(sf_index);
return 0;
}

View File

@ -100,8 +100,12 @@ VGMSTREAM* init_vgmstream_sqex_scd(STREAMFILE* sf) {
target_entry = i;
}
}
if (meta_offset == 0) goto fail;
/* SCD can contain 0 entries too */
if (meta_offset == 0) {
vgm_logi("SQEX SCD: bank has no subsongs (ignore)\n");
goto fail;
}
}
/** stream header **/

View File

@ -765,7 +765,7 @@ static void parse_sead_sab_name(sead_header *sead, STREAMFILE *sf) {
}
static int parse_sead(sead_header *sead, STREAMFILE *sf) {
static int parse_sead(sead_header* sead, STREAMFILE* sf) {
uint32_t (*read_u32)(off_t,STREAMFILE*) = sead->big_endian ? read_u32be : read_u32le;
uint16_t (*read_u16)(off_t,STREAMFILE*) = sead->big_endian ? read_u16be : read_u16le;
@ -856,8 +856,10 @@ static int parse_sead(sead_header *sead, STREAMFILE *sf) {
}
/* SAB can contain 0 entries too */
if (sead->mtrl_offset == 0)
if (sead->mtrl_offset == 0) {
vgm_logi("SQEX SEAD: bank has no subsongs (ignore)\n");
goto fail;
}
}
/** stream header **/

View File

@ -40,12 +40,14 @@ typedef enum {
ASF = 30, /* Argonaut ASF 4-bit ADPCM */
EAXA = 31, /* Electronic Arts EA-XA 4-bit ADPCM v1 */
OKI4S = 32, /* OKI ADPCM with 16-bit output (unlike OKI/VOX/Dialogic ADPCM's 12-bit) */
} txth_type;
UNKNOWN = 99,
} txth_codec_t;
typedef enum { DEFAULT, NEGATIVE, POSITIVE, INVERTED } txth_loop_t;
typedef struct {
txth_type codec;
txth_codec_t codec;
uint32_t codec_mode;
uint32_t value_mul;
@ -196,6 +198,25 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
}
/* set common interleaves to simplify usage
* (maybe should ignore if manually overwritten, possibly with 0 on purpose?) */
if (txth.interleave == 0) {
uint32_t interleave = 0;
switch(txth.codec) {
case PSX: interleave = 0x10; break;
case PSX_bf: interleave = 0x10; break;
case NGC_DSP: interleave = 0x08; break;
case PCM16LE: interleave = 0x02; break;
case PCM16BE: interleave = 0x02; break;
case PCM8: interleave = 0x01; break;
case PCM8_U: interleave = 0x01; break;
default:
break;
}
txth.interleave = interleave;
}
/* type to coding conversion */
switch (txth.codec) {
case PSX: coding = coding_PSX; break;
@ -881,63 +902,61 @@ fail:
return 0;
}
static txth_codec_t parse_codec(txth_header* txth, const char* val) {
if (is_string(val,"PSX")) return PSX;
else if (is_string(val,"XBOX")) return XBOX;
else if (is_string(val,"NGC_DTK")) return NGC_DTK;
else if (is_string(val,"DTK")) return NGC_DTK;
else if (is_string(val,"PCM16BE")) return PCM16BE;
else if (is_string(val,"PCM16LE")) return PCM16LE;
else if (is_string(val,"PCM8")) return PCM8;
else if (is_string(val,"SDX2")) return SDX2;
else if (is_string(val,"DVI_IMA")) return DVI_IMA;
else if (is_string(val,"MPEG")) return MPEG;
else if (is_string(val,"IMA")) return IMA;
else if (is_string(val,"AICA")) return AICA;
else if (is_string(val,"MSADPCM")) return MSADPCM;
else if (is_string(val,"NGC_DSP")) return NGC_DSP;
else if (is_string(val,"DSP")) return NGC_DSP;
else if (is_string(val,"PCM8_U_int")) return PCM8_U_int;
else if (is_string(val,"PSX_bf")) return PSX_bf;
else if (is_string(val,"MS_IMA")) return MS_IMA;
else if (is_string(val,"PCM8_U")) return PCM8_U;
else if (is_string(val,"APPLE_IMA4")) return APPLE_IMA4;
else if (is_string(val,"ATRAC3")) return ATRAC3;
else if (is_string(val,"ATRAC3PLUS")) return ATRAC3PLUS;
else if (is_string(val,"XMA1")) return XMA1;
else if (is_string(val,"XMA2")) return XMA2;
else if (is_string(val,"FFMPEG")) return FFMPEG;
else if (is_string(val,"AC3")) return AC3;
else if (is_string(val,"PCFX")) return PCFX;
else if (is_string(val,"PCM4")) return PCM4;
else if (is_string(val,"PCM4_U")) return PCM4_U;
else if (is_string(val,"OKI16")) return OKI16;
else if (is_string(val,"OKI4S")) return OKI4S;
else if (is_string(val,"AAC")) return AAC;
else if (is_string(val,"TGC")) return TGC;
else if (is_string(val,"GCOM_ADPCM")) return TGC;
else if (is_string(val,"ASF")) return ASF;
else if (is_string(val,"EAXA")) return EAXA;
/* special handling */
else if (is_string(val,"name_value")) return txth->name_values[0];
else if (is_string(val,"name_value1")) return txth->name_values[0];
else if (is_string(val,"name_value2")) return txth->name_values[1];
else if (is_string(val,"name_value3")) return txth->name_values[2];
//todo rest (handle in function)
return UNKNOWN;
}
static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, char* val) {
//;VGM_LOG("TXTH: key=%s, val=%s\n", key, val);
/* CODEC */
if (is_string(key,"codec")) {
if (is_string(val,"PSX")) txth->codec = PSX;
else if (is_string(val,"XBOX")) txth->codec = XBOX;
else if (is_string(val,"NGC_DTK")) txth->codec = NGC_DTK;
else if (is_string(val,"DTK")) txth->codec = NGC_DTK;
else if (is_string(val,"PCM16BE")) txth->codec = PCM16BE;
else if (is_string(val,"PCM16LE")) txth->codec = PCM16LE;
else if (is_string(val,"PCM8")) txth->codec = PCM8;
else if (is_string(val,"SDX2")) txth->codec = SDX2;
else if (is_string(val,"DVI_IMA")) txth->codec = DVI_IMA;
else if (is_string(val,"MPEG")) txth->codec = MPEG;
else if (is_string(val,"IMA")) txth->codec = IMA;
else if (is_string(val,"AICA")) txth->codec = AICA;
else if (is_string(val,"MSADPCM")) txth->codec = MSADPCM;
else if (is_string(val,"NGC_DSP")) txth->codec = NGC_DSP;
else if (is_string(val,"DSP")) txth->codec = NGC_DSP;
else if (is_string(val,"PCM8_U_int")) txth->codec = PCM8_U_int;
else if (is_string(val,"PSX_bf")) txth->codec = PSX_bf;
else if (is_string(val,"MS_IMA")) txth->codec = MS_IMA;
else if (is_string(val,"PCM8_U")) txth->codec = PCM8_U;
else if (is_string(val,"APPLE_IMA4")) txth->codec = APPLE_IMA4;
else if (is_string(val,"ATRAC3")) txth->codec = ATRAC3;
else if (is_string(val,"ATRAC3PLUS")) txth->codec = ATRAC3PLUS;
else if (is_string(val,"XMA1")) txth->codec = XMA1;
else if (is_string(val,"XMA2")) txth->codec = XMA2;
else if (is_string(val,"FFMPEG")) txth->codec = FFMPEG;
else if (is_string(val,"AC3")) txth->codec = AC3;
else if (is_string(val,"PCFX")) txth->codec = PCFX;
else if (is_string(val,"PCM4")) txth->codec = PCM4;
else if (is_string(val,"PCM4_U")) txth->codec = PCM4_U;
else if (is_string(val,"OKI16")) txth->codec = OKI16;
else if (is_string(val,"OKI4S")) txth->codec = OKI4S;
else if (is_string(val,"AAC")) txth->codec = AAC;
else if (is_string(val,"TGC")) txth->codec = TGC;
else if (is_string(val,"GCOM_ADPCM")) txth->codec = TGC;
else if (is_string(val,"ASF")) txth->codec = ASF;
else if (is_string(val,"EAXA")) txth->codec = EAXA;
else goto fail;
/* set common interleaves to simplify usage
* (do it here to in case it's overwritten later, possibly with 0 on purpose) */
if (txth->interleave == 0) {
switch(txth->codec) {
case PSX: txth->interleave = 0x10; break;
case PSX_bf: txth->interleave = 0x10; break;
case NGC_DSP: txth->interleave = 0x08; break;
case PCM16LE: txth->interleave = 0x02; break;
case PCM16BE: txth->interleave = 0x02; break;
case PCM8: txth->interleave = 0x01; break;
case PCM8_U: txth->interleave = 0x01; break;
default: break;
}
}
txth->codec = parse_codec(txth, val);
if (txth->codec == UNKNOWN)
goto fail;
}
else if (is_string(key,"codec_mode")) {
if (!parse_num(txth->sf_head,txth,val, &txth->codec_mode)) goto fail;
@ -1372,7 +1391,7 @@ static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, cha
return 1;
fail:
VGM_LOG("TXTH: error parsing key=%s, val=%s\n", key, val);
vgm_logi("TXTH: error parsing key=%s, val=%s\n", key, val);
return 0;
}
@ -1589,6 +1608,26 @@ static int read_name_table_keyval(txth_header* txth, const char* line, char* key
return 0;
}
static int parse_name_val(txth_header* txth, char* subval) {
int ok;
ok = parse_num(txth->sf_head, txth, subval, &txth->name_values[txth->name_values_count]);
if (!ok) {
/* in rare cases may set codec */
txth_codec_t codec = parse_codec(txth, subval);
if (codec == UNKNOWN)
goto fail;
txth->name_values[txth->name_values_count] = codec;
}
txth->name_values_count++;
if (txth->name_values_count >= 16) /* surely nobody needs that many */
goto fail;
return 1;
fail:
return 0;
}
static int parse_name_table(txth_header* txth, char* name_list) {
STREAMFILE* sf_names = NULL;
off_t txt_offset, file_size;
@ -1666,9 +1705,7 @@ static int parse_name_table(txth_header* txth, char* name_list) {
if (current[0] == ',')
current++;
if (!parse_num(txth->sf_head,txth,subval, &txth->name_values[txth->name_values_count])) goto fail;
txth->name_values_count++;
if (txth->name_values_count >= 16) /* surely nobody needs that many */
if (!parse_name_val(txth, subval))
goto fail;
}
@ -1806,7 +1843,7 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_
offset += txth->base_offset;
if (/*offset < 0 ||*/ offset > get_streamfile_size(sf)) {
VGM_LOG("TXTH: wrong offset %x + %x\n", offset - txth->base_offset, txth->base_offset);
vgm_logi("TXTH: wrong offset over file size (%x + %x)\n", offset - txth->base_offset, txth->base_offset);
goto fail;
}
@ -1920,7 +1957,7 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_
//;VGM_LOG("TXTH: final result %u (0x%x)\n", result, result);
return 1;
fail:
VGM_LOG("TXTH: error parsing num '%s'\n", val);
//VGM_LOG("TXTH: error parsing num '%s'\n", val);
return 0;
}

View File

@ -634,7 +634,7 @@ static VGMSTREAM* init_vgmstream_ubi_bao_header(ubi_bao_header* bao, STREAMFILE*
VGMSTREAM* vgmstream = NULL;
if (bao->total_subsongs <= 0) {
VGM_LOG("UBI BAO: no subsongs\n");
vgm_logi("UBI BAO: bank has no subsongs (ignore)\n");
goto fail; /* not uncommon */
}
@ -1473,7 +1473,10 @@ static STREAMFILE* setup_bao_streamfile(ubi_bao_header* bao, STREAMFILE* sf) {
if (bao->stream_size - bao->prefetch_size != 0) {
new_sf = open_streamfile_by_filename(sf, bao->resource_name);
if (!new_sf) { VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name); goto fail; }
if (!new_sf) {
vgm_logi("UBI BAO: external file '%s' not found (put together)\n", bao->resource_name);
goto fail;
}
stream_segments[1] = new_sf;
new_sf = open_clamp_streamfile(stream_segments[1], bao->stream_offset, (bao->stream_size - bao->prefetch_size));
@ -1495,7 +1498,10 @@ static STREAMFILE* setup_bao_streamfile(ubi_bao_header* bao, STREAMFILE* sf) {
}
else if (bao->is_external) {
new_sf = open_streamfile_by_filename(sf, bao->resource_name);
if (!new_sf) { VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name); goto fail; }
if (!new_sf) {
vgm_logi("UBI BAO: external file '%s' not found (put together)\n", bao->resource_name);
goto fail;
}
temp_sf = new_sf;
new_sf = open_clamp_streamfile(temp_sf, bao->stream_offset, bao->stream_size);
@ -1884,11 +1890,10 @@ static int config_bao_version(ubi_bao_header* bao, STREAMFILE* sf) {
* - 0x94: stream id? 0x9C: extra size */
case 0x002A0300: /* Watch Dogs (Wii U) */
/* similar to SC:B */
default: /* others possibly using BAO: Just Dance, Watch_Dogs, Far Cry Primal, Far Cry 4 */
VGM_LOG("UBI BAO: unknown BAO version %08x\n", bao->version);
default: /* others possibly using BAO: Watch_Dogs, Far Cry Primal, Far Cry 4 */
vgm_logi("UBI BAO: unknown BAO version %08x\n", bao->version);
return 0;
}
VGM_LOG("UBI BAO: unknown BAO version %08x\n", bao->version);
return 0;
}

View File

@ -644,7 +644,7 @@ static VGMSTREAM *init_vgmstream_ubi_dat_main(ubi_sb_header *sb, STREAMFILE *sf_
sf_data = open_streamfile_by_filename(sf, sb->resource_name);
if (!sf_data) {
/* play silence if external file is not found since Rayman 2 seems to rely on this behavior */
VGM_LOG("UBI DAT: external stream '%s' not found\n", sb->resource_name);
vgm_logi("UBI DAT: external file '%s' not found (put together)\n", sb->resource_name);
strncat(sb->readable_name, " (missing)", sizeof(sb->readable_name));
sb->duration = (float)pcm_bytes_to_samples(sb->stream_size, sb->channels, 16) / (float)sb->sample_rate;
return init_vgmstream_ubi_sb_silence(sb);
@ -1301,10 +1301,11 @@ static VGMSTREAM* init_vgmstream_ubi_sb_audio(ubi_sb_header* sb, STREAMFILE* sf_
if (sb->is_external) {
sf_data = open_streamfile_by_filename(sf, sb->resource_name);
if (sf_data == NULL) {
VGM_LOG("UBI SB: external stream '%s' not found\n", sb->resource_name);
vgm_logi("UBI SB: external file '%s' not found (put together)\n", sb->resource_name);
goto fail;
}
} else {
}
else {
sf_data = sf;
}
@ -1341,7 +1342,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_layer(ubi_sb_header* sb, STREAMFILE* sf_
if (sb->is_external) {
sf_data = open_streamfile_by_filename(sf,sb->resource_name);
if (sf_data == NULL) {
VGM_LOG("UBI SB: external stream '%s' not found\n", sb->resource_name);
vgm_logi("UBI SB: external file '%s' not found (put together)\n", sb->resource_name);
goto fail;
}
}
@ -1563,7 +1564,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_header(ubi_sb_header* sb, STREAMFILE* sf
VGMSTREAM* vgmstream = NULL;
if (sb->total_subsongs == 0) {
VGM_LOG("UBI SB: no subsongs\n");
vgm_logi("UBI SB: bank has no subsongs (ignore)\n");
goto fail;
}
@ -1862,8 +1863,8 @@ static int parse_type_audio(ubi_sb_header* sb, off_t offset, STREAMFILE* sf) {
/* PC can have subblock 2 based on two fields near the end but it wasn't seen so far */
/* stream_type field is not used if the flag is not set (it even contains garbage in some versions)
* except for PS3 which has two hardware codecs (PSX and AT3) */
if (!software_flag && sb->platform != UBI_PS3)
* except for PS3 and new PSP which have two hardware codecs (PSX and AT3) */
if (!software_flag && sb->platform != UBI_PS3 && !(sb->platform == UBI_PSP && !sb->is_psp_old))
sb->stream_type = 0x00;
} else {
sb->subblock_id = (sb->stream_type == 0x01) ? 0 : 1;
@ -4042,6 +4043,6 @@ static int config_sb_version(ubi_sb_header* sb, STREAMFILE* sf) {
return 1;
}
VGM_LOG("UBI SB: unknown SB/SM version+platform %08x\n", sb->version);
vgm_logi("UBI SB: unknown SB/SM version+platform %08x (report)\n", sb->version);
return 0;
}

View File

@ -8,7 +8,7 @@ VGMSTREAM* init_vgmstream_wii_bns(STREAMFILE* sf) {
off_t bns_offset;
uint32_t info_offset = 0, data_offset = 0;
uint32_t channel_info_offset_list_offset;
int channels, loop_flag, sample_rate;
int channels, loop_flag, sample_rate;
uint32_t sample_count, loop_start;
/* checks */
@ -106,7 +106,7 @@ VGMSTREAM* init_vgmstream_wii_bns(STREAMFILE* sf) {
channel_info_offset_list_offset = info_offset + read_u32be(info_offset+0x10,sf);
}
/* build the VGMSTREAM */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;

View File

@ -510,7 +510,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
if (ww.bits_per_sample != 16) goto fail;
/* original data_size doesn't look related to samples or anything */
ww.data_size = ww.file_size - ww.data_offset;
ww.data_size = ww.file_size - ww.data_offset;
vgmstream->codec_data = init_ffmpeg_offset(sf, ww.data_offset, ww.data_size);
if (!vgmstream->codec_data) goto fail;
@ -592,8 +592,8 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
vgmstream->layout_type = layout_none;
break;
}
#endif
case HEVAG: /* PSV */
/* changed values, another bizarre Wwise quirk */
//ww.block_align /* unknown (1ch=2, 2ch=4) */
@ -644,6 +644,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
break;
}
#endif
case PTADPCM: /* newer ADPCM [Bayonetta 2 (Switch), Genshin Impact (PC)] */
if (ww.bits_per_sample != 4) goto fail;
if (ww.block_align != 0x24 * ww.channels && ww.block_align != 0x104 * ww.channels) goto fail;
@ -681,7 +682,7 @@ static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_o
* - .bnk would be memory banks = full
* - otherwise small-ish sizes, stereo, with initial predictors for the
* second channel matching half size = full
* some files aren't detectable like this though, when predictors are 0
* some files aren't detectable like this though, when predictors are 0
* (but since memory wem aren't that used this shouldn't be too common) */
if (ww->truncated)
@ -885,6 +886,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
case 0x3041: ww->codec = OPUSWW; break; /* "OPUS_WEM", added on Wwise 2019.2.3, replaces OPUS */
case 0x8311: ww->codec = PTADPCM; break; /* added on Wwise 2019.1, replaces IMA */
default:
vgm_logi("WWISE: unknown codec 0x%04x (report)\n", ww->format);
goto fail;
}
@ -893,11 +895,14 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
if (ww->extra_size == 0x0c + ww->channels * 0x2e) {
/* newer Wwise DSP with coefs [Epic Mickey 2 (Wii), Batman Arkham Origins Blackgate (3DS)] */
ww->codec = DSP;
} else if (ww->extra_size == 0x0a && ww->wiih_offset) { /* WiiH */
}
else if (ww->extra_size == 0x0a && ww->wiih_offset) { /* WiiH */
/* few older Wwise DSP with num_samples in extra_size [Tony Hawk: Shred (Wii)] */
ww->codec = DSP;
} else if (ww->block_align == 0x104 * ww->channels) {
ww->codec = PTADPCM; /* Bayonetta 2 (Switch) */
}
else if (ww->block_align == 0x104 * ww->channels) {
/* Bayonetta 2 (Switch) */
ww->codec = PTADPCM;
}
}
@ -911,7 +916,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
/* catch wrong rips as truncated tracks' file_size should be much smaller than data_size,
* but it's possible to pre-fetch small files too [Punch Out!! (Wii)] */
if (ww->data_offset + ww->data_size - ww->file_size < 0x5000 && ww->file_size > 0x10000) {
VGM_LOG("WWISE: wrong expected data_size\n");
vgm_logi("WWISE: wrong expected size (re-rip?)\n");
goto fail;
}
@ -919,7 +924,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
ww->codec == OPUSNX || ww->codec == OPUS || ww->codec == OPUSWW || ww->codec == PTADPCM) {
ww->truncated = 1; /* only seen those, probably all exist (XWMA, AAC, HEVAG, ATRAC9?) */
} else {
VGM_LOG("WWISE: wrong size, maybe truncated\n");
vgm_logi("WWISE: wrong expected size, maybe truncated (report)\n");
goto fail;
}
}
@ -955,7 +960,7 @@ fail:
0x14 (4): LoopInfo.dwLoopEndPacketOffset?
0x18 (4): dwSeekTableSize (0 = no seek table)
0x1c (4): dwVorbisDataOffset (offset within data)
0x20 (2): uMaxPacketSize (not including header)
0x20 (2): uMaxPacketSize (not including header)
0x22 (2): uLastGranuleExtra (0..~0x100)
0x24 (4): dwDecodeAllocSize (0~0x5000)
0x28 (4): dwDecodeX64AllocSize (mid, 0~0x5000)
@ -971,7 +976,7 @@ fail:
0x0c (2): ? (small, 0..~0x400) [(4) when size is 0x2C]
0x10 (4): dwSeekTableSize (0 = no seek table)
0x14 (4): dwVorbisDataOffset (offset within data)
0x18 (2): uMaxPacketSize (not including header)
0x18 (2): uMaxPacketSize (not including header)
0x1a (2): uLastGranuleExtra (0..~0x100) [(4) when size is 0x2C]
0x1c (4): dwDecodeAllocSize (0~0x5000)
0x20 (4): dwDecodeX64AllocSize (0~0x5000)
@ -988,7 +993,7 @@ fail:
0x26 (2): LoopInfo.uLoopEndExtra (extra samples after seek?)
0x28 (4): dwSeekTableSize (0 = no seek table)
0x2c (4): dwVorbisDataOffset (offset within data)
0x30 (2): uMaxPacketSize (not including header)
0x30 (2): uMaxPacketSize (not including header)
0x32 (2): uLastGranuleExtra (small, 0..~0x100)
0x34 (4): dwDecodeAllocSize (mid, 0~0x5000)
0x38 (4): dwDecodeX64AllocSize (mid, 0~0x5000)

View File

@ -190,7 +190,7 @@ static int lz4mg_decompress(lz4mg_stream_t* strm) {
default:
goto fail;
}
}
}
buffer_end:
strm->next_out += dst_pos;
@ -208,16 +208,16 @@ fail:
#if 0
/* non-streamed form for reference, assumes buffers are big enough */
static void decompress_lz4mg(uint8_t* dst, size_t dst_size, const uint8_t* src, size_t src_size) {
size_t src_pos = 0;
size_t dst_pos = 0;
size_t src_pos = 0;
size_t dst_pos = 0;
uint8_t token;
int literal_len, match_len, next_len;
int match_pos, match_offset;
int i;
while (src_pos < src_size && dst_pos < dst_size) {
while (src_pos < src_size && dst_pos < dst_size) {
token = src[src_pos++];
token = src[src_pos++];
if (src_pos > src_size)
break;
@ -259,7 +259,7 @@ static void decompress_lz4mg(uint8_t* dst, size_t dst_size, const uint8_t* src,
for(i = 0; i < match_len; i++) {
dst[dst_pos++] = dst[match_pos++]; /* note RLE with short offsets */
}
}
}
}
#endif

View File

@ -2,7 +2,7 @@
#include "../coding/coding.h"
/* XSH+XSD/XSS - from Treyarch games [Spider-Man 2002 (Xbox), Kelly Slater's Pro Surfer (Xbox)] */
/* XSH+XSD/XSS - from Treyarch games */
VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sf_body = NULL;
@ -30,34 +30,47 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
switch(version) {
case 0x009D:
case 0x009D: /* Spider-Man 2002 (Xbox) */
offset = 0x0c + (target_subsong-1) * 0x60;
name_offset = offset + 0x00;
name_size = 0x20;
stream_type = read_u32le(offset + 0x20,sf);
stream_offset = read_u32le(offset + 0x24,sf);
stream_size = read_u32le(offset + 0x28,sf);
flags = read_u32le(offset + 0x34,sf);
/* 0x38: flags? */
offset += 0x20;
stream_type = read_u32le(offset + 0x00,sf);
stream_offset = read_u32le(offset + 0x04,sf);
stream_size = read_u32le(offset + 0x08,sf);
flags = read_u32le(offset + 0x14,sf);
/* 0x18: flags? */
num_samples = 0;
offset = offset + 0x3c;
offset += 0x1c;
break;
case 0x0100:
offset = 0x0c + (target_subsong-1) * 0x64;
case 0x0100: /* Kelly Slater's Pro Surfer (Xbox) */
case 0x0101: /* Minority Report: Everybody Runs (Xbox), NHL 2K3 (Xbox) */
/* NHL has stream IDs instead of names */
if (read_u32le(0x0c,sf) > 0x1000) {
offset = 0x0c + (target_subsong-1) * 0x64;
name_offset = offset + 0x00;
name_size = 0x20;
offset += 0x20;
}
else {
offset = 0x0c + (target_subsong-1) * 0x48;
name_offset = offset + 0x00;
name_size = 0x00;
offset += 0x04;
}
name_offset = offset + 0x00;
name_size = 0x20;
stream_type = read_u32le(offset + 0x20,sf);
stream_offset = read_u32le(offset + 0x24,sf);
stream_size = read_u32le(offset + 0x28,sf);
flags = read_u32le(offset + 0x34,sf);
num_samples = read_u32le(offset + 0x38,sf);
/* 0x3c: flags? */
stream_type = read_u32le(offset + 0x00,sf);
stream_offset = read_u32le(offset + 0x04,sf);
stream_size = read_u32le(offset + 0x08,sf);
flags = read_u32le(offset + 0x14,sf);
num_samples = read_u32le(offset + 0x18,sf);
/* 0x1c: flags? */
offset = offset + 0x40;
offset += 0x20;
break;
default:
@ -90,13 +103,13 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
char filename[255];
switch (version) {
case 0x009D:
/* stream is a named .xss, with stream_offset/size = 0 (Spider-Man) */
/* stream is a named .xss, with stream_offset/size = 0 */
read_string(filename, name_size, name_offset,sf);
strcat(filename, ".xss");
sf_body = open_streamfile_by_filename(sf,filename);
if (!sf_body) {
VGM_LOG("XSH: can't find %s\n", filename);
vgm_logi("XSH: external file '%s' not found (put together)\n", filename);
goto fail;
}
@ -112,11 +125,12 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
//break;
case 0x0100:
/* bigfile with all streams (Kelly Slater) */
case 0x0101:
/* bigfile with all streams */
snprintf(filename, sizeof(filename), "%s", "STREAMS.XSS");
sf_body = open_streamfile_by_filename(sf,filename);
if (!sf_body) {
VGM_LOG("XSH: can't find %s\n", filename);
vgm_logi("XSH: external file '%s' not found (put together)\n", filename);
goto fail;
}
break;

View File

@ -26,8 +26,8 @@ typedef struct {
off_t stream_offset;
} xvag_header;
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);
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* sf) {
@ -42,7 +42,7 @@ VGMSTREAM* init_vgmstream_xvag(STREAMFILE* sf) {
/* checks */
/* .xvag: standard
* (extensionless): The Last Of Us (PS3) speech files */
* (extensionless): The Last of Us (PS3) speech files */
if (!check_extensions(sf,"xvag,"))
goto fail;
if (!is_id32be(0x00,sf, "XVAG"))
@ -254,7 +254,7 @@ fail:
}
#ifdef VGM_USE_ATRAC9
static int init_xvag_atrac9(STREAMFILE* sf, 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};
@ -265,7 +265,7 @@ static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header *
/* 0x08: data size (layer only) */
/* 0x10: decoder delay? */
cfg.encoder_delay = read_32bit(chunk_offset+0x14,sf);
/* sometimes ATRAC9 data starts with a fake RIFF, that has total channels rather than layer channels */
/* sometimes ATRAC9 data starts with a fake RIFF, that has total channels rather than layer channels */
vgmstream->codec_data = init_atrac9(&cfg);
if (!vgmstream->codec_data) goto fail;
@ -278,7 +278,7 @@ fail:
}
#endif
static layered_layout_data* build_layered_xvag(STREAMFILE* sf, 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_sf = NULL;
int32_t (*read_32bit)(off_t,STREAMFILE*) = xvag->big_endian ? read_32bitBE : read_32bitLE;
@ -309,7 +309,7 @@ static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header * xva
if (!init_xvag_atrac9(sf, data->layers[i], xvag, chunk_offset))
goto fail;
/* interleaves N layers for custom multichannel, may rarely use subsongs [Days Gone (PS4) multilayer test]
/* interleaves N layers for custom multichannel, may rarely use subsongs [Days Gone (PS4) multilayer test]
* ex. 2 layers, 1 subsong : [L1][L2][L1][L2]
* ex. 2 layers, 2 subsongs: [L1S1][L2S1][L1S2][L2S2] (assumed, could be [L1S1][L1S2][L2S1][L2S2]) */
chunk = i + xvag->subsongs * (xvag->target_subsong - 1); /* [L1S1][L2S1][L1S2][L2S2] */

View File

@ -1,6 +1,7 @@
#include "vgmstream.h"
#include "plugins.h"
#include "mixing.h"
#include "util/log.h"
/* ****************************************** */
@ -546,3 +547,16 @@ void vgmstream_mixing_stereo_only(VGMSTREAM *vgmstream, int start) {
/* remove channels after stereo */
mixing_push_killmix(vgmstream, start + 2);
}
/* ****************************************** */
/* LOG: log */
/* ****************************************** */
void vgmstream_set_log_callback(int level, void* callback) {
vgm_log_set_callback(NULL, level, 0, callback);
}
void vgmstream_set_log_stdout(int level) {
vgm_log_set_callback(NULL, level, 1, NULL);
}

View File

@ -77,6 +77,14 @@ typedef struct {
/* get a simple title for plugins */
void vgmstream_get_title(char* buf, int buf_len, const char* filename, VGMSTREAM* vgmstream, vgmstream_title_t* cfg);
enum {
VGM_LOG_LEVEL_INFO = 1,
VGM_LOG_LEVEL_DEBUG = 2,
VGM_LOG_LEVEL_ALL = 100,
};
// CB: void (*callback)(int level, const char* str)
void vgmstream_set_log_callback(int level, void* callback);
void vgmstream_set_log_stdout(int level);
#if 0

View File

@ -518,7 +518,7 @@ static void seek_force_loop(VGMSTREAM* vgmstream, int loop_count) {
return;
/* pretend decoder reached loop end so state is set to loop start */
vgmstream->loop_count = loop_count - 1; /* seeking to first loop musy become ++ > 0 */
vgmstream->loop_count = loop_count - 1; /* seeking to first loop must become ++ > 0 */
vgmstream->current_sample = vgmstream->loop_end_sample;
vgmstream_do_loop(vgmstream);
}

File diff suppressed because it is too large Load Diff

View File

@ -19,40 +19,34 @@
/* MSVC fixes (though mingw uses MSVCRT but not MSC_VER, maybe use AND?) */
#if defined(__MSVCRT__) || defined(_MSC_VER)
#include <io.h>
#include <io.h>
#ifndef fseeko
#define fseeko fseek
#endif
#ifndef ftello
#define ftello ftell
#endif
#define dup _dup
#ifdef fileno
#undef fileno
#endif
#define fileno _fileno
#define fdopen _fdopen
// #ifndef off64_t
// #define off_t __int64
// #endif
#endif
#if defined(XBMC)
#define fseeko fseek
#ifndef off64_t
#define off_t __int64
#endif
#endif
#ifndef DIR_SEPARATOR
#if defined (_WIN32) || defined (WIN32)
#define DIR_SEPARATOR '\\'
#else
#define DIR_SEPARATOR '/'
#endif
#if defined (_WIN32) || defined (WIN32)
#define DIR_SEPARATOR '\\'
#else
#define DIR_SEPARATOR '/'
#endif
#endif
/* 64-bit offset is needed for banks that hit +2.5GB (like .fsb or .ktsl2stbin).
* Leave as typedef to toggle since it's theoretically slower when compiled as 32-bit.
* ATM it's only used in choice places until more performance tests are done.
* uint32_t could be an option but needs to test when/how neg offsets are used.
*
* On POSIX 32-bit off_t can become off64_t by passing -D_FILE_OFFSET_BITS=64,
* but not on MSVC as it doesn't have proper POSIX support, so a custom type is needed.
* fseeks/tells also need to be adjusted for 64-bit support.
*/
typedef int64_t offv_t; //off64_t
//typedef int64_t sizev_t; // size_t int64_t off64_t
/* Streamfiles normally use an internal buffer to increase performance, configurable
* but usually of this size. Lower increases the number of freads/system calls (slower).
* However some formats need to jump around causing more buffer trashing than usual,
@ -65,17 +59,26 @@
* to do file operations, as plugins may need to provide their own callbacks.
* Reads from arbitrary offsets, meaning internally may need fseek equivalents during reads. */
typedef struct _STREAMFILE {
size_t (*read)(struct _STREAMFILE*, uint8_t* dst, off_t offset, size_t length);
size_t (*get_size)(struct _STREAMFILE*);
off_t (*get_offset)(struct _STREAMFILE*); //todo: DO NOT USE, NOT RESET PROPERLY (remove?)
/* for dual-file support */
void (*get_name)(struct _STREAMFILE*, char* name, size_t length);
struct _STREAMFILE* (*open)(struct _STREAMFILE*, const char* const filename, size_t buffersize);
/* read 'length' data at 'offset' to 'dst' */
size_t (*read)(struct _STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length);
/* get max offset */
size_t (*get_size)(struct _STREAMFILE* sf);
//todo: DO NOT USE, NOT RESET PROPERLY (remove?)
offv_t (*get_offset)(struct _STREAMFILE*);
/* copy current filename to name buf */
void (*get_name)(struct _STREAMFILE* sf, char* name, size_t name_size);
/* open another streamfile from filename */
struct _STREAMFILE* (*open)(struct _STREAMFILE* sf, const char* const filename, size_t buffer_size);
/* free current STREAMFILE */
void (*close)(struct _STREAMFILE*);
/* Substream selection for files with subsongs. Manually used in metas if supported.
* Not ideal here, but it's the simplest way to pass to all init_vgmstream_x functions. */
/* Substream selection for formats with subsongs.
* Not ideal here, but it was the simplest way to pass to all init_vgmstream_x functions. */
int stream_index; /* 0=default/auto (first), 1=first, N=Nth */
} STREAMFILE;
@ -105,8 +108,8 @@ STREAMFILE* open_wrap_streamfile_f(STREAMFILE* sf);
/* Opens a STREAMFILE that clamps reads to a section of a larger streamfile.
* Can be used with subfiles inside a bigger file (to fool metas, or to simplify custom IO). */
STREAMFILE* open_clamp_streamfile(STREAMFILE* sf, off_t start, size_t size);
STREAMFILE* open_clamp_streamfile_f(STREAMFILE* sf, off_t start, size_t size);
STREAMFILE* open_clamp_streamfile(STREAMFILE* sf, offv_t start, size_t size);
STREAMFILE* open_clamp_streamfile_f(STREAMFILE* sf, offv_t start, size_t size);
/* Opens a STREAMFILE that uses custom IO for streamfile reads.
* Can be used to modify data on the fly (ex. decryption), or even transform it from a format to another.
@ -156,8 +159,8 @@ static inline void close_streamfile(STREAMFILE* sf) {
}
/* read from a file, returns number of bytes read */
static inline size_t read_streamfile(uint8_t *dst, off_t offset, size_t length, STREAMFILE* sf) {
return sf->read(sf, dst, offset,length);
static inline size_t read_streamfile(uint8_t* dst, offv_t offset, size_t length, STREAMFILE* sf) {
return sf->read(sf, dst, offset, length);
}
/* return file size */

View File

@ -136,49 +136,4 @@ void swap_samples_le(sample_t *buf, int count);
void concatn(int length, char * dst, const char * src);
/* Simple stdout logging for debugging and regression testing purposes.
* Needs C99 variadic macros, uses do..while to force ";" as statement */
#ifdef VGM_DEBUG_OUTPUT
/* equivalent to printf when condition is true */
#define VGM_ASSERT(condition, ...) \
do { if (condition) {printf(__VA_ARGS__);} } while (0)
#define VGM_ASSERT_ONCE(condition, ...) \
do { static int written; if (!written) { if (condition) {printf(__VA_ARGS__); written = 1;} } } while (0)
/* equivalent to printf */
#define VGM_LOG(...) \
do { printf(__VA_ARGS__); } while (0)
#define VGM_LOG_ONCE(...) \
do { static int written; if (!written) { printf(__VA_ARGS__); written = 1; } } while (0)
/* prints file/line/func */
#define VGM_LOGF() \
do { printf("%s:%i '%s'\n", __FILE__, __LINE__, __func__); } while (0)
/* prints to a file */
#define VGM_LOGT(txt, ...) \
do { FILE *fl = fopen(txt,"a+"); if(fl){fprintf(fl,__VA_ARGS__); fflush(fl);} fclose(fl); } while(0)
/* prints a buffer/array */
#define VGM_LOGB(buf, buf_size, bytes_per_line) \
do { \
int i; \
for (i=0; i < buf_size; i++) { \
printf("%02x",buf[i]); \
if (bytes_per_line && (i+1) % bytes_per_line == 0) printf("\n"); \
} \
printf("\n"); \
} while (0)
#else/*VGM_DEBUG_OUTPUT*/
#define VGM_ASSERT(condition, ...) /* nothing */
#define VGM_ASSERT_ONCE(condition, ...) /* nothing */
#define VGM_LOG(...) /* nothing */
#define VGM_LOG_ONCE(...) /* nothing */
#define VGM_LOGF() /* nothing */
#define VGM_LOGT() /* nothing */
#define VGM_LOGB(buf, buf_size, bytes_per_line) /* nothing */
#endif/*VGM_DEBUG_OUTPUT*/
#endif

View File

@ -0,0 +1,35 @@
#include "chunks.h"
//#include "log.h"
int next_chunk(chunk_t* chunk, STREAMFILE* sf) {
uint32_t (*read_u32type)(off_t,STREAMFILE*) = !chunk->le_type ? read_u32be : read_u32le;
uint32_t (*read_u32size)(off_t,STREAMFILE*) = chunk->be_size ? read_u32be : read_u32le;
if (chunk->max == 0)
chunk->max = get_streamfile_size(sf);
if (chunk->current >= chunk->max)
return 0;
/* can be used to signal "stop" */
if (chunk->current < 0)
return 0;
chunk->type = read_u32type(chunk->current + 0x00,sf);
chunk->size = read_u32size(chunk->current + 0x04,sf);
chunk->offset = chunk->current + 0x04 + 0x04;
chunk->current += chunk->full_size ? chunk->size : 0x08 + chunk->size;
//;VGM_LOG("CHUNK: %x, %x, %x\n", dc.offset, chunk->type, chunk->size);
/* read past data */
if (chunk->type == 0xFFFFFFFF || chunk->size == 0xFFFFFFFF)
return 0;
/* empty chunk with 0 size, seen in some formats (XVAG uses it as end marker, Wwise doesn't) */
if (chunk->type == 0 || chunk->size == 0)
return 0;
/* more chunks remain */
return 1;
}

View File

@ -0,0 +1,27 @@
#ifndef _UTIL_CHUNKS_H
#define _UTIL_CHUNKS_H
#include "../streamfile.h"
typedef struct {
uint32_t type; /* chunk id/fourcc */
uint32_t size; /* chunk size */
uint32_t offset; /* chunk offset (after type/size) */
off_t current; /* start position, or next chunk after size (set to -1 to break) */
off_t max; /* max offset, or filesize if not set */
int le_type; /* read type as LE instead of more common BE */
int be_size; /* read type as BE instead of more common LE */
int full_size; /* chunk size includes type+size */
} chunk_t;
int next_chunk(chunk_t* chunk, STREAMFILE* sf);
#if 0
enum {
CHUNK_RIFF = 0x52494646, /* "RIFF" */
CHUNK_LIST = 0x4C495354, /* "LIST" */
};
#endif
#endif

View File

@ -0,0 +1,90 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* log context; should probably make a unique instance and pass to metas/decoders/etc, but for the time being use global */
//extern ...* log;
typedef struct {
int level;
void (*callback)(int level, const char* str);
} logger_t;
logger_t log_impl = {0};
//void* log = &log_impl;
enum {
LOG_LEVEL_INFO = 1,
LOG_LEVEL_DEBUG = 2,
LOG_LEVEL_ALL = 100,
};
static void vgm_log_callback_printf(int level, const char* str) {
printf("%s", str);
}
void vgm_log_set_callback(void* ctx_p, int level, int type, void* callback) {
logger_t* ctx = ctx_p;
if (!ctx) ctx = &log_impl;
ctx->level = level;
switch(type) {
case 0:
ctx->callback = callback;
break;
case 1:
ctx->callback = vgm_log_callback_printf;
break;
default:
break;
}
}
static void log_internal(void* ctx_p, int level, const char* fmt, va_list args) {
char line[255];
int out;
logger_t* ctx = ctx_p;
if (!ctx) ctx = &log_impl;
if (!ctx->callback)
return;
if (level > ctx->level)
return;
out = vsnprintf(line, sizeof(line), fmt, args);
if (out < 0 || out > sizeof(line))
strcpy(line, "(ignored log)"); //to-do something better, meh
ctx->callback(level, line);
}
void vgm_logd(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
log_internal(NULL, LOG_LEVEL_DEBUG, fmt, args);
va_end(args);
}
void vgm_logi(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
log_internal(NULL, LOG_LEVEL_INFO, fmt, args);
va_end(args);
}
void vgm_asserti(int condition, const char* fmt, ...) {
if (!condition)
return;
{
va_list args;
va_start(args, fmt);
log_internal(NULL, LOG_LEVEL_INFO, fmt, args);
va_end(args);
}
}

View File

@ -0,0 +1,78 @@
#ifndef _UTIL_LOG_H
#define _UTIL_LOG_H
/* Dumb logger utils (tuned for simplicity). Notes:
* - must set callback/defaults to print anything
* - mainly used to print info for users, like format detected but wrong size
* (don't clutter by logging code that happens most of the time, since log may be shared with other plugins)
* - callbacks receive formed string for simplicity (to be adjusted)
* - DO NOT put logs in tight loops (like decoders), slow fn calls and clutter
* (metas are usually fine but also consider cluttering)
* - as compiler must support variable args, needs to pass VGM_LOG_OUTPUT flag to enable
* - debug logs are removed unless VGM_DEBUG_OUTPUT is passed to compiler args
* (passing either of them works)
* - callback should be thread-safe (no internal checks and only one log ATM)
* - still WIP, some stuff not working ATM or may change
*/
// void (*callback)(int level, const char* str);
void vgm_log_set_callback(void* ctx_p, int level, int type, void* callback);
#if defined(VGM_LOG_OUTPUT) || defined(VGM_DEBUG_OUTPUT)
void vgm_logi(/*void* ctx,*/ const char* fmt, ...);
void vgm_asserti(/*void* ctx,*/ int condition, const char* fmt, ...);
//void vgm_logi_once(/*void* ctx, int* once_flag, */ const char* fmt, ...);
#else
#define vgm_logi(...) /* nothing */
#define vgm_asserti(...) /* nothing */
#endif
#ifdef VGM_DEBUG_OUTPUT
void vgm_logd(/*void* ctx,*/ const char* fmt, ...);
#define VGM_LOG(...) do { vgm_logd(__VA_ARGS__); } while (0)
#define VGM_ASSERT(condition, ...) do { if (condition) {vgm_logd(__VA_ARGS__);} } while (0)
#else
#define vgm_logd(...) /* nothing */
#define VGM_LOG(...) /* nothing */
#define VGM_ASSERT(condition, ...) /* nothing */
#endif
/* original stdout logging for debugging and regression testing purposes, may be removed later.
* Needs C99 variadic macros, uses do..while to force ";" as statement */
#ifdef VGM_DEBUG_OUTPUT
#define VGM_LOG_ONCE(...) \
do { static int written; if (!written) { printf(__VA_ARGS__); written = 1; } } while (0)
#define VGM_ASSERT_ONCE(condition, ...) \
do { static int written; if (!written) { if (condition) {printf(__VA_ARGS__); written = 1;} } } while (0)
/* prints to a file */
#define VGM_LOGT(txt, ...) \
do { FILE *fl = fopen(txt,"a+"); if(fl){fprintf(fl,__VA_ARGS__); fflush(fl);} fclose(fl); } while(0)
/* prints a buffer/array */
#define VGM_LOGB(buf, buf_size, bytes_per_line) \
do { \
int i; \
for (i=0; i < buf_size; i++) { \
printf("%02x",buf[i]); \
if (bytes_per_line && (i+1) % bytes_per_line == 0) printf("\n"); \
} \
printf("\n"); \
} while (0)
#else /* VGM_DEBUG_OUTPUT */
#define VGM_LOG_ONCE(...) /* nothing */
#define VGM_ASSERT_ONCE(condition, ...) /* nothing */
#define VGM_LOGT() /* nothing */
#define VGM_LOGB(buf, buf_size, bytes_per_line) /* nothing */
#endif /*VGM_DEBUG_OUTPUT*/
#endif

View File

@ -24,7 +24,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_bfwav,
init_vgmstream_bfstm,
init_vgmstream_mca,
init_vgmstream_btsnd,
init_vgmstream_nds_strm,
init_vgmstream_agsc,
init_vgmstream_ngc_adpdtk,
@ -533,6 +532,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
/* 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 */
init_vgmstream_encrypted, /* encrypted stuff */
init_vgmstream_btsnd, /* semi-headerless */
init_vgmstream_raw_int, /* .int raw PCM */
init_vgmstream_ps_headerless, /* tries to detect a bunch of PS-ADPCM formats */
init_vgmstream_raw_snds, /* .snds raw SNDS IMA (*after* ps_headerless) */
@ -911,6 +911,8 @@ void describe_vgmstream(VGMSTREAM* vgmstream, char* desc, int length) {
char temp[TEMPSIZE];
double time_mm, time_ss;
desc[0] = '\0';
if (!vgmstream) {
snprintf(temp,TEMPSIZE, "NULL VGMSTREAM");
concatn(length,desc,temp);

View File

@ -18,6 +18,12 @@ enum {
#include "streamfile.h"
#ifdef BUILD_VGMSTREAM
#include "util/log.h"
#else
#include <libvgmstream/log.h>
#endif
/* Due mostly to licensing issues, Vorbis, MPEG, G.722.1, etc decoding is done by external libraries.
* Libs are disabled by default, defined on compile-time for builds that support it */
//#define VGM_USE_VORBIS

View File

@ -14,6 +14,11 @@
@implementation VGMContainer
+ (void)initialize
{
register_log_callback();
}
+ (NSArray *)fileTypes
{
return [VGMDecoder fileTypes];

View File

@ -205,6 +205,11 @@
@implementation VGMDecoder
+ (void)initialize
{
register_log_callback();
}
- (BOOL)open:(id<CogSource>)s
{
int track_num = [[[s url] fragment] intValue];

View File

@ -12,10 +12,12 @@
typedef struct _COGSTREAMFILE {
STREAMFILE sf;
void *file;
off_t offset;
offv_t offset;
char name[PATH_LIMIT];
} COGSTREAMFILE;
STREAMFILE *cogsf_create_from_url(NSURL * url);
VGMSTREAM *init_vgmstream_from_cogfile(const char *path, int subsong);
void register_log_callback();

View File

@ -10,7 +10,17 @@
#import "Plugin.h"
static void cogsf_seek(COGSTREAMFILE *this, off_t offset) {
#import "Logging.h"
static void log_callback(int level, const char *str) {
ALog(@"%@", str);
}
void register_log_callback() {
vgmstream_set_log_callback(VGM_LOG_LEVEL_ALL, &log_callback);
}
static void cogsf_seek(COGSTREAMFILE *this, offv_t offset) {
if (!this) return;
NSObject* _file = (__bridge NSObject *)(this->file);
id<CogSource> __unsafe_unretained file = (id) _file;
@ -20,18 +30,18 @@ static void cogsf_seek(COGSTREAMFILE *this, off_t offset) {
this->offset = [file tell];
}
static off_t cogsf_get_size(COGSTREAMFILE *this) {
static offv_t cogsf_get_size(COGSTREAMFILE *this) {
if (!this) return 0;
NSObject* _file = (__bridge NSObject *)(this->file);
id<CogSource> __unsafe_unretained file = (id) _file;
off_t offset = [file tell];
offv_t offset = [file tell];
[file seek:0 whence:SEEK_END];
off_t size = [file tell];
offv_t size = [file tell];
[file seek:offset whence:SEEK_SET];
return size;
}
static off_t cogsf_get_offset(COGSTREAMFILE *this) {
static offv_t cogsf_get_offset(COGSTREAMFILE *this) {
if (!this) return 0;
return this->offset;
}
@ -47,7 +57,7 @@ static void cogsf_get_name(COGSTREAMFILE *this, char *buffer, size_t length) {
buffer[length-1]='\0';
}
static size_t cogsf_read(COGSTREAMFILE *this, uint8_t *dest, off_t offset, size_t length) {
static size_t cogsf_read(COGSTREAMFILE *this, uint8_t *dest, offv_t offset, size_t length) {
if (!this) return 0;
NSObject* _file = (__bridge NSObject *)(this->file);
id<CogSource> __unsafe_unretained file = (id) _file;