Fix Wwise DSP memory interleave + renames [Punch Out!! (Wii)]

This commit is contained in:
bnnm 2020-04-22 00:34:49 +02:00
parent 4e55391be1
commit b24116b0c7
2 changed files with 118 additions and 86 deletions

View File

@ -105,7 +105,8 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
}
else {
//;VGM_LOG("BKHD: %lx, %x\n", subfile_offset, subfile_size);
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "wem");
/* could pass .wem but few files need memory .wem detection */
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, NULL);
if (!temp_sf) goto fail;
header_id = read_u32be(0x00, temp_sf);

View File

@ -38,9 +38,11 @@ typedef struct {
int32_t loop_end_sample;
} wwise_header;
static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_offset);
/* Wwise - Audiokinetic Wwise (Wave Works Interactive Sound Engine) middleware */
VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
VGMSTREAM * init_vgmstream_wwise(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL;
wwise_header ww = {0};
off_t start_offset, first_offset = 0xc;
@ -51,18 +53,19 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
/* .wem: newer "Wwise Encoded Media" used after the 2011.2 SDK (~july 2011)
* .wav: older ADPCM files [Punch Out!! (Wii)]
* .xma: older XMA files [Too Human (X360), Tron Evolution (X360)]
* .ogg: older Vorbis files [The King of Fighters XII (X360)] */
if (!check_extensions(streamFile,"wem,wav,lwav,ogg,logg,xma"))
* .ogg: older Vorbis files [The King of Fighters XII (X360)]
* .bnk: Wwise banks for memory .wem detection */
if (!check_extensions(sf,"wem,wav,lwav,ogg,logg,xma,bnk"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x52494646 && /* "RIFF" (LE) */
read_32bitBE(0x00,streamFile) != 0x52494658) /* "RIFX" (BE) */
if (read_32bitBE(0x00,sf) != 0x52494646 && /* "RIFF" (LE) */
read_32bitBE(0x00,sf) != 0x52494658) /* "RIFX" (BE) */
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x57415645 && /* "WAVE" */
read_32bitBE(0x08,streamFile) != 0x58574D41) /* "XWMA" */
if (read_32bitBE(0x08,sf) != 0x57415645 && /* "WAVE" */
read_32bitBE(0x08,sf) != 0x58574D41) /* "XWMA" */
goto fail;
ww.big_endian = read_32bitBE(0x00,streamFile) == 0x52494658; /* RIFX */
ww.big_endian = read_32bitBE(0x00,sf) == 0x52494658; /* RIFX */
if (ww.big_endian) { /* Wwise honors machine's endianness (PC=RIFF, X360=RIFX --unlike XMA) */
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
@ -71,7 +74,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
read_16bit = read_16bitLE;
}
ww.file_size = streamFile->get_size(streamFile);
ww.file_size = sf->get_size(sf);
#if 0
/* Wwise's RIFF size is often wonky, seemingly depending on codec:
@ -82,8 +85,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
* - some RIFX have LE size
* (later we'll validate "data" which fortunately is correct)
*/
if (read_32bit(0x04,streamFile)+0x04+0x04 != ww.file_size) {
VGM_LOG("WWISE: bad riff size (real=0x%x vs riff=0x%x)\n", read_32bit(0x04,streamFile)+0x04+0x04, ww.file_size);
if (read_32bit(0x04,sf)+0x04+0x04 != ww.file_size) {
VGM_LOG("WWISE: bad riff size (real=0x%x vs riff=0x%x)\n", read_32bit(0x04,sf)+0x04+0x04, ww.file_size);
goto fail;
}
#endif
@ -93,8 +96,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
off_t fact_offset;
size_t fact_size;
if (find_chunk(streamFile, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */
if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, streamFile) == 0x4C794E20) /* "LyN " */
if (find_chunk(sf, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */
if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, sf) == 0x4C794E20) /* "LyN " */
goto fail; /* parsed elsewhere */
}
/* Wwise doesn't use "fact", though */
@ -106,36 +109,36 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
size_t loop_size;
/* find basic chunks */
if (read_32bitBE(0x0c, streamFile) == 0x584D4132) { /* "XMA2" with no "fmt" [Too Human (X360)] */
if (read_32bitBE(0x0c, sf) == 0x584D4132) { /* "XMA2" with no "fmt" [Too Human (X360)] */
ww.format = 0x0165; /* signal for below */
}
else {
if (!find_chunk(streamFile, 0x666d7420,first_offset,0, &ww.fmt_offset,&ww.fmt_size, ww.big_endian, 0)) /* "fmt " */
if (!find_chunk(sf, 0x666d7420,first_offset,0, &ww.fmt_offset,&ww.fmt_size, ww.big_endian, 0)) /* "fmt " */
goto fail;
if (ww.fmt_size < 0x12)
goto fail;
ww.format = (uint16_t)read_16bit(ww.fmt_offset+0x00,streamFile);
ww.format = (uint16_t)read_16bit(ww.fmt_offset+0x00,sf);
}
if (ww.format == 0x0165) {
/* pseudo-XMA2WAVEFORMAT ("fmt"+"XMA2" or just "XMA2) */
if (!find_chunk(streamFile, 0x584D4132,first_offset,0, &ww.chunk_offset,NULL, ww.big_endian, 0)) /* "XMA2" */
if (!find_chunk(sf, 0x584D4132,first_offset,0, &ww.chunk_offset,NULL, ww.big_endian, 0)) /* "XMA2" */
goto fail;
xma2_parse_xma2_chunk(streamFile, ww.chunk_offset,&ww.channels,&ww.sample_rate, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample);
xma2_parse_xma2_chunk(sf, ww.chunk_offset,&ww.channels,&ww.sample_rate, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample);
}
else {
/* pseudo-WAVEFORMATEX */
ww.channels = read_16bit(ww.fmt_offset+0x02,streamFile);
ww.sample_rate = read_32bit(ww.fmt_offset+0x04,streamFile);
ww.average_bps = read_32bit(ww.fmt_offset+0x08,streamFile);/* bytes per sec */
ww.block_align = (uint16_t)read_16bit(ww.fmt_offset+0x0c,streamFile);
ww.bits_per_sample = (uint16_t)read_16bit(ww.fmt_offset+0x0e,streamFile);
ww.channels = read_16bit(ww.fmt_offset+0x02,sf);
ww.sample_rate = read_32bit(ww.fmt_offset+0x04,sf);
ww.average_bps = read_32bit(ww.fmt_offset+0x08,sf);/* bytes per sec */
ww.block_align = (uint16_t)read_16bit(ww.fmt_offset+0x0c,sf);
ww.bits_per_sample = (uint16_t)read_16bit(ww.fmt_offset+0x0e,sf);
if (ww.fmt_size > 0x10 && ww.format != 0x0165 && ww.format != 0x0166) /* ignore XMAWAVEFORMAT */
ww.extra_size = (uint16_t)read_16bit(ww.fmt_offset+0x10,streamFile);
ww.extra_size = (uint16_t)read_16bit(ww.fmt_offset+0x10,sf);
if (ww.extra_size >= 0x06) { /* always present (actual RIFFs only have it in WAVEFORMATEXTENSIBLE) */
/* mostly WAVEFORMATEXTENSIBLE's bitmask (see AkSpeakerConfig.h) */
ww.channel_layout = read_32bit(ww.fmt_offset+0x14,streamFile);
ww.channel_layout = read_32bit(ww.fmt_offset+0x14,sf);
/* later games (+2018?) have a pseudo-format instead to handle more cases:
* - 8b: uNumChannels
* - 4b: eConfigType (0=none, 1=standard, 2=ambisonic)
@ -149,18 +152,18 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
/* find loop info ("XMA2" chunks already read them) */
if (ww.format == 0x0166) { /* XMA2WAVEFORMATEX in fmt */
ww.chunk_offset = ww.fmt_offset;
xma2_parse_fmt_chunk_extra(streamFile, ww.chunk_offset, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample, ww.big_endian);
xma2_parse_fmt_chunk_extra(sf, ww.chunk_offset, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample, ww.big_endian);
}
else if (find_chunk(streamFile, 0x736D706C,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /* "smpl", common */
else if (find_chunk(sf, 0x736D706C,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /* "smpl", common */
if (loop_size >= 0x34
&& read_32bit(loop_offset+0x1c, streamFile)==1 /* loop count */
&& read_32bit(loop_offset+0x24+4, streamFile)==0) {
&& read_32bit(loop_offset+0x1c, sf)==1 /* loop count */
&& read_32bit(loop_offset+0x24+4, sf)==0) {
ww.loop_flag = 1;
ww.loop_start_sample = read_32bit(loop_offset+0x24+0x8, streamFile);
ww.loop_end_sample = read_32bit(loop_offset+0x24+0xc, streamFile) + 1; /* like standard RIFF */
ww.loop_start_sample = read_32bit(loop_offset+0x24+0x8, sf);
ww.loop_end_sample = read_32bit(loop_offset+0x24+0xc, sf) + 1; /* like standard RIFF */
}
}
//else if (find_chunk(streamFile, 0x4C495354,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"LIST", common */
//else if (find_chunk(sf, 0x4C495354,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"LIST", common */
// /* usually contains "cue"s with sample positions for events (ex. Platinum Games) but no real looping info */
//}
@ -169,7 +172,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
* "akd ": seem to store extra info for Wwise editor (wave peaks/loudness/HDR envelope?)
*/
if (!find_chunk(streamFile, 0x64617461,first_offset,0, &ww.data_offset,&ww.data_size, ww.big_endian, 0)) /* "data" */
if (!find_chunk(sf, 0x64617461,first_offset,0, &ww.data_offset,&ww.data_size, ww.big_endian, 0)) /* "data" */
goto fail;
}
@ -200,7 +203,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
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 && find_chunk(streamFile, 0x57696948, first_offset,0, NULL,NULL, ww.big_endian, 0)) { /* WiiH */
} else if (ww.extra_size == 0x0a && find_chunk(sf, 0x57696948, first_offset,0, NULL,NULL, ww.big_endian, 0)) { /* 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) {
@ -209,14 +212,15 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
}
/* Some Wwise files (ex. Oddworld PSV, Bayonetta 2 WiiU, often in BGM.bnk) are truncated mirrors of another file.
* They come in RAM banks, prefetch to play the beginning while the rest of the real stream loads.
* We'll add basic support to avoid complaints of this or that .wem not playing */
/* Some Wwise .bnk (RAM) files have truncated, prefetch mirrors of another file, that
* play while the rest of the real stream loads. We'll add basic support to avoid
* complaints of this or that .wem not playing */
if (ww.data_offset + ww.data_size > ww.file_size) {
//VGM_LOG("WWISE: truncated data size (prefetch): (real=0x%x > riff=0x%x)\n", ww.data_size, ww.file_size);
/* catch wrong rips as truncated tracks' file_size should be much smaller than data_size */
if (ww.data_offset + ww.data_size - ww.file_size < 0x5000) {
/* 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");
goto fail;
}
@ -293,7 +297,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail; /* always 0 for Worbis */
/* autodetect format (fields are mostly common, see the end of the file) */
if (find_chunk(streamFile, 0x766F7262,first_offset,0, &vorb_offset,&vorb_size, ww.big_endian, 0)) { /* "vorb" */
if (find_chunk(sf, 0x766F7262,first_offset,0, &vorb_offset,&vorb_size, ww.big_endian, 0)) { /* "vorb" */
/* older Wwise (~<2012) */
switch(vorb_size) {
@ -328,12 +332,12 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
goto fail;
}
vgmstream->num_samples = read_32bit(vorb_offset + 0x00, streamFile);
setup_offset = read_32bit(vorb_offset + data_offsets + 0x00, streamFile); /* within data (0 = no seek table) */
audio_offset = read_32bit(vorb_offset + data_offsets + 0x04, streamFile); /* within data */
vgmstream->num_samples = read_32bit(vorb_offset + 0x00, sf);
setup_offset = read_32bit(vorb_offset + data_offsets + 0x00, sf); /* within data (0 = no seek table) */
audio_offset = read_32bit(vorb_offset + data_offsets + 0x04, sf); /* within data */
if (block_offsets) {
cfg.blocksize_1_exp = read_8bit(vorb_offset + block_offsets + 0x00, streamFile); /* small */
cfg.blocksize_0_exp = read_8bit(vorb_offset + block_offsets + 0x01, streamFile); /* big */
cfg.blocksize_1_exp = read_8bit(vorb_offset + block_offsets + 0x00, sf); /* small */
cfg.blocksize_0_exp = read_8bit(vorb_offset + block_offsets + 0x01, sf); /* big */
}
ww.data_size -= audio_offset;
@ -350,8 +354,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
* - trimmed inline: ~2010, ex. Army of Two: 40 days (X360) some multiplayer files
* - external: ~2010, ex. Assassin's Creed Brotherhood (X360), Dead Nation (X360) */
if (vorb_size == 0x34) {
size_t setup_size = (uint16_t)read_16bit(start_offset + setup_offset, streamFile);
uint32_t id = (uint32_t)read_32bitBE(start_offset + setup_offset + 0x06, streamFile);
size_t setup_size = (uint16_t)read_16bit(start_offset + setup_offset, sf);
uint32_t id = (uint32_t)read_32bitBE(start_offset + setup_offset + 0x06, sf);
/* if the setup after header starts with "(data)BCV" it's an inline codebook) */
if ((id & 0x00FFFFFF) == 0x00424356) { /* 0"BCV" */
@ -363,13 +367,13 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
}
}
vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg);
vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg);
if (!vgmstream->codec_data) goto fail;
}
else {
/* newer Wwise (>2012) */
off_t extra_offset = ww.fmt_offset + 0x18; /* after flag + channels */
int is_wem = check_extensions(streamFile,"wem");
int is_wem = check_extensions(sf,"wem");
switch(ww.extra_size) {
case 0x30:
@ -389,11 +393,11 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
goto fail;
}
vgmstream->num_samples = read_32bit(extra_offset + 0x00, streamFile);
setup_offset = read_32bit(extra_offset + data_offsets + 0x00, streamFile); /* within data */
audio_offset = read_32bit(extra_offset + data_offsets + 0x04, streamFile); /* within data */
cfg.blocksize_1_exp = read_8bit(extra_offset + block_offsets + 0x00, streamFile); /* small */
cfg.blocksize_0_exp = read_8bit(extra_offset + block_offsets + 0x01, streamFile); /* big */
vgmstream->num_samples = read_32bit(extra_offset + 0x00, sf);
setup_offset = read_32bit(extra_offset + data_offsets + 0x00, sf); /* within data */
audio_offset = read_32bit(extra_offset + data_offsets + 0x04, sf); /* within data */
cfg.blocksize_1_exp = read_8bit(extra_offset + block_offsets + 0x00, sf); /* small */
cfg.blocksize_0_exp = read_8bit(extra_offset + block_offsets + 0x01, sf); /* big */
ww.data_size -= audio_offset;
/* detect normal packets */
@ -404,11 +408,11 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
}
/* try with the selected codebooks */
vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg);
vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg);
if (!vgmstream->codec_data) {
/* codebooks failed: try again with the other type */
cfg.setup_type = is_wem ? WWV_EXTERNAL_CODEBOOKS : WWV_AOTUV603_CODEBOOKS;
vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg);
vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg);
if (!vgmstream->codec_data) goto fail;
}
}
@ -441,12 +445,15 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
vgmstream->interleave_block_size = 0x08; /* ww.block_align = 0x8 in older Wwise, samples per block in newer Wwise */
/* find coef position */
if (find_chunk(streamFile, 0x57696948,first_offset,0, &wiih_offset,&wiih_size, ww.big_endian, 0)) { /*"WiiH", older Wwise */
if (find_chunk(sf, 0x57696948,first_offset,0, &wiih_offset,&wiih_size, ww.big_endian, 0)) { /*"WiiH", older Wwise */
vgmstream->num_samples = dsp_bytes_to_samples(ww.data_size, ww.channels);
if (wiih_size != 0x2e * ww.channels) goto fail;
if (is_dsp_full_interleave(sf, &ww, wiih_offset))
vgmstream->interleave_block_size = ww.data_size / 2;
}
else if (ww.extra_size == 0x0c + ww.channels * 0x2e) { /* newer Wwise */
vgmstream->num_samples = read_32bit(ww.fmt_offset + 0x18, streamFile);
vgmstream->num_samples = read_32bit(ww.fmt_offset + 0x18, sf);
wiih_offset = ww.fmt_offset + 0x1c;
wiih_size = 0x2e * ww.channels;
}
@ -466,13 +473,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
vgmstream->loop_flag = 0;
}
/* get coefs and default history */
dsp_read_coefs(vgmstream,streamFile,wiih_offset, 0x2e, ww.big_endian);
for (i=0; i < ww.channels; i++) {
vgmstream->ch[i].adpcm_history1_16 = read_16bitBE(wiih_offset + i * 0x2e + 0x24,streamFile);
vgmstream->ch[i].adpcm_history2_16 = read_16bitBE(wiih_offset + i * 0x2e + 0x26,streamFile);
}
dsp_read_coefs(vgmstream,sf,wiih_offset + 0x00, 0x2e, ww.big_endian);
dsp_read_hist (vgmstream,sf,wiih_offset + 0x24, 0x2e, ww.big_endian);
break;
}
@ -488,13 +490,13 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
//if (ww.fmt_size != ...) goto fail; /* XMA1 0x20, XMA2old: 0x34, XMA2new: 0x40, XMA2 Guitar Hero Live/padded: 0x64, etc */
if (!ww.big_endian) goto fail; /* must be Wwise (real XMA are LE and parsed elsewhere) */
if (find_chunk(streamFile, 0x584D4132,first_offset,0, &xma2_offset,&xma2_size, ww.big_endian, 0)) { /*"XMA2"*/ /* older Wwise */
bytes = ffmpeg_make_riff_xma2_from_xma2_chunk(buf,0x100, xma2_offset, xma2_size, ww.data_size, streamFile);
if (find_chunk(sf, 0x584D4132,first_offset,0, &xma2_offset,&xma2_size, ww.big_endian, 0)) { /*"XMA2"*/ /* older Wwise */
bytes = ffmpeg_make_riff_xma2_from_xma2_chunk(buf,0x100, xma2_offset, xma2_size, ww.data_size, sf);
} else { /* newer Wwise */
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, ww.fmt_offset, ww.fmt_size, ww.data_size, streamFile, ww.big_endian);
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, ww.fmt_offset, ww.fmt_size, ww.data_size, sf, ww.big_endian);
}
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, ww.data_offset,ww.data_size);
vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, ww.data_offset,ww.data_size);
if ( !vgmstream->codec_data ) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
@ -502,11 +504,11 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
vgmstream->num_samples = ww.num_samples; /* set while parsing XMAWAVEFORMATs */
/* Wwise loops are always pre-adjusted (old or new) and only num_samples is off */
xma_fix_raw_samples(vgmstream, streamFile, ww.data_offset,ww.data_size, ww.chunk_offset, 1,0);
xma_fix_raw_samples(vgmstream, sf, ww.data_offset,ww.data_size, ww.chunk_offset, 1,0);
/* "XMAc": rare Wwise extension, XMA2 physical loop regions (loop_start_b, loop_end_b, loop_subframe_data)
* Can appear even in the file doesn't loop, maybe it's meant to be the playable physical region */
//VGM_ASSERT(find_chunk(streamFile, 0x584D4163,first_offset,0, NULL,NULL, ww.big_endian, 0), "WWISE: XMAc chunk found\n");
//VGM_ASSERT(find_chunk(sf, 0x584D4163,first_offset,0, NULL,NULL, ww.big_endian, 0), "WWISE: XMAc chunk found\n");
/* other chunks: "seek", regular XMA2 seek table */
/* XMA is VBR so this is very approximate percent, meh */
@ -527,7 +529,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
if (!ww.big_endian) goto fail; /* must be from Wwise X360 (PC LE XWMA is parsed elsewhere) */
bytes = ffmpeg_make_riff_xwma(buf,0x100, ww.format, ww.data_size, vgmstream->channels, vgmstream->sample_rate, ww.average_bps, ww.block_align);
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, ww.data_offset,ww.data_size);
ffmpeg_data = init_ffmpeg_header_offset(sf, buf,bytes, ww.data_offset,ww.data_size);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg;
@ -543,9 +545,9 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
msd.data_size = ww.data_size;
if (ww.format == 0x0162)
wmapro_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x00E0);
wmapro_get_samples(&msd, sf, ww.block_align, ww.sample_rate,0x00E0);
else
wma_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x001F);
wma_get_samples(&msd, sf, ww.block_align, ww.sample_rate,0x001F);
vgmstream->num_samples = msd.num_samples;
if (!vgmstream->num_samples)
@ -564,7 +566,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
/* extra: size 0x12, unknown values */
ffmpeg_data = init_ffmpeg_offset(streamFile, ww.data_offset,ww.data_size);
ffmpeg_data = init_ffmpeg_offset(sf, ww.data_offset,ww.data_size);
if (!ffmpeg_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg;
@ -581,9 +583,9 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
if (ww.fmt_size == 0x28) {
size_t seek_size;
vgmstream->num_samples += read_32bit(ww.fmt_offset + 0x18, streamFile);
vgmstream->num_samples += read_32bit(ww.fmt_offset + 0x18, sf);
/* 0x1c: null? 0x20: data_size without seek_size */
seek_size = read_32bit(ww.fmt_offset + 0x24, streamFile);
seek_size = read_32bit(ww.fmt_offset + 0x24, sf);
start_offset += seek_size;
ww.data_size -= seek_size;
@ -592,7 +594,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
goto fail;
}
skip = switch_opus_get_encoder_delay(start_offset, streamFile); /* should be 120 */
skip = switch_opus_get_encoder_delay(start_offset, sf); /* should be 120 */
/* OPUS is VBR so this is very approximate percent, meh */
if (ww.truncated) {
@ -601,7 +603,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
ww.data_size = ww.file_size - start_offset;
}
vgmstream->codec_data = init_ffmpeg_switch_opus(streamFile, start_offset,ww.data_size, vgmstream->channels, skip, vgmstream->sample_rate);
vgmstream->codec_data = init_ffmpeg_switch_opus(sf, start_offset,ww.data_size, vgmstream->channels, skip, vgmstream->sample_rate);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
@ -612,7 +614,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail;
/* extra: size 0x12 */
vgmstream->num_samples = read_32bit(ww.fmt_offset + 0x18, streamFile);
vgmstream->num_samples = read_32bit(ww.fmt_offset + 0x18, sf);
/* 0x1c: stream size without OggS? */
/* 0x20: full samples (without encoder delay) */
@ -623,7 +625,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
ww.data_size = ww.file_size - start_offset;
}
vgmstream->codec_data = init_ffmpeg_offset(streamFile, ww.data_offset,ww.data_size);
vgmstream->codec_data = init_ffmpeg_offset(sf, ww.data_offset,ww.data_size);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
@ -657,15 +659,15 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
if (ww.extra_size != 0x12) goto fail;
cfg.channels = vgmstream->channels;
cfg.config_data = read_32bitBE(ww.fmt_offset+0x18,streamFile);
cfg.encoder_delay = read_32bit(ww.fmt_offset+0x20,streamFile);
cfg.config_data = read_32bitBE(ww.fmt_offset+0x18,sf);
cfg.encoder_delay = read_32bit(ww.fmt_offset+0x20,sf);
vgmstream->codec_data = init_atrac9(&cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_ATRAC9;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = read_32bit(ww.fmt_offset+0x1c,streamFile);
vgmstream->num_samples = read_32bit(ww.fmt_offset+0x1c,sf);
break;
}
#endif
@ -687,7 +689,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
if ( !vgmstream_open_stream(vgmstream,sf,start_offset) )
goto fail;
return vgmstream;
@ -696,6 +698,35 @@ fail:
return NULL;
}
static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_offset) {
/* older (only?) Wwise use full interleave for memory (in .bnk) files, but
* detection from the .wem side is problematic [Punch Out!! (Wii)]
* - truncated point to streams = normal
* - .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
* (but since memory wem aren't that used this shouldn't be too common) */
if (ww->truncated)
return 0;
if (check_extensions(sf,"bnk"))
return 1;
if (ww->channels == 2 && ww->data_size <= 0x30000) {
uint16_t head_ps2 = read_u16be(coef_offset + 1 * 0x2e + 0x22, sf); /* ch2's initial predictor */
uint16_t init_ps2 = read_u8(ww->data_offset + 0x08, sf); /* at normal interleave */
uint16_t half_ps2 = read_u8(ww->data_offset + ww->data_size / 2, sf); /* at full interleave */
//;VGM_LOG("WWISE: DSP head2=%x, init2=%x, half2=%x\n", head_ps2, init_ps2, half_ps2);
if (head_ps2 != init_ps2 && head_ps2 == half_ps2) {
return 1;
}
}
return 0;
}
/* VORBIS FORMAT RESEARCH */